#!/bin/sh # Creating a VRF on linux (like `ip link add vrf_foobar type vrf table 10`) automatically inserts a # `l3mdev` rule (both IPv4 and IPv6) with preference 1000 by default. # # Sadly this means that the `lookup local` with preference 0 (the table `local` containing your # addresses in the "default VRF") is queried before that, which breaks routing of packets from a # VRF to your non-VRF addresses. # # So you actually want the `l3mdev` rule before the `lookup local` rule, and this script helps with # that. # # Your VRF routing table usually is contained completely in the table you specified when creating # the VRF; this script also creates an "pref 2000 l3mdev unreachable" rule to make sure within VRFs # no routes "outside" the VRF are used. (As an alternative you could add `unreachable default # metric 4278198272` routes in both IPv4 and IPv6 VRF tables). # # This should still leave enough room to add policy-based routing rules if you need them. # # Also see `vrf_prepare()` and `vrf_create()` in linux kernel # source:tools/testing/selftests/net/forwarding/lib.sh set -e has_rule() { if [ -n "$(ip $family rule list "$@")" ]; then # echo "Have: ip $family rule $*" return 0 else # echo "Have not: ip $family rule $*" return 1 fi } rule() { # echo "Running: ip $family rule $*" ip $family rule "$@" } run() { # move lookup local to pref 32765 (from 0) if ! has_rule pref 32765 lookup local; then rule add pref 32765 lookup local fi if has_rule pref 0 lookup local; then rule del pref 0 lookup local fi # make sure that in VRFs after failed lookup in the VRF specific table nothing else is reached if ! has_rule pref 1000 l3mdev; then # this should be added by the kernel when a VRF is created; add it here for completeness rule add pref 1000 l3mdev protocol kernel fi if ! has_rule pref 2000 l3mdev; then # can't search for actions; so can't make sure this is actually using "unreachable" rule add pref 2000 l3mdev unreachable fi } family=-4 run family=-6 run