#
# 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 <name> type vrf happily returns 0 even though
	# <name> 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