Replace locks on /var/run/mwan3.lock with locks via procd. This fixes a deadlock issue where mwan3 stop would have a procd lock, but a hotplug script would have the /var/run/mwan3.lock Locking can be removed from mwan3rtmon since: 1) procd will have sent the KILL signal to the process during shutdown, so it will not add routes to already removed interfaces on mwan3 shutdown and 2) mwan3rtmon checks if an interface is active based on the mwan3_iface_in_<IFACE> entry in iptables, and the hotplug script always adds this before creating the route table and removes it before deleting the route table Fixes github issue #13704 (https://github.com/openwrt/packages/issues/13704)
179 lines
4.5 KiB
Bash
179 lines
4.5 KiB
Bash
#!/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 "$@"
|