#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Author: Jesper Dangaard Brouer # Allow wrapper scripts to name test if [ -z "$TESTNAME" ]; then TESTNAME=xdp_vlan fi # Default XDP mode XDP_MODE=xdpgeneric usage() { echo "Testing XDP + TC eBPF VLAN manipulations: $TESTNAME" echo "" echo "Usage: $0 [-vfh]" echo " -v | --verbose : Verbose" echo " --flush : Flush before starting (e.g. after --interactive)" echo " --interactive : Keep netns setup running after test-run" echo " --mode=XXX : Choose XDP mode (xdp | xdpgeneric | xdpdrv)" echo "" } valid_xdp_mode() { local mode=$1 case "$mode" in xdpgeneric | xdpdrv | xdp) return 0 ;; *) return 1 esac } cleanup() { local status=$? if [ "$status" = "0" ]; then echo "selftests: $TESTNAME [PASS]"; else echo "selftests: $TESTNAME [FAILED]"; fi if [ -n "$INTERACTIVE" ]; then echo "Namespace setup still active explore with:" echo " ip netns exec ns1 bash" echo " ip netns exec ns2 bash" exit $status fi set +e ip link del veth1 2> /dev/null ip netns del ns1 2> /dev/null ip netns del ns2 2> /dev/null } # Using external program "getopt" to get --long-options OPTIONS=$(getopt -o hvfi: \ --long verbose,flush,help,interactive,debug,mode: -- "$@") if (( $? != 0 )); then usage echo "selftests: $TESTNAME [FAILED] Error calling getopt, unknown option?" exit 2 fi eval set -- "$OPTIONS" ## --- Parse command line arguments / parameters --- while true; do case "$1" in -v | --verbose) export VERBOSE=yes shift ;; -i | --interactive | --debug ) INTERACTIVE=yes shift ;; -f | --flush ) cleanup shift ;; --mode ) shift XDP_MODE=$1 shift ;; -- ) shift break ;; -h | --help ) usage; echo "selftests: $TESTNAME [SKIP] usage help info requested" exit 0 ;; * ) shift break ;; esac done if [ "$EUID" -ne 0 ]; then echo "selftests: $TESTNAME [FAILED] need root privileges" exit 1 fi valid_xdp_mode $XDP_MODE if [ $? -ne 0 ]; then echo "selftests: $TESTNAME [FAILED] unknown XDP mode ($XDP_MODE)" exit 1 fi ip link set dev lo xdpgeneric off 2>/dev/null > /dev/null if [ $? -ne 0 ]; then echo "selftests: $TESTNAME [SKIP] need ip xdp support" exit 0 fi # Interactive mode likely require us to cleanup netns if [ -n "$INTERACTIVE" ]; then ip link del veth1 2> /dev/null ip netns del ns1 2> /dev/null ip netns del ns2 2> /dev/null fi # Exit on failure set -e # Some shell-tools dependencies which ip > /dev/null which tc > /dev/null which ethtool > /dev/null # Make rest of shell verbose, showing comments as doc/info if [ -n "$VERBOSE" ]; then set -v fi # Create two namespaces ip netns add ns1 ip netns add ns2 # Run cleanup if failing or on kill trap cleanup 0 2 3 6 9 # Create veth pair ip link add veth1 type veth peer name veth2 # Move veth1 and veth2 into the respective namespaces ip link set veth1 netns ns1 ip link set veth2 netns ns2 # NOTICE: XDP require VLAN header inside packet payload # - Thus, disable VLAN offloading driver features # - For veth REMEMBER TX side VLAN-offload # # Disable rx-vlan-offload (mostly needed on ns1) ip netns exec ns1 ethtool -K veth1 rxvlan off ip netns exec ns2 ethtool -K veth2 rxvlan off # # Disable tx-vlan-offload (mostly needed on ns2) ip netns exec ns2 ethtool -K veth2 txvlan off ip netns exec ns1 ethtool -K veth1 txvlan off export IPADDR1=100.64.41.1 export IPADDR2=100.64.41.2 # In ns1/veth1 add IP-addr on plain net_device ip netns exec ns1 ip addr add ${IPADDR1}/24 dev veth1 ip netns exec ns1 ip link set veth1 up # In ns2/veth2 create VLAN device export VLAN=4011 export DEVNS2=veth2 ip netns exec ns2 ip link add link $DEVNS2 name $DEVNS2.$VLAN type vlan id $VLAN ip netns exec ns2 ip addr add ${IPADDR2}/24 dev $DEVNS2.$VLAN ip netns exec ns2 ip link set $DEVNS2 up ip netns exec ns2 ip link set $DEVNS2.$VLAN up # Bringup lo in netns (to avoids confusing people using --interactive) ip netns exec ns1 ip link set lo up ip netns exec ns2 ip link set lo up # At this point, the hosts cannot reach each-other, # because ns2 are using VLAN tags on the packets. ip netns exec ns2 sh -c 'ping -W 1 -c 1 100.64.41.1 || echo "Success: First ping must fail"' # Now we can use the test_xdp_vlan.c program to pop/push these VLAN tags # ---------------------------------------------------------------------- # In ns1: ingress use XDP to remove VLAN tags export DEVNS1=veth1 export FILE=test_xdp_vlan.o # First test: Remove VLAN by setting VLAN ID 0, using "xdp_vlan_change" export XDP_PROG=xdp_vlan_change ip netns exec ns1 ip link set $DEVNS1 $XDP_MODE object $FILE section $XDP_PROG # In ns1: egress use TC to add back VLAN tag 4011 # (del cmd) # tc qdisc del dev $DEVNS1 clsact 2> /dev/null # ip netns exec ns1 tc qdisc add dev $DEVNS1 clsact ip netns exec ns1 tc filter add dev $DEVNS1 egress \ prio 1 handle 1 bpf da obj $FILE sec tc_vlan_push # Now the namespaces can reach each-other, test with ping: ip netns exec ns2 ping -i 0.2 -W 2 -c 2 $IPADDR1 ip netns exec ns1 ping -i 0.2 -W 2 -c 2 $IPADDR2 # Second test: Replace xdp prog, that fully remove vlan header # # Catch kernel bug for generic-XDP, that does didn't allow us to # remove a VLAN header, because skb->protocol still contain VLAN # ETH_P_8021Q indication, and this cause overwriting of our changes. # export XDP_PROG=xdp_vlan_remove_outer2 ip netns exec ns1 ip link set $DEVNS1 $XDP_MODE off ip netns exec ns1 ip link set $DEVNS1 $XDP_MODE object $FILE section $XDP_PROG # Now the namespaces should still be able reach each-other, test with ping: ip netns exec ns2 ping -i 0.2 -W 2 -c 2 $IPADDR1 ip netns exec ns1 ping -i 0.2 -W 2 -c 2 $IPADDR2