improve startup and runtime performance by 1) moving common startup procedures out of hotplug script when called from mwan3 start 2) reducing calls to iptables to check status of rules 3) consolidating iptables updates and updating with iptables-restore 4) do not wait for kill if nothing was killed 5) running interface hotplug scripts in parallel 6) eliminate operations in hotplug script that check status on every single interface unnecessarily 7) consolidate how mwan3track makes hotplug calls 8) do not restart mwan3track on connected events This is a significant refactor, but should not result in any breaking changes or require users to update their configurations. version bump to 2.9.0 Signed-off-by: Aaron Goodman <aaronjg@stanford.edu>
320 lines
9.1 KiB
Bash
Executable file
320 lines
9.1 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
. /lib/functions.sh
|
|
. /lib/mwan3/common.sh
|
|
|
|
INTERFACE=""
|
|
DEVICE=""
|
|
PING="/bin/ping"
|
|
|
|
IFDOWN_EVENT=0
|
|
IFUP_EVENT=0
|
|
|
|
clean_up() {
|
|
LOG notice "Stopping mwan3track for interface \"${INTERFACE}\""
|
|
exit 0
|
|
}
|
|
|
|
if_down() {
|
|
LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})"
|
|
IFDOWN_EVENT=1
|
|
}
|
|
|
|
if_up() {
|
|
LOG info "Detect ifup event on interface ${INTERFACE} (${DEVICE})"
|
|
IFUP_EVENT=1
|
|
}
|
|
|
|
validate_track_method() {
|
|
case "$1" in
|
|
ping)
|
|
[ -x "$PING" ] || {
|
|
LOG warn "Missing ping. Please enable ping util and recompile busybox."
|
|
return 1
|
|
}
|
|
;;
|
|
arping)
|
|
command -v arping 1>/dev/null 2>&1 || {
|
|
LOG warn "Missing arping. Please install iputils-arping package."
|
|
return 1
|
|
}
|
|
;;
|
|
httping)
|
|
command -v httping 1>/dev/null 2>&1 || {
|
|
LOG warn "Missing httping. Please install httping package."
|
|
return 1
|
|
}
|
|
[ -n "$2" -a "$2" != "0.0.0.0" -a "$2" != "::" ] || {
|
|
LOG warn "Cannot determine source IP for the interface which is required by httping."
|
|
return 1
|
|
}
|
|
;;
|
|
nping-*)
|
|
command -v nping 1>/dev/null 2>&1 || {
|
|
LOG warn "Missing nping. Please install nping package."
|
|
return 1
|
|
}
|
|
;;
|
|
*)
|
|
LOG warn "Unsupported tracking method: $track_method"
|
|
return 2
|
|
;;
|
|
esac
|
|
}
|
|
|
|
disconnected() {
|
|
echo "offline" > /var/run/mwan3track/$INTERFACE/STATUS
|
|
echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/OFFLINE
|
|
echo "0" > /var/run/mwan3track/$INTERFACE/ONLINE
|
|
score=0
|
|
[ "$1" == 1 ] && return
|
|
LOG notice "Interface $INTERFACE ($DEVICE) is offline"
|
|
env -i ACTION="disconnected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
|
}
|
|
|
|
connected() {
|
|
echo "online" > /var/run/mwan3track/$INTERFACE/STATUS
|
|
echo "0" > /var/run/mwan3track/$INTERFACE/OFFLINE
|
|
echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/ONLINE
|
|
host_up_count=0
|
|
lost=0
|
|
turn=0
|
|
loss=0
|
|
[ "$1" == 1 ] && return
|
|
LOG notice "Interface $INTERFACE ($DEVICE) is online"
|
|
env -i ACTION="connected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
|
}
|
|
|
|
firstconnect() {
|
|
if [ "$STATUS" = "offline" ]; then
|
|
disconnected 1
|
|
else
|
|
connected 1
|
|
fi
|
|
}
|
|
|
|
update_status() {
|
|
local status track_ip
|
|
track_ip=$1
|
|
status=$2
|
|
|
|
echo "$1" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
|
|
[ -z "$3" ] && return
|
|
echo "$3" > /var/run/mwan3track/$INTERFACE/LATENCY_${track_ip}
|
|
echo "$4" > /var/run/mwan3track/$INTERFACE/LOSS_${track_ip}
|
|
}
|
|
|
|
main() {
|
|
local reliability count timeout interval failure_interval
|
|
local recovery_interval down up size
|
|
local keep_failure_interval check_quality failure_latency
|
|
local recovery_latency failure_loss recovery_loss
|
|
local max_ttl httping_ssl
|
|
|
|
[ -z "$5" ] && echo "Error: should not be started manually" && exit 0
|
|
|
|
INTERFACE=$1
|
|
DEVICE=$2
|
|
STATUS=$3
|
|
SRC_IP=$4
|
|
mkdir -p /var/run/mwan3track/$INTERFACE
|
|
trap clean_up TERM
|
|
trap if_down USR1
|
|
trap if_up USR2
|
|
|
|
config_load mwan3
|
|
config_get track_method $INTERFACE track_method ping
|
|
config_get_bool httping_ssl $INTERFACE httping_ssl 0
|
|
validate_track_method $track_method $SRC_IP || {
|
|
track_method=ping
|
|
if validate_track_method $track_method; then
|
|
LOG warn "Using ping to track interface $INTERFACE avaliability"
|
|
else
|
|
LOG err "No track method avaliable"
|
|
exit 1
|
|
fi
|
|
}
|
|
config_get reliability $INTERFACE reliability 1
|
|
config_get count $INTERFACE count 1
|
|
config_get timeout $INTERFACE timeout 4
|
|
config_get interval $INTERFACE interval 10
|
|
config_get down $INTERFACE down 5
|
|
config_get up $INTERFACE up 5
|
|
config_get size $INTERFACE size 56
|
|
config_get max_ttl $INTERFACE max_ttl 60
|
|
config_get failure_interval $INTERFACE failure_interval $interval
|
|
config_get_bool keep_failure_interval $INTERFACE keep_failure_interval 0
|
|
config_get recovery_interval $INTERFACE recovery_interval $interval
|
|
config_get_bool check_quality $INTERFACE check_quality 0
|
|
config_get failure_latency $INTERFACE failure_latency 1000
|
|
config_get recovery_latency $INTERFACE recovery_latency 500
|
|
config_get failure_loss $INTERFACE failure_loss 40
|
|
config_get recovery_loss $INTERFACE recovery_loss 10
|
|
|
|
local score=$(($down+$up))
|
|
local track_ips=$(echo $* | cut -d ' ' -f 5-99)
|
|
local host_up_count=0
|
|
local lost=0
|
|
local turn=0
|
|
local ping_protocol=4
|
|
local sleep_time result ping_result ping_result_raw ping_status loss latency
|
|
|
|
firstconnect
|
|
while true; do
|
|
|
|
sleep_time=$interval
|
|
|
|
for track_ip in $track_ips; do
|
|
if [ $host_up_count -lt $reliability ]; then
|
|
case "$track_method" in
|
|
ping)
|
|
# pinging IPv6 hosts with an interface is troublesome
|
|
# https://bugs.openwrt.org/index.php?do=details&task_id=2897
|
|
# so get the IP address of the interface and use that instead
|
|
if [ -z ${track_ip##*:*} ]; then
|
|
ping_protocol=6
|
|
else
|
|
unset SRC_IP
|
|
fi
|
|
if [ $check_quality -eq 0 ]; then
|
|
$PING -$ping_protocol -I ${SRC_IP:-$DEVICE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null
|
|
result=$?
|
|
else
|
|
ping_result_raw="$($PING -$ping_protocol -I ${SRC_IP:-$DEVICE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null)"
|
|
ping_status=$?
|
|
ping_result=$(echo "$ping_result_raw" | tail -n2)
|
|
loss="$(echo "$ping_result" | grep "packet loss" | cut -d "," -f3 | awk '{print $1}' | sed -e 's/%//')"
|
|
if [ "$ping_status" -ne 0 ] || [ "$loss" -eq 100 ]; then
|
|
latency=999999
|
|
loss=100
|
|
else
|
|
latency="$(echo "$ping_result" | grep -E 'rtt|round-trip' | cut -d "=" -f2 | cut -d "/" -f2 | cut -d "." -f1)"
|
|
fi
|
|
fi
|
|
;;
|
|
arping)
|
|
arping -I $DEVICE -c $count -w $timeout -q $track_ip &> /dev/null
|
|
result=$?
|
|
;;
|
|
httping)
|
|
if [ "$httping_ssl" -eq 1 ]; then
|
|
httping -y $SRC_IP -c $count -t $timeout -q "https://$track_ip" &> /dev/null
|
|
else
|
|
httping -y $SRC_IP -c $count -t $timeout -q "http://$track_ip" &> /dev/null
|
|
fi
|
|
result=$?
|
|
;;
|
|
nping-tcp)
|
|
result=$(nping -e $DEVICE -c $count $track_ip --tcp | grep Lost | awk '{print $12}')
|
|
;;
|
|
nping-udp)
|
|
result=$(nping -e $DEVICE -c $count $track_ip --udp | grep Lost | awk '{print $12}')
|
|
;;
|
|
nping-icmp)
|
|
result=$(nping -e $DEVICE -c $count $track_ip --icmp | grep Lost | awk '{print $12}')
|
|
;;
|
|
nping-arp)
|
|
result=$(nping -e $DEVICE -c $count $track_ip --arp | grep Lost | awk '{print $12}')
|
|
;;
|
|
esac
|
|
if [ $check_quality -eq 0 ]; then
|
|
if [ $result -eq 0 ]; then
|
|
let host_up_count++
|
|
update_status "$track_ip" "up"
|
|
|
|
if [ $score -le $up ]; then
|
|
LOG info "Check ($track_method) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
|
fi
|
|
else
|
|
let lost++
|
|
update_status "$track_ip" "down"
|
|
|
|
if [ $score -gt $up ]; then
|
|
LOG info "Check ($track_method) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
|
fi
|
|
fi
|
|
else
|
|
if [ "$loss" -ge "$failure_loss" -o "$latency" -ge "$failure_latency" ]; then
|
|
let lost++
|
|
update_status "$track_ip" "down" $latency $loss
|
|
|
|
if [ $score -gt $up ]; then
|
|
LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
|
fi
|
|
elif [ "$loss" -le "$recovery_loss" -a "$latency" -le "$recovery_latency" ]; then
|
|
let host_up_count++
|
|
update_status "$track_ip" "up" $latency $loss
|
|
|
|
if [ $score -le $up ]; then
|
|
LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
|
fi
|
|
else
|
|
echo "skipped" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
|
|
fi
|
|
fi
|
|
else
|
|
echo "skipped" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
|
|
fi
|
|
done
|
|
|
|
if [ $host_up_count -lt $reliability ]; then
|
|
let score--
|
|
|
|
if [ $score -lt $up ]; then
|
|
score=0
|
|
[ ${keep_failure_interval} -eq 1 ] && {
|
|
sleep_time=$failure_interval
|
|
}
|
|
else
|
|
sleep_time=$failure_interval
|
|
fi
|
|
|
|
if [ $score -eq $up ]; then
|
|
disconnected
|
|
score=0
|
|
fi
|
|
else
|
|
if [ $score -lt $(($down+$up)) ] && [ $lost -gt 0 ]; then
|
|
LOG info "Lost $(($lost*$count)) ping(s) on interface $INTERFACE ($DEVICE). Current score: $score"
|
|
fi
|
|
|
|
let score++
|
|
lost=0
|
|
|
|
if [ $score -gt $up ]; then
|
|
echo "online" > /var/run/mwan3track/$INTERFACE/STATUS
|
|
score=$(($down+$up))
|
|
elif [ $score -le $up ]; then
|
|
sleep_time=$recovery_interval
|
|
fi
|
|
|
|
if [ $score -eq $up ]; then
|
|
connected $INTERFACE $DEVICE
|
|
fi
|
|
fi
|
|
|
|
let turn++
|
|
mkdir -p "/var/run/mwan3track/${1}"
|
|
echo "${lost}" > /var/run/mwan3track/$INTERFACE/LOST
|
|
echo "${score}" > /var/run/mwan3track/$INTERFACE/SCORE
|
|
echo "${turn}" > /var/run/mwan3track/$INTERFACE/TURN
|
|
echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/TIME
|
|
|
|
host_up_count=0
|
|
sleep "${sleep_time}" &
|
|
wait
|
|
|
|
if [ "${IFDOWN_EVENT}" -eq 1 ]; then
|
|
LOG debug "Register ifdown event on interface ${INTERFACE} (${DEVICE})"
|
|
disconnected 1
|
|
IFDOWN_EVENT=0
|
|
fi
|
|
if [ "${IFUP_EVENT}" -eq 1 ]; then
|
|
LOG debug "Register ifup event on interface ${INTERFACE} (${DEVICE})"
|
|
firstconnect
|
|
IFUP_EVENT=0
|
|
fi
|
|
done
|
|
}
|
|
|
|
main "$@"
|