shithub: riscv

ref: 440ccbc06007422f04943378260f250f9efa5331
dir: /rc/bin/ethermultilink/

View raw version
#!/bin/rc

# ethermultilink outpus bridge(3) commands to switch
# between multiple ethernet (or wifi) interfaces
# depending on their link status.
# the first argument is the primary interface,
# which is permanently added to the bridge
# while the following arguments are for secondary
# interfaces in increasing priority order.
# only the highest priority active interface is bound.

rfork e

fn usage {
	echo 'Usage: ' $0 'primaryether secondaryether1 [secondaryether2 ....] > /net/bridgeX/ctl' >[1=2]
	exit 'usage'
}
fn missing {
	echo 'missing: ' $1 >[1=2]
	exit 'missing'
}


~ $#* 0 1 && usage

# make sure arguments are ethernets
for(i){
	test -r $i/stats || missing $i/stats
}

# first interface is the primary
primary=$1
shift

ea=`{cat $primary/addr} || missing $primary/addr
net=`{echo $primary | sed 's!/*[^/]*$!!g'}
test -r $net/arp || missing $net/arp

# insert the primary to bridge
echo bind ether primary 0 $primary || exit

# now select secondary from the list depending on link status
@{
type=none
old=/dev/null
while(){
	# interfaces are in increasing priority order
	for(i){
		if(! ~ $i $primary && grep -s 'link: 1' $i/stats)
			secondary=$i
	}
	if(! ~ $secondary $old){
		echo $primary is switching from $old to $secondary >[1=2]

		if(! ~ $type none){
			echo unbind $type secondary 0
		}

		# if the secondary has the same ea as the primary,
		# we need to bind it in non-bridge mode
		type=ether
		if(~ $ea `{cat $secondary/addr})
			type=ethermac

		echo bind $type secondary 0 $secondary

		# make switches aware of the new path
		echo flush > $net/arp
	}
	old=$secondary
	sleep 1
}
} </dev/null &

exit ''