# # DHCLIENT exit hook for vrf support. # # Code ported from https://github.com/CumulusNetworks/vrf under GPLv2 license # (see https://github.com/CumulusNetworks/vrf/blob/master/debian/copyright). # # Get table_id for device enslaved to a vrf. vrf_get_table_dev() { local table_id # If vrf_slave is not in the output, device is not enslaved. table_id=$(ip -o -d link show dev ${1} 2>/dev/null |\ egrep ' vrf_slave table [0-9]*' |\ sed -e 's/.*vrf_slave table \([0-9]*\) .*/\1/') [ -z "${table_id}" ] && return 1 echo ${table_id} return 0 } # Get table_id for vrf device. vrf_get_table() { local table_id table_id=$(ip -o -d link show dev ${1} 2>/dev/null |\ egrep ' vrf table [0-9]*' |\ sed -e 's/.*vrf table \([0-9]*\) .*/\1/') [ -z "${table_id}" ] && return 1 echo ${table_id} return 0 } vrf_exists() { local vrf=${1} local n [ "$vrf" = "default" ] && return 0 # ip link show dev type vrf happily returns 0 even though # is not of type vrf. Hence the wc -l. n=$(ip -br link show dev ${vrf} type vrf 2>/dev/null | wc -l) [ ${n} -eq 1 ] && return 0 return $? } # Check vrf device contains only alphanumeric characters. get_vrf_arg() { local vrf vrf=$(echo $1 | tr -cd [:alnum:]) if [ "$vrf" != "$1" ]; then echo "Invalid VRF" >&2 return 1 fi echo $vrf } vrf_table() { local table_id local vrf vrf=$(get_vrf_arg ${1}) [ $? -ne 0 ] && return 1 vrf_exists $vrf if [ $? -eq 0 ]; then vrf_get_table $vrf return 0 fi # Maybe this is a device, not a vrf. table_id=$(vrf_get_table_dev $vrf) if [ $? -eq 0 ]; then echo ${table_id} return 0 fi return 1 } table_id=$(vrf_table ${interface}) if [ -n "${table_id}" ]; then case "$reason" in BOUND|RENEW|REBIND|REBOOT) if [ -z "$old_ip_address" ] || [ "$old_ip_address" != "$new_ip_address" ] || [ "$reason" = "BOUND" ] || [ "$reason" = "REBOOT" ]; then # If we have $new_rfc3442_classless_static_routes then we have to # ignore $new_routers entirely. if [ ! "$new_rfc3442_classless_static_routes" ]; then # Set if_metric if IF_METRIC is set or there's more than one router. if_metric="$IF_METRIC" if [ "${new_routers%% *}" != "${new_routers}" ]; then if_metric=${if_metric:-1} fi for router in $new_routers; do if [ "$new_subnet_mask" = "255.255.255.255" ]; then # Set explicit route for p2p connection. ip -4 route add table ${table_id} ${router} dev $interface >/dev/null 2>&1 fi # Remove old default route should it remain from dhclient-script. ip -4 route del default via ${router} dev ${interface} \ ${if_metric:+metric $if_metric} >/dev/null 2>&1 # Set default route. ip -4 route add table ${table_id} default via ${router} dev ${interface} \ ${if_metric:+metric $if_metric} >/dev/null 2>&1 if [ -n "$if_metric" ]; then if_metric=$((if_metric+1)) fi done else set -- $new_rfc3442_classless_static_routes while [ $# -gt 0 ]; do net_length=$1 via_arg='' case $net_length in 32|31|30|29|28|27|26|25) if [ $# -lt 9 ]; then return 1 fi net_address="${2}.${3}.${4}.${5}" gateway="${6}.${7}.${8}.${9}" shift 9 ;; 24|23|22|21|20|19|18|17) if [ $# -lt 8 ]; then return 1 fi net_address="${2}.${3}.${4}.0" gateway="${5}.${6}.${7}.${8}" shift 8 ;; 16|15|14|13|12|11|10|9) if [ $# -lt 7 ]; then return 1 fi net_address="${2}.${3}.0.0" gateway="${4}.${5}.${6}.${7}" shift 7 ;; 8|7|6|5|4|3|2|1) if [ $# -lt 6 ]; then return 1 fi net_address="${2}.0.0.0" gateway="${3}.${4}.${5}.${6}" shift 6 ;; 0) # default route if [ $# -lt 5 ]; then return 1 fi net_address="0.0.0.0" gateway="${2}.${3}.${4}.${5}" shift 5 ;; *) # error return 1 ;; esac # Take care of link-local routes. if [ "${gateway}" != '0.0.0.0' ]; then via_arg="via ${gateway}" fi # Set route (ip detects host routes automatically). ip -4 route add table ${table_id} "${net_address}/${net_length}" \ ${via_arg} dev "${interface}" >/dev/null 2>&1 done fi fi if [ -n "$alias_ip_address" ] && [ "$new_ip_address" != "$alias_ip_address" ]; then ip -4 route add table ${table_id} ${alias_ip_address} dev ${interface} >/dev/null 2>&1 fi ;; EXPIRE|FAIL|RELEASE|STOP) if [ -n "$alias_ip_address" ]; then ip -4 route add table ${table_id} ${alias_ip_address} dev ${interface} >/dev/null 2>&1 fi ;; TIMEOUT) # If there is no router recorded in the lease or the 1st router answers pings. if [ -z "$new_routers" ] || ping -q -c 1 "${new_routers%% *}"; then # If we have $new_rfc3442_classless_static_routes then we have to # ignore $new_routers entirely. if [ ! "$new_rfc3442_classless_static_routes" ]; then if [ -n "$alias_ip_address" ] && [ "$new_ip_address" != "$alias_ip_address" ]; then ip -4 route add table ${table_id} ${alias_ip_address} dev ${interface} >/dev/null 2>&1 fi # Set default route. for router in $new_routers; do ip -4 route add table ${table_id} default via ${router} dev ${interface} \ ${if_metric:+metric $if_metric} >/dev/null 2>&1 if [ -n "$if_metric" ]; then if_metric=$((if_metric+1)) fi done fi fi ;; esac fi