If the interface goes into failure state (is disconnecting) then with this change one hotplug.d event is generated. The same is true for the recovery state (is connecting), when the interface comes back from a failure state. In both cases, a hotplug.d event for the iface is triggered. Once with the $ACTION=disconnecting and once for the $ACTION=connecting. Signed-off-by: Florian Eckert <fe@dev.tdt.de>
406 lines
11 KiB
Bash
Executable file
406 lines
11 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
. /lib/functions.sh
|
|
. /lib/functions/network.sh
|
|
. /lib/mwan3/common.sh
|
|
|
|
INTERFACE=""
|
|
DEVICE=""
|
|
|
|
IFDOWN_EVENT=0
|
|
IFUP_EVENT=0
|
|
|
|
stop_subprocs() {
|
|
[ -n "$SLEEP_PID" ] && kill "$SLEEP_PID" && unset SLEEP_PID
|
|
[ -n "$TRACK_PID" ] && kill "$TRACK_PID" && unset TRACK_PID
|
|
}
|
|
|
|
WRAP() {
|
|
# shellcheck disable=SC2048
|
|
FAMILY=$FAMILY DEVICE=$DEVICE SRCIP=$SRC_IP FWMARK=$MMX_DEFAULT LD_PRELOAD=/lib/mwan3/libwrap_mwan3_sockopt.so.1.0 $*
|
|
}
|
|
|
|
clean_up() {
|
|
LOG notice "Stopping mwan3track for interface \"${INTERFACE}\". Status was \"${STATUS}\""
|
|
stop_subprocs
|
|
exit 0
|
|
}
|
|
|
|
if_down() {
|
|
LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})"
|
|
IFDOWN_EVENT=1
|
|
stop_subprocs
|
|
}
|
|
|
|
if_up() {
|
|
LOG info "Detect ifup event on interface ${INTERFACE} (${DEVICE})"
|
|
IFDOWN_EVENT=0
|
|
IFUP_EVENT=1
|
|
STARTED=1
|
|
stop_subprocs
|
|
}
|
|
|
|
ping_test_host() {
|
|
if [ "$FAMILY" = "ipv6" ]; then
|
|
echo "::1"
|
|
else
|
|
echo "127.0.0.1"
|
|
fi
|
|
}
|
|
|
|
get_ping_command() {
|
|
if [ -x "/usr/bin/ping" ] && /usr/bin/ping -${FAMILY#ipv} -c1 -q $(ping_test_host) &>/dev/null; then
|
|
# -4 option added in iputils c3e68ac6 so need to check if we can use it
|
|
# or if we must use ping and ping6
|
|
echo "/usr/bin/ping -${FAMILY#ipv}"
|
|
elif [ "$FAMILY" = "ipv6" ] && [ -x "/usr/bin/ping6" ]; then
|
|
echo "/usr/bin/ping6"
|
|
elif [ "$FAMILY" = "ipv4" ] && [ -x "/usr/bin/ping" ]; then
|
|
echo "/usr/bin/ping"
|
|
elif [ -x "/bin/ping" ]; then
|
|
echo "/bin/ping -${FAMILY#ipv}"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
validate_track_method() {
|
|
case "$1" in
|
|
ping)
|
|
PING=$(get_ping_command)
|
|
if [ $? -ne 0 ]; then
|
|
LOG warn "Missing ping. Please enable BUSYBOX_DEFAULT_PING and recompile busybox or install iputils-ping package."
|
|
return 1
|
|
fi
|
|
;;
|
|
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
|
|
}
|
|
;;
|
|
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
|
|
}
|
|
|
|
validate_wrap() {
|
|
[ -x /lib/mwan3/libwrap_mwan3_sockopt.so.1.0 ] && return
|
|
LOG error "Missing libwrap_mwan3_sockopt. Please reinstall mwan3." &&
|
|
exit 1
|
|
}
|
|
|
|
disconnected() {
|
|
STATUS='offline'
|
|
echo "offline" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
|
get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE
|
|
echo "0" > $MWAN3TRACK_STATUS_DIR/$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() {
|
|
STATUS='online'
|
|
echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
|
echo "0" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE
|
|
get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/ONLINE
|
|
host_up_count=0
|
|
lost=0
|
|
turn=0
|
|
loss=0
|
|
LOG notice "Interface $INTERFACE ($DEVICE) is online"
|
|
env -i FIRSTCONNECT=$1 ACTION="connected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
|
}
|
|
|
|
disconnecting() {
|
|
if [ "$STATUS" != "disconnecting" ] ; then
|
|
STATUS="disconnecting"
|
|
echo "disconnecting" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
|
LOG notice "Interface $INTERFACE ($DEVICE) is disconnecting"
|
|
env -i ACTION="disconnecting" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
|
fi
|
|
}
|
|
|
|
connecting() {
|
|
if [ "$STATUS" != "connecting" ] ; then
|
|
STATUS="connecting"
|
|
echo "connecting" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
|
LOG notice "Interface $INTERFACE ($DEVICE) is connecting"
|
|
env -i ACTION="connecting" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
|
fi
|
|
}
|
|
|
|
disabled() {
|
|
STATUS='disabled'
|
|
echo "disabled" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
|
STARTED=0
|
|
}
|
|
|
|
firstconnect() {
|
|
local true_iface
|
|
network_flush_cache
|
|
|
|
mwan3_get_true_iface true_iface $INTERFACE
|
|
network_get_device DEVICE $true_iface
|
|
|
|
if [ "$STATUS" != "online" ]; then
|
|
config_get STATUS $INTERFACE initial_state "online"
|
|
fi
|
|
|
|
if ! network_is_up $true_iface || [ -z "$DEVICE" ]; then
|
|
disabled
|
|
return
|
|
fi
|
|
|
|
mwan3_get_src_ip SRC_IP $INTERFACE
|
|
|
|
LOG debug "firstconnect: called on $INTERFACE/$true_iface ($DEVICE). Status is $STATUS. SRC_IP is $SRC_IP"
|
|
|
|
STARTED=1
|
|
if [ "$STATUS" = "offline" ]; then
|
|
disconnected 1
|
|
else
|
|
connected 1
|
|
fi
|
|
}
|
|
|
|
update_status() {
|
|
local track_ip=$1
|
|
|
|
echo "$2" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip}
|
|
[ -z "$3" ] && return
|
|
echo "$3" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LATENCY_${track_ip}
|
|
echo "$4" > $MWAN3TRACK_STATUS_DIR/$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 track_ips do_log
|
|
|
|
INTERFACE=$1
|
|
STATUS=""
|
|
STARTED=0
|
|
TRACK_OUTPUT=$MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_OUTPUT
|
|
|
|
mwan3_init
|
|
|
|
mkdir -p $MWAN3TRACK_STATUS_DIR/$INTERFACE
|
|
|
|
trap clean_up TERM
|
|
trap if_down USR1
|
|
trap if_up USR2
|
|
|
|
config_get FAMILY $INTERFACE family ipv4
|
|
config_get track_method $INTERFACE track_method ping
|
|
config_get_bool httping_ssl $INTERFACE httping_ssl 0
|
|
validate_track_method $track_method || {
|
|
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 sleep_time result ping_status loss latency
|
|
mwan3_list_track_ips()
|
|
{
|
|
track_ips="$track_ips $1"
|
|
}
|
|
config_list_foreach "$1" track_ip mwan3_list_track_ips
|
|
|
|
local score=$((down+up))
|
|
local host_up_count=0
|
|
local lost=0
|
|
local turn=0
|
|
|
|
firstconnect
|
|
while true; do
|
|
[ $STARTED -eq 0 ] && { sleep $MAX_SLEEP & SLEEP_PID=$!; wait; }
|
|
unset SLEEP_PID
|
|
sleep_time=$interval
|
|
for track_ip in $track_ips; do
|
|
if [ $host_up_count -lt $reliability ]; then
|
|
case "$track_method" in
|
|
ping)
|
|
if [ $check_quality -eq 0 ]; then
|
|
WRAP $PING -n -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null &
|
|
TRACK_PID=$!
|
|
wait $TRACK_PID
|
|
result=$?
|
|
else
|
|
WRAP $PING -n -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null > $TRACK_OUTPUT &
|
|
TRACK_PID=$!
|
|
wait $TRACK_PID
|
|
ping_status=$?
|
|
loss="$(sed $TRACK_OUTPUT -ne 's/.*\([0-9]\+\)% packet loss.*/\1/p')"
|
|
if [ "$ping_status" -ne 0 ] || [ "$loss" -eq 100 ]; then
|
|
latency=999999
|
|
loss=100
|
|
else
|
|
latency="$(sed $TRACK_OUTPUT -ne 's%\(rtt\|round-trip\).* = [^/]*/\([0-9]\+\).*%\2%p')"
|
|
fi
|
|
fi
|
|
;;
|
|
arping)
|
|
WRAP arping -I $DEVICE -c $count -w $timeout -q $track_ip &> /dev/null &
|
|
TRACK_PID=$!
|
|
wait $TRACK_PID
|
|
result=$?
|
|
;;
|
|
httping)
|
|
if [ "$httping_ssl" -eq 1 ]; then
|
|
WRAP httping -c $count -t $timeout -q "https://$track_ip" &> /dev/null &
|
|
else
|
|
WRAP httping -c $count -t $timeout -q "http://$track_ip" &> /dev/null &
|
|
fi
|
|
TRACK_PID=$!
|
|
wait $TRACK_PID
|
|
result=$?
|
|
;;
|
|
nping-*)
|
|
WRAP nping -c $count $track_ip --${FAMILY#nping-} > $TRACK_OUTPUT &
|
|
TRACK_PID=$!
|
|
wait $TRACK_PID
|
|
result=$(grep $TRACK_OUTPUT Lost | awk '{print $12}')
|
|
;;
|
|
esac
|
|
do_log=""
|
|
if [ $check_quality -eq 0 ]; then
|
|
if [ $result -eq 0 ]; then
|
|
let host_up_count++
|
|
update_status "$track_ip" "up"
|
|
|
|
[ $score -le $up ] && do_log="success"
|
|
else
|
|
let lost++
|
|
update_status "$track_ip" "down"
|
|
|
|
[ $score -gt $up ] && do_log="failed"
|
|
fi
|
|
[ -n "$do_log" ] && LOG info "Check ($track_method) ${do_log} for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
|
|
|
else
|
|
if [ "$loss" -ge "$failure_loss" ] || [ "$latency" -ge "$failure_latency" ]; then
|
|
let lost++
|
|
update_status "$track_ip" "down" $latency $loss
|
|
|
|
[ $score -gt $up ] && do_log="failed"
|
|
elif [ "$loss" -le "$recovery_loss" ] && [ "$latency" -le "$recovery_latency" ]; then
|
|
let host_up_count++
|
|
update_status "$track_ip" "up" $latency $loss
|
|
|
|
[ $score -le $up ] && do_log="success"
|
|
else
|
|
echo "skipped" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip}
|
|
fi
|
|
[ -n "$do_log" ] && LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) ${do_log} for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
|
fi
|
|
else
|
|
echo "skipped" > $MWAN3TRACK_STATUS_DIR/$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
|
|
disconnecting
|
|
sleep_time=$failure_interval
|
|
fi
|
|
|
|
if [ $score -eq $up ]; then
|
|
disconnected
|
|
score=0
|
|
fi
|
|
else
|
|
if [ $score -lt $((down+up)) ] && [ $lost -gt 0 ]; then
|
|
connecting
|
|
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" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
|
score=$((down+up))
|
|
elif [ $score -le $up ]; then
|
|
connecting
|
|
sleep_time=$recovery_interval
|
|
fi
|
|
|
|
if [ $score -eq $up ]; then
|
|
connected
|
|
fi
|
|
fi
|
|
|
|
let turn++
|
|
mkdir -p "$MWAN3TRACK_STATUS_DIR/${1}"
|
|
echo "${lost}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LOST
|
|
echo "${score}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/SCORE
|
|
echo "${turn}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TURN
|
|
get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TIME
|
|
|
|
host_up_count=0
|
|
if [ "${IFDOWN_EVENT}" -eq 0 ] && [ "${IFUP_EVENT}" -eq 0 ]; then
|
|
sleep "${sleep_time}" &
|
|
SLEEP_PID=$!
|
|
wait
|
|
unset SLEEP_PID
|
|
fi
|
|
|
|
if [ "${IFDOWN_EVENT}" -eq 1 ]; then
|
|
LOG debug "Register ifdown event on interface ${INTERFACE} (${DEVICE})"
|
|
disabled
|
|
disconnected
|
|
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 "$@"
|