Package: isc-dhcp-client
Version: 4.4.1-2.1+b2

The distributed dhclient-script will does not work correctly in a VRF 
environment, the default route will be added to the main routing table when the 
lease is obtained. This functionality should be extended, thus this is more of 
a feature request than a bug (though it does behave badly when presented with 
such an environment).
Example:
root@test:~# ip link add external type vrf table 1
root@test:~# ip rule add iif external table 1
root@test:~# ip rule add oif external table 1
root@test:~# ip link set ext master external
root@test:~# dhclient ext
root@test:~# ip route show table 1
broadcast 172.19.121.0 (172.19.226.0) dev ext proto kernel scope link src 
172.19.121.181
172.19.121.0/24 (172.19.226.0/24) dev ext proto kernel scope link src 
172.19.121.181
local 172.19.121.181 (172.19.226.181) dev ext proto kernel scope host src 
172.19.121.181 (172.19.226.181)
broadcast 172.19.121.255 (172.19.226.255) dev ext proto kernel scope link src 
172.19.121.181 (172.19.226.181)
root@test:~# ip route show
default via 172.19.121.1 (172.19.226.1) dev ext

Expected behavior: if the interface is in a VRF, the default route will be 
added to the VRF.
Here are the changes I made to the script (the detection method I used might 
break bridges though, however, I'd think bridge interfaces will never make it 
to that point anyway). My logic: detect whether this interface has a master or 
not, find it, find which table this route is meant to be a part of, and then 
set the string. If none of that happened, the string will be empty and things 
will work as they do now.
This could be improved (in many ways, but in particular) by doing a backcheck 
of ip link show vrf $vrf and observing that we do indeed see $interface within 
that output.
Tested in my environment and it properly gives two default routes, one in the 
VRF, one not.
--- /sbin/dhclient-script 2020-03-23 03:08:55.000000000 -0600
+++ dhclient-script 2020-07-04 10:34:11.197856308 -0600
@@ -264,15 +264,23 @@
if_metric=${if_metric:-1}
fi

+ # For VRFs.
+ vrf="`ip link show dev ${interface} | grep master | awk '{print $9}'`"
+ if [ ! -z $vrf ]; then
+ # find parent table
+ vrf_table="`ip vrf show | grep $vrf | awk '{print $2}'`"
+ vrf_string="table $vrf_table"
+ fi
+
for router in $new_routers; do
if [ "$new_subnet_mask" = "255.255.255.255" ]; then
# point-to-point connection => set explicit route
- ip -4 route add ${router} dev $interface >/dev/null 2>&1
+ ip -4 route add ${router} dev $interface $vrf_string >/dev/null 2>&1
fi

# set default route
ip -4 route add default via ${router} dev ${interface} \
- ${if_metric:+metric $if_metric} >/dev/null 2>&1
+ ${if_metric:+metric $if_metric} $vrf_string >/dev/null 2>&1

if [ -n "$if_metric" ]; then
if_metric=$((if_metric+1))

Reply via email to