mwan3: refine link selection
authorChen Minqiang <ptpt52@gmail.com>
Sun, 15 Apr 2018 11:55:25 +0000 (19:55 +0800)
committerChen Minqiang <ptpt52@gmail.com>
Wed, 8 Aug 2018 21:06:17 +0000 (05:06 +0800)
 - globals src_ip to none
 - ip route back to source
 - add mwan3rtmon
 - update version to 2.7

Signed-off-by: Chen Minqiang <ptpt52@gmail.com>
net/mwan3/Makefile
net/mwan3/files/etc/config/mwan3
net/mwan3/files/etc/hotplug.d/iface/16-mwan3 [new file with mode: 0644]
net/mwan3/files/lib/mwan3/mwan3.sh
net/mwan3/files/usr/sbin/mwan3
net/mwan3/files/usr/sbin/mwan3rtmon [new file with mode: 0755]

index adb54b24ae08cc29ca7b73a52022eac00d057bcc..741c92ce72707e0781c86b9b25196259a78bbe7b 100644 (file)
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=mwan3
-PKG_VERSION:=2.6.18
+PKG_VERSION:=2.7.0
 PKG_RELEASE:=1
 PKG_MAINTAINER:=Florian Eckert <fe@dev.tdt.de>
 PKG_LICENSE:=GPLv2
index b7f6c2c11ba27b86629444b0cd9ed458f85cdf80..64aadeed578afc233890d78865f003d5312973c9 100644 (file)
@@ -1,7 +1,7 @@
 
 config globals 'globals'
        option mmx_mask '0x3F00'
-       option local_source 'lan'
+       option local_source 'none'
 
 config interface 'wan'
        option enabled '1'
diff --git a/net/mwan3/files/etc/hotplug.d/iface/16-mwan3 b/net/mwan3/files/etc/hotplug.d/iface/16-mwan3
new file mode 100644 (file)
index 0000000..d2d148b
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. /lib/functions.sh
+. /lib/functions/network.sh
+. /lib/mwan3/mwan3.sh
+
+config_load mwan3
+config_get_bool enabled globals 'enabled' '0'
+[ ${enabled} -gt 0 ] || exit 0
+
+if [ "$ACTION" == "ifup" ]; then
+       mwan3_lock
+       mwan3_rtmon
+       mwan3_unlock
+fi
+
+exit 0
index 2c5bbf3c126e9a10e5f7122dbc41916b46c30245..d3360a5690bca6e072c22a4a383dec5ed6fb0fa6 100644 (file)
@@ -20,6 +20,63 @@ MM_BLACKHOLE=""
 MMX_UNREACHABLE=""
 MM_UNREACHABLE=""
 
+mwan3_rtmon_ipv4()
+{
+       local tid=1
+       local idx=0
+       local ret=1
+       main_tbsum=$($IP4 route list table main  | grep -v ^default | md5sum | head -c32)
+       while uci get mwan3.@interface[$idx] >/dev/null 2>&1 ; do
+               idx=$((idx+1))
+               tid=$idx
+               [ "$(uci get mwan3.@interface[$((idx-1))].family)" = "ipv4" ] && {
+                       if $IP4 route list table $tid | grep -q ^default; then
+                               tbsum=$($IP4 route list table $tid  | grep -v ^default | md5sum | head -c32)
+                               if [ "$tbsum" != "$main_tbsum" ]; then
+                                       $IP4 route list table $tid | grep -v ^default | while read line; do
+                                               $IP4 route del table $tid $line
+                                       done
+                                       $IP4 route list table main  | grep -v ^default | while read line; do
+                                               $IP4 route add table $tid $line
+                                       done
+                               fi
+                       fi
+               }
+               if [ "$(uci get mwan3.@interface[$((idx-1))].enabled)" = "1" ]; then
+                       ret=0
+               fi
+       done
+       return $ret
+}
+
+mwan3_rtmon_ipv6()
+{
+       local tid=1
+       local idx=0
+       local ret=1
+       main_tbsum=$($IP6 route list table main  | grep -v "^default\|^::/" | md5sum | head -c32)
+       while uci get mwan3.@interface[$idx] >/dev/null 2>&1 ; do
+               idx=$((idx+1))
+               tid=$idx
+               [ "$(uci get mwan3.@interface[$((idx-1))].family)" = "ipv6" ] && {
+                       if $IP6 route list table $tid | grep -q ^::/0; then
+                               tbsum=$($IP6 route list table $tid  | grep -v "^default\|^::/" | md5sum | head -c32)
+                               if [ "$tbsum" != "$main_tbsum" ]; then
+                                       $IP6 route list table $tid | grep -v "^default\|^::/" | while read line; do
+                                               $IP6 route del table $tid $line
+                                       done
+                                       $IP6 route list table main  | grep -v "^default\|^::/" | while read line; do
+                                               $IP6 route add table $tid $line
+                                       done
+                               fi
+                       fi
+               }
+               if [ "$(uci get mwan3.@interface[$((idx-1))].enabled)" = "1" ]; then
+                       ret=0
+               fi
+       done
+       return $ret
+}
 
 # counts how many bits are set to 1
 # n&(n-1) clears the lowest bit set to 1
@@ -188,10 +245,6 @@ mwan3_set_general_iptables()
                        $IPT -A mwan3_connected -m set --match-set mwan3_connected dst -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
                fi
 
-               if ! $IPT -S mwan3_ifaces_out &> /dev/null; then
-                       $IPT -N mwan3_ifaces_out
-               fi
-
                if ! $IPT -S mwan3_rules &> /dev/null; then
                        $IPT -N mwan3_rules
                fi
@@ -209,7 +262,6 @@ mwan3_set_general_iptables()
                        $IPT -A mwan3_hook -j CONNMARK --restore-mark --nfmask $MMX_MASK --ctmask $MMX_MASK
                        $IPT -A mwan3_hook -m mark --mark 0x0/$MMX_MASK -j mwan3_ifaces_in
                        $IPT -A mwan3_hook -m mark --mark 0x0/$MMX_MASK -j mwan3_connected
-                       $IPT -A mwan3_hook -m mark --mark 0x0/$MMX_MASK -j mwan3_ifaces_out
                        $IPT -A mwan3_hook -m mark --mark 0x0/$MMX_MASK -j mwan3_rules
                        $IPT -A mwan3_hook -j CONNMARK --save-mark --nfmask $MMX_MASK --ctmask $MMX_MASK
                        $IPT -A mwan3_hook -m mark ! --mark $MMX_DEFAULT/$MMX_MASK -j mwan3_connected
@@ -241,30 +293,16 @@ mwan3_create_iface_iptables()
                        $IPT4 -N mwan3_ifaces_in
                fi
 
-               if ! $IPT4 -S mwan3_ifaces_out &> /dev/null; then
-                       $IPT4 -N mwan3_ifaces_out
-               fi
-
                if ! $IPT4 -S mwan3_iface_in_$1 &> /dev/null; then
                        $IPT4 -N mwan3_iface_in_$1
                fi
 
-               if ! $IPT4 -S mwan3_iface_out_$1 &> /dev/null; then
-                       $IPT4 -N mwan3_iface_out_$1
-               fi
-
                $IPT4 -F mwan3_iface_in_$1
                $IPT4 -A mwan3_iface_in_$1 -i $2 -m set --match-set mwan3_connected src -m mark --mark 0x0/$MMX_MASK -m comment --comment "default" -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
                $IPT4 -A mwan3_iface_in_$1 -i $2 -m mark --mark 0x0/$MMX_MASK -m comment --comment "$1" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
 
                $IPT4 -D mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1 &> /dev/null
                $IPT4 -A mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1
-
-               $IPT4 -F mwan3_iface_out_$1
-               $IPT4 -A mwan3_iface_out_$1 -o $2 -m mark --mark 0x0/$MMX_MASK -m comment --comment "$1" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
-
-               $IPT4 -D mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1 &> /dev/null
-               $IPT4 -A mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1
        fi
 
        if [ "$family" == "ipv6" ]; then
@@ -274,30 +312,16 @@ mwan3_create_iface_iptables()
                        $IPT6 -N mwan3_ifaces_in
                fi
 
-               if ! $IPT6 -S mwan3_ifaces_out &> /dev/null; then
-                       $IPT6 -N mwan3_ifaces_out
-               fi
-
                if ! $IPT6 -S mwan3_iface_in_$1 &> /dev/null; then
                        $IPT6 -N mwan3_iface_in_$1
                fi
 
-               if ! $IPT6 -S mwan3_iface_out_$1 &> /dev/null; then
-                       $IPT6 -N mwan3_iface_out_$1
-               fi
-
                $IPT6 -F mwan3_iface_in_$1
                $IPT6 -A mwan3_iface_in_$1 -i $2 -m set --match-set mwan3_connected_v6 src -m mark --mark 0x0/$MMX_MASK -m comment --comment "default" -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
                $IPT6 -A mwan3_iface_in_$1 -i $2 -m mark --mark 0x0/$MMX_MASK -m comment --comment "$1" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
 
                $IPT6 -D mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1 &> /dev/null
                $IPT6 -A mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1
-
-               $IPT6 -F mwan3_iface_out_$1
-               $IPT6 -A mwan3_iface_out_$1 -o $2 -m mark --mark 0x0/$MMX_MASK -m comment --comment "$1" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
-
-               $IPT6 -D mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1 &> /dev/null
-               $IPT6 -A mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1
        fi
 }
 
@@ -310,10 +334,6 @@ mwan3_delete_iface_iptables()
                $IPT4 -D mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1 &> /dev/null
                $IPT4 -F mwan3_iface_in_$1 &> /dev/null
                $IPT4 -X mwan3_iface_in_$1 &> /dev/null
-
-               $IPT4 -D mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1 &> /dev/null
-               $IPT4 -F mwan3_iface_out_$1 &> /dev/null
-               $IPT4 -X mwan3_iface_out_$1 &> /dev/null
        fi
 
        if [ "$family" == "ipv6" ]; then
@@ -321,10 +341,6 @@ mwan3_delete_iface_iptables()
                $IPT6 -D mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1 &> /dev/null
                $IPT6 -F mwan3_iface_in_$1 &> /dev/null
                $IPT6 -X mwan3_iface_in_$1 &> /dev/null
-
-               $IPT6 -D mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1 &> /dev/null
-               $IPT6 -F mwan3_iface_out_$1 &> /dev/null
-               $IPT6 -X mwan3_iface_out_$1 &> /dev/null
        fi
 }
 
@@ -352,6 +368,7 @@ mwan3_create_iface_route()
 
                $IP4 route flush table $id
                $IP4 route add table $id default $route_args dev $2
+               mwan3_rtmon_ipv4
        fi
 
        if [ "$family" == "ipv6" ]; then
@@ -369,6 +386,7 @@ mwan3_create_iface_route()
 
                $IP6 route flush table $id
                $IP6 route add table $id default $route_args dev $2
+               mwan3_rtmon_ipv6
        fi
 }
 
@@ -409,7 +427,7 @@ mwan3_create_iface_rules()
                        $IP4 rule del pref $(($id+2000))
                done
 
-               $IP4 rule add pref $(($id+1000)) iif $2 lookup main
+               $IP4 rule add pref $(($id+1000)) iif $2 lookup $id
                $IP4 rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup $id
        fi
 
@@ -423,7 +441,7 @@ mwan3_create_iface_rules()
                        $IP6 rule del pref $(($id+2000))
                done
 
-               $IP6 rule add pref $(($id+1000)) iif $2 lookup main
+               $IP6 rule add pref $(($id+1000)) iif $2 lookup $id
                $IP6 rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup $id
        fi
 }
@@ -475,6 +493,16 @@ mwan3_delete_iface_ipset_entries()
        done
 }
 
+mwan3_rtmon()
+{
+       pid="$(pgrep -f mwan3rtmon)"
+       if [ "${pid}" != "" ]; then
+               kill -USR1 "${pid}"
+       else
+               [ -x /usr/sbin/mwan3rtmon ] && /usr/sbin/mwan3rtmon &
+       fi
+}
+
 mwan3_track()
 {
        local track_ip track_ips pid
@@ -507,13 +535,14 @@ mwan3_track_signal()
 
 mwan3_set_policy()
 {
-       local iface_count id iface family metric probability weight
+       local iface_count id iface family metric probability weight device
 
        config_get iface $1 interface
        config_get metric $1 metric 1
        config_get weight $1 weight 1
 
        [ -n "$iface" ] || return 0
+       network_get_device device $iface
        [ "$metric" -gt $DEFAULT_LOWEST_METRIC ] && $LOG warn "Member interface $iface has >$DEFAULT_LOWEST_METRIC metric. Not appending to policy" && return 0
 
        mwan3_get_iface_id id $iface
@@ -552,6 +581,9 @@ mwan3_set_policy()
 
                                $IPT4 -I mwan3_policy_$policy -m mark --mark 0x0/$MMX_MASK $probability -m comment --comment "$iface $weight $total_weight_v4" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
                        fi
+               else
+                       $IPT4 -S mwan3_policy_$policy | grep -q '.*--comment ".* [0-9]* [0-9]*"' || \
+                               $IPT4 -I mwan3_policy_$policy -o $device -m mark --mark 0x0/$MMX_MASK -m comment --comment "out $iface $device" -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
                fi
        fi
 
@@ -585,6 +617,9 @@ mwan3_set_policy()
 
                                $IPT6 -I mwan3_policy_$policy -m mark --mark 0x0/$MMX_MASK $probability -m comment --comment "$iface $weight $total_weight_v6" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
                        fi
+               else
+                       $IPT6 -S mwan3_policy_$policy | grep -q '.*--comment ".* [0-9]* [0-9]*"' || \
+                               $IPT6 -I mwan3_policy_$policy -o $device -m mark --mark 0x0/$MMX_MASK -m comment --comment "out $iface $device" -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
                fi
        fi
 }
@@ -649,7 +684,7 @@ mwan3_set_sticky_iptables()
                        [ -n "$id" ] || return 0
 
                        for IPT in "$IPT4" "$IPT6"; do
-                               if [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -a -n "$($IPT -S mwan3_iface_out_$1 2> /dev/null)" ]; then
+                               if [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ]; then
                                        $IPT -I mwan3_rule_$rule -m mark --mark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK -m set ! --match-set mwan3_sticky_$rule src,src -j MARK --set-xmark 0x0/$MMX_MASK
                                        $IPT -I mwan3_rule_$rule -m mark --mark 0/$MMX_MASK -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
                                fi
@@ -822,9 +857,9 @@ mwan3_report_iface_status()
 
        if [ -z "$id" -o -z "$device" ]; then
                result="unknown"
-       elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" -a -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" -a -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -a -n "$($IPT -S mwan3_iface_out_$1 2> /dev/null)" -a -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
+       elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" -a -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" -a -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -a -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
                result="$(mwan3_get_iface_hotplug_state $1)"
-       elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" -o -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" -o -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -o -n "$($IPT -S mwan3_iface_out_$1 2> /dev/null)" -o -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
+       elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" -o -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" -o -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -o -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
                result="error"
        elif [ "$enabled" == "1" ]; then
                result="offline"
@@ -858,16 +893,16 @@ mwan3_report_policies_v4()
        for policy in $($IPT4 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
                echo "$policy:" | sed 's/mwan3_policy_//'
 
-               [ -n "$total_weight" ] || total_weight=$($IPT4 -S $policy | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
+               [ -n "$total_weight" ] || total_weight=$($IPT4 -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
 
                if [ ! -z "${total_weight##*[!0-9]*}" ]; then
-                       for iface in $($IPT4 -S $policy | cut -s -d'"' -f2 | awk '{print $1}'); do
-                               weight=$($IPT4 -S $policy | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
+                       for iface in $($IPT4 -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '{print $1}'); do
+                               weight=$($IPT4 -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
                                percent=$(($weight*100/$total_weight))
                                echo " $iface ($percent%)"
                        done
                else
-                       echo " $($IPT4 -S $policy | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')"
+                       echo " $($IPT4 -S $policy | grep -v '.*--comment "out .*" .*$' | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')"
                fi
 
                unset total_weight
@@ -883,16 +918,16 @@ mwan3_report_policies_v6()
        for policy in $($IPT6 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
                echo "$policy:" | sed 's/mwan3_policy_//'
 
-               [ -n "$total_weight" ] || total_weight=$($IPT6 -S $policy | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
+               [ -n "$total_weight" ] || total_weight=$($IPT6 -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
 
                if [ ! -z "${total_weight##*[!0-9]*}" ]; then
-                       for iface in $($IPT6 -S $policy | cut -s -d'"' -f2 | awk '{print $1}'); do
-                               weight=$($IPT6 -S $policy | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
+                       for iface in $($IPT6 -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '{print $1}'); do
+                               weight=$($IPT6 -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
                                percent=$(($weight*100/$total_weight))
                                echo " $iface ($percent%)"
                        done
                else
-                       echo " $($IPT6 -S $policy | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')"
+                       echo " $($IPT6 -S $policy | grep -v '.*--comment "out .*" .*$' | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')"
                fi
 
                unset total_weight
index a0c296f18e2bc0ea2acce0787163a596723a044f..c10ffa8a53a6d9542cba2d5c1bbaa996d482907b 100755 (executable)
@@ -155,6 +155,12 @@ stop()
 {
        local ipset route rule table IP IPT pid src_ip
 
+       for pid in $(pgrep -f "mwan3rtmon"); do
+               kill -TERM "$pid" > /dev/null 2>&1
+               sleep 1
+               kill -KILL "$pid" > /dev/null 2>&1
+       done
+
        for pid in $(pgrep -f "mwan3track"); do
                kill -TERM "$pid" > /dev/null 2>&1
                sleep 1
diff --git a/net/mwan3/files/usr/sbin/mwan3rtmon b/net/mwan3/files/usr/sbin/mwan3rtmon
new file mode 100755 (executable)
index 0000000..9d2b62b
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+. /lib/functions.sh
+. /lib/mwan3/mwan3.sh
+
+LOG="logger -t $(basename "$0")[$$] -p"
+
+clean_up() {
+       $LOG notice "Stopping mwan3rtmon..."
+       exit 0
+}
+
+rtchange() {
+       $LOG info "Detect rtchange event."
+}
+
+main() {
+       trap clean_up TERM
+       trap rtchange USR1
+
+       sleep 3
+       while mwan3_rtmon_ipv4 || mwan3_rtmon_ipv6; do
+               sleep 5
+       done
+}
+
+main "$@"