#!/bin/sh
|
|
|
|
. /lib/functions.sh
|
|
. /lib/functions/network.sh
|
|
. /lib/mwan3/mwan3.sh
|
|
. /lib/mwan3/common.sh
|
|
|
|
trap_with_arg()
|
|
{
|
|
func="$1" ; shift
|
|
pid="$1" ; shift
|
|
for sig ; do
|
|
# shellcheck disable=SC2064
|
|
trap "$func $sig $pid" "$sig"
|
|
done
|
|
}
|
|
|
|
func_trap()
|
|
{
|
|
kill -${1} ${2} 2>/dev/null
|
|
}
|
|
|
|
mwan3_add_all_routes()
|
|
{
|
|
local tid IP IPT route_line family active_tbls tid initial_state
|
|
local ipv=$1
|
|
|
|
add_active_tbls()
|
|
{
|
|
let tid++
|
|
config_get family "$1" family ipv4
|
|
config_get initial_state "$1" initial_state "online"
|
|
[ "$family" != "$ipv" ] && return
|
|
if $IPT -S "mwan3_iface_in_$1" &> /dev/null; then
|
|
active_tbls="$active_tbls${tid} "
|
|
fi
|
|
}
|
|
|
|
add_route()
|
|
{
|
|
let tid++
|
|
[ -n "${active_tbls##* $tid *}" ] && return
|
|
$IP route add table $tid $route_line ||
|
|
LOG warn "failed to add $route_line to table $tid"
|
|
}
|
|
|
|
mwan3_update_dev_to_table
|
|
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
|
|
if [ "$ipv" = "ipv4" ]; then
|
|
IP="$IP4"
|
|
IPT="$IPT4"
|
|
elif [ "$ipv" = "ipv6" ]; then
|
|
IP="$IP6"
|
|
IPT="$IPT6"
|
|
fi
|
|
tid=0
|
|
active_tbls=" "
|
|
config_foreach add_active_tbls interface
|
|
[ $active_tbls = " " ] && return
|
|
mwan3_get_routes | while read -r route_line; do
|
|
mwan3_route_line_dev "tid" "$route_line" "$ipv"
|
|
if [ -n "$tid" ] && [ -z "${active_tbls##* $tid *}" ]; then
|
|
$IP route add table $tid $route_line
|
|
elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then
|
|
config_foreach add_route interface
|
|
fi
|
|
done
|
|
}
|
|
|
|
mwan3_rtmon_route_handle()
|
|
{
|
|
local action route_line family tbl device line route_line_exp tid source_routing
|
|
|
|
route_line=${1##"Deleted "}
|
|
route_family=$2
|
|
|
|
config_get_bool source_routing globals source_routing 0
|
|
[ $source_routing -eq 0 ] && unset source_routing
|
|
|
|
if [ "$route_line" = "$1" ]; then
|
|
action="replace"
|
|
route_line_exp="s/expires \([0-9]\+\)sec//;s/error [0-9]\+//; ${source_routing:+s/default\(.*\) from [^ ]*/default\1/}"
|
|
$IPS -! add mwan3_connected_${route_family##ip} ${route_line%% *}
|
|
else
|
|
action="del"
|
|
route_line_exp="s/expires [0-9]\+sec//;s/error [0-9]\+//; ${source_routing:+s/default\(.*\) from [^ ]*/default\1/}"
|
|
mwan3_set_connected_${route_family}
|
|
fi
|
|
|
|
if [ "$route_family" = "ipv4" ]; then
|
|
IP="$IP4"
|
|
elif [ "$route_family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
|
IP="$IP6"
|
|
route_line=$(echo "$route_line" | sed "$route_line_exp")
|
|
else
|
|
LOG warn "route update called with invalid family - $route_family"
|
|
return
|
|
fi
|
|
|
|
# don't try to add routes when link has gone down
|
|
if [ -z "${route_line##linkdown*}" ]; then
|
|
LOG debug "not adding route due to linkdown - skipping $route_line"
|
|
return
|
|
fi
|
|
|
|
handle_route() {
|
|
local iface=$1
|
|
tbl=$($IP route list table $tid 2>/dev/null)$'\n'
|
|
|
|
if [ -n "$iface" ] && [ "$(mwan3_get_mwan3track_status $iface)" != "active" ]; then
|
|
LOG debug "interface $iface is disabled - skipping '$route_line'";
|
|
return
|
|
fi
|
|
|
|
# check that action needs to be performed. May not need to take action if we
|
|
# got a delete event, but table was already flushed
|
|
if [ $action = "del" ] && [ -n "${tbl##*$route_line$'\n'*}" ]; then
|
|
LOG debug "skipping already deleted route table $tid - skipping '$route_line'"
|
|
return
|
|
fi
|
|
|
|
network_get_device device "$iface"
|
|
LOG debug "adjusting route $device: '$IP route $action table $tid $route_line'"
|
|
$IP route "$action" table $tid $route_line ||
|
|
LOG warn "failed: '$IP route $action table $tid $route_line'"
|
|
}
|
|
handle_route_cb(){
|
|
local iface=$1
|
|
let tid++
|
|
config_get family "$iface" family ipv4
|
|
[ "$family" != "$route_family" ] && return
|
|
handle_route "$iface"
|
|
}
|
|
|
|
mwan3_update_dev_to_table
|
|
mwan3_route_line_dev "tid" "$route_line" "$route_family"
|
|
|
|
if [ -n "$tid" ]; then
|
|
handle_route
|
|
elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then
|
|
config_foreach handle_route_cb interface
|
|
fi
|
|
}
|
|
|
|
main()
|
|
{
|
|
local IP family
|
|
|
|
config_load mwan3
|
|
family=$1
|
|
[ -z $family ] && family=ipv4
|
|
if [ "$family" = "ipv6" ]; then
|
|
if [ $NO_IPV6 -ne 0 ]; then
|
|
LOG warn "mwan3rtmon started for ipv6, but ipv6 not enabled on system"
|
|
exit 1
|
|
fi
|
|
IP="$IP6"
|
|
else
|
|
IP="$IP4"
|
|
fi
|
|
mwan3_init
|
|
sh -c "echo \$\$; exec $IP monitor route" | {
|
|
read -r monitor_pid
|
|
trap_with_arg func_trap "$monitor_pid" SIGINT SIGTERM SIGKILL
|
|
while IFS='' read -r line; do
|
|
[ -z "${line##*table*}" ] && continue
|
|
LOG debug "handling route update $family '$line'"
|
|
mwan3_rtmon_route_handle "$line" "$family"
|
|
done
|
|
} &
|
|
child=$!
|
|
kill -SIGSTOP $child
|
|
trap_with_arg func_trap "$child" SIGINT SIGTERM SIGKILL
|
|
mwan3_set_connected_${family}
|
|
mwan3_add_all_routes ${family}
|
|
kill -SIGCONT $child
|
|
wait $!
|
|
}
|
|
main "$@"
|