Merging multiple routes into a single multipath route

Daniel Gröber dxld at darkboxed.org
Sun May 8 10:26:26 CEST 2022


Hi Johannes,

On Tue, May 03, 2022 at 04:07:08PM +0200, Johannes Erwerle wrote:
> I would like to use both uplinks via the linux multipath routing and I am
> searching for a way to "merge" both default routes that I get into one route
> with multiple next hops.
> 
> Is there a way to accomplish that with bird? (or any other tool?)

Instead of letting the dhcp client install the routes and then trying to
massage them into shape you could do this directly by configuring the dhcp
client appropriately. The isc-dhcp client actually and very good support
for scripting in dhclient-*-hooks.d that lets you override what the
dhclient-script (which handles the OS specific stuff) does by default.

I have been working on a dhcp script myself to allow for VRRP redundancy on
a DHCP managed interface. You should be able to use the
neutralize_ip_change hack I use to override iproute2 commands called by
dhclient-script for your purposes too:

    neutralize_ip_change () {
        ip () neutered_ip "$@"
    }
    neutered_ip () { : do stuff and call real "ip" command; }

This works because dhclient-script (a bash script) sources the hooks so we
can mess with the shell environment to override the "ip" command with a
shell function that matches on the args and does whatever we want.

Script attached since I haven't published it anywhere yet. Note this is
only lightly tested so far but I'd be happy to help you make this work for
your use-case.

--Daniel
-------------- next part --------------
#!/bin/sh
# Install into /etc/dhcp and symlink to /etc/dhcp/dhclient-{enter,exit}-hooks.d

IFACE=enp9s0f1.4
VRID=4
PRIO=100
DUMMYIP_OLD=192.168.254.254
DUMMYIP_NEW=192.168.254.253

PIDFILE=/var/run/"vrrpd_${IFACE}_${VRID}.pid"
HOOKDIR="$(basename "$dir")"

## Debugging
#set -x
#exec >> /tmp/dhcp.log 2>&1
echo $HOOKDIR $reason $interface >>/tmp/dhcp.log
set | grep 'ip_address\|route' | sort >>/tmp/dhcp.log
printf '\n\n' >>/tmp/dhcp.log

killvrrp () {
	echo "killvrrp $PIDFILE" >>/tmp/dhcp.log
	[ -n $old_ip_address ] || return
	if [ -e "$PIDFILE" ]; then
		kill "$(cat $PIDFILE)" || true
	fi
}

startvrrp () {
	echo "startvrrp $new_ip_address\n" >>/tmp/dhcp.log
	[ -n $new_ip_address ] || return
	echo vrrpd -D -n -i "$interface" -v "$VRID" -p "$PRIO" "$new_ip_address"
	vrrpd -D -n -i "$interface" -v "$VRID" -p "$PRIO" "$new_ip_address" ||
		exit_status=1
}

# dhclient-script insists on fucking with the IP address, we don't want any
# of that since vrrpd will do it.
neutralize_ip_change () {
	ip () neutered_ip "$@"
}

neutered_ip () {
	[ $# -ge 3 ] || { ip "$@"; return; }
	if
		[ "$1" = "-4" -a "$2" = addr -a "$3" = flush ] ||
		[ "$1" = "-4" -a "$2" = addr -a "$3" = add ] ||
		[ "$1" = "-4" -a "$2" = addr -a "$3" = change ]
	then
		echo ignored "$@"
		return
	else
		echo =ip "$@"
		command ip "$@"
	fi
}

do_vrrp () {

if [ "$HOOKDIR" = "dhclient-enter-hooks.d" ]; then
	case $reason in
		BOUND | REBOOT | TIMEOUT) ;; # Just started shouldn't be running
		RENEW | REBIND)
			[ $new_ip_address = $old_ip_address] || killvrrp ;;
		EXPIRE | FAIL | RELEASE | STOP | TIMEOUT)
			killvrrp ;;
	esac

	neutralize_ip_change
elif [ "$HOOKDIR" = "dhclient-exit-hooks.d" ]; then
	case $reason in
		# Note: TIMEOUT is when we can't reach a dhcp server during
		# startup but have a valid lease still that we're going to
		# use.
		BOUND | REBOOT | TIMEOUT)
			startvrrp ;;
		RENEW | REBIND)
			[ $new_ip_address = $old_ip_address] || startvrrp ;;
		EXPIRE | FAIL | RELEASE) ;;
	esac
fi
}

if [ "$interface" = $IFACE ]; then
	do_vrrp
fi


More information about the Bird-users mailing list