#!/bin/bash# SPDX-License-Identifier: GPL-2.0## OVS kernel module self tests trap ovs_exit_sig EXIT TERM INT ERR # Kselftest framework requirement - SKIP code is 4.ksft_skip=4 PAUSE_ON_FAIL=noVERBOSE=0TRACING=0WAIT_TIMEOUT=5 if test "X$KSFT_MACHINE_SLOW" == "Xyes"; then WAIT_TIMEOUT=10fi tests=" arp_ping eth-arp: Basic arp ping between two NS ct_connect_v4 ip4-ct-xon: Basic ipv4 tcp connection using ct connect_v4 ip4-xon: Basic ipv4 ping between two NS nat_connect_v4 ip4-nat-xon: Basic ipv4 tcp connection via NAT nat_related_v4 ip4-nat-related: ICMP related matches work with SNAT netlink_checks ovsnl: validate netlink attrs and settings upcall_interfaces ovs: test the upcall interfaces tunnel_metadata ovs: test extraction of tunnel metadata drop_reason drop: test drop reasons are emitted pop_vlan vlan: POP_VLAN action strips tag dec_ttl ttl: dec_ttl decrements IP TTL flow_set flow-set: Flow modify action_set set: SET action rewrites fields trunc trunc: output truncation icmpv6 icmpv6: ICMPv6 echo type match sctp_connect_v4 sctp: SCTP flow key matching psample psample: Sampling packets with psample" info() { [ "${ovs_dir}" != "" ] && echo "`date +"[%m-%d %H:%M:%S]"` $*" >> ${ovs_dir}/debug.log [ $VERBOSE = 0 ] || echo $*} ovs_wait() { info "waiting $WAIT_TIMEOUT s for: $@" if "$@" ; then info "wait succeeded immediately" return 0 fi # A quick re-check helps speed up small races in fast systems. # However, fractional sleeps might not necessarily work. local start=0 sleep 0.1 || { sleep 1; start=1; } for (( i=start; i<WAIT_TIMEOUT; i++ )); do if "$@" ; then info "wait succeeded after $i seconds" return 0 fi sleep 1 done info "wait failed after $i seconds" return 1} ovs_base=`pwd`sbxs=sbx_add () { info "adding sandbox '$1'" sbxs="$sbxs $1" NO_BIN=0 # Create sandbox. local d="$ovs_base"/$1 if [ -e $d ]; then info "removing $d" rm -rf "$d" fi mkdir "$d" || return 1 ovs_setenv $1} ovs_exit_sig() { [ -e ${ovs_dir}/cleanup ] && . "$ovs_dir/cleanup"} on_exit() { echo "$1" > ${ovs_dir}/cleanup.tmp cat ${ovs_dir}/cleanup >> ${ovs_dir}/cleanup.tmp mv ${ovs_dir}/cleanup.tmp ${ovs_dir}/cleanup} ovs_setenv() { sandbox=$1 ovs_dir=$ovs_base${1:+/$1}; export ovs_dir test -e ${ovs_dir}/cleanup || : > ${ovs_dir}/cleanup} ovs_sbx() { if test "X$2" != X; then (ovs_setenv $1; shift; info "run cmd: $@"; "$@" >> ${ovs_dir}/debug.log) else ovs_setenv $1 fi} ovs_add_dp () { info "Adding DP/Bridge IF: sbx:$1 dp:$2 {$3, $4, $5}" sbxname="$1" shift ovs_sbx "$sbxname" python3 $ovs_base/ovs-dpctl.py add-dp $* on_exit "ovs_sbx $sbxname python3 $ovs_base/ovs-dpctl.py del-dp $1;"} ovs_add_if () { info "Adding IF to DP: br:$3 if:$4 ($2)" if [ "$5" != "-u" ]; then ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-if \ -t "$2" "$3" "$4" || return 1 else python3 $ovs_base/ovs-dpctl.py add-if \ -u -t "$2" "$3" "$4" >$ovs_dir/$4.out 2>$ovs_dir/$4.err & pid=$! on_exit "ovs_sbx $1 kill -TERM $pid 2>/dev/null" fi} ovs_del_if () { info "Deleting IF from DP: br:$2 if:$3" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-if "$2" "$3" || return 1} ovs_netns_spawn_daemon() { sbx=$1 shift netns=$1 shift if [ "$netns" == "_default" ]; then $* >> $ovs_dir/stdout 2>> $ovs_dir/stderr & else ip netns exec $netns $* >> $ovs_dir/stdout 2>> $ovs_dir/stderr & fi pid=$! ovs_sbx "$sbx" on_exit "kill -TERM $pid 2>/dev/null"} ovs_spawn_daemon() { sbx=$1 shift ovs_netns_spawn_daemon $sbx "_default" $*} ovs_add_netns_and_veths () { info "Adding netns attached: sbx:$1 dp:$2 {$3, $4, $5}" ovs_sbx "$1" ip netns add "$3" || return 1 on_exit "ovs_sbx $1 ip netns del $3" ovs_sbx "$1" ip link add "$4" type veth peer name "$5" || return 1 on_exit "ovs_sbx $1 ip link del $4 >/dev/null 2>&1" ovs_sbx "$1" ip link set "$4" up || return 1 ovs_sbx "$1" ip link set "$5" netns "$3" || return 1 ovs_sbx "$1" ip netns exec "$3" ip link set "$5" up || return 1 if [ "$6" != "" ]; then ovs_sbx "$1" ip netns exec "$3" ip addr add "$6" dev "$5" \ || return 1 fi if [ "$7" != "-u" ]; then ovs_add_if "$1" "netdev" "$2" "$4" || return 1 else ovs_add_if "$1" "netdev" "$2" "$4" -u || return 1 fi if [ $TRACING -eq 1 ]; then ovs_netns_spawn_daemon "$1" "$3" tcpdump -l -i any -s 6553 ovs_wait grep -q "listening on any" ${ovs_dir}/stderr fi return 0} ovs_add_flow () { info "Adding flow to DP: sbx:$1 br:$2 flow:$3 act:$4" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-flow "$2" "$3" "$4" if [ $? -ne 0 ]; then info "Flow [ $3 : $4 ] failed" return 1 fi return 0} ovs_mod_flow () { if [ -n "$4" ]; then info "Modifying flow: sbx:$1 br:$2 flow:$3 act:$4" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \ mod-flow "$2" "$3" "$4" else info "Modifying flow (no actions): sbx:$1 br:$2 flow:$3" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \ mod-flow "$2" "$3" fi if [ $? -ne 0 ]; then info "Flow modify [ $3 ] failed" return 1 fi return 0} ovs_del_flows () { info "Deleting all flows from DP: sbx:$1 br:$2" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-flows "$2" return 0} ovs_drop_record_and_run () { local sbx=$1 shift perf record -a -q -e skb:kfree_skb -o ${ovs_dir}/perf.data $* \ >> ${ovs_dir}/stdout 2>> ${ovs_dir}/stderr return $?} ovs_drop_reason_count(){ local reason=$1 local perf_output=`perf script -i ${ovs_dir}/perf.data -F trace:event,trace` local pattern="skb:kfree_skb:.*reason: $reason" return `echo "$perf_output" | grep "$pattern" | wc -l`} ovs_test_flow_fails () { ERR_MSG="Flow actions may not be safe on all matching packets" PRE_TEST=$(dmesg | grep -c "${ERR_MSG}") ovs_add_flow $@ &> /dev/null $@ && return 1 POST_TEST=$(dmesg | grep -c "${ERR_MSG}") if [ "$PRE_TEST" == "$POST_TEST" ]; then return 1 fi return 0} usage() { echo echo "$0 [OPTIONS] [TEST]..." echo "If no TEST argument is given, all tests will be run." echo echo "Options" echo " -t: capture traffic via tcpdump" echo " -v: verbose" echo " -p: pause on failure" echo echo "Available tests${tests}" exit 1} test_dec_ttl() { sbx_add "test_dec_ttl" || return $? ovs_add_dp "test_dec_ttl" decttl || return 1 info "create namespaces" for ns in client server; do ovs_add_netns_and_veths "test_dec_ttl" "decttl" "$ns" \ "${ns:0:1}0" "${ns:0:1}1" || return 1 done ip netns exec client ip addr add 10.0.0.1/24 dev c1 ip netns exec client ip link set c1 up ip netns exec server ip addr add 10.0.0.2/24 dev s1 ip netns exec server ip link set s1 up # Probe: check if kernel supports dec_ttl action. ovs_add_flow "test_dec_ttl" decttl \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'dec_ttl(le_1())' &>/dev/null if [ $? -ne 0 ]; then info "no support for dec_ttl - skipping" ovs_exit_sig return $ksft_skip fi ovs_del_flows "test_dec_ttl" decttl # ARP flows (bidirectional) ovs_add_flow "test_dec_ttl" decttl \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_dec_ttl" decttl \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 # IP flows with dec_ttl action ovs_add_flow "test_dec_ttl" decttl \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'dec_ttl(le_1()),2' || return 1 ovs_add_flow "test_dec_ttl" decttl \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' \ 'dec_ttl(le_1()),1' || return 1 info "verify connectivity with dec_ttl" ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 || return 1 info "verify TTL=1 is dropped by dec_ttl" ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \ -t 1 10.0.0.2 >/dev/null 2>&1 \ && { info "FAIL: ping should fail with TTL=1 and dec_ttl" return 1; } return 0} test_flow_set() { sbx_add "test_flow_set" || return $? ovs_add_dp "test_flow_set" flowset || return 1 info "create namespaces" for ns in client server; do ovs_add_netns_and_veths "test_flow_set" "flowset" "$ns" \ "${ns:0:1}0" "${ns:0:1}1" || return 1 done ip netns exec client ip addr add 10.0.0.1/24 dev c1 ip netns exec client ip link set c1 up ip netns exec server ip addr add 10.0.0.2/24 dev s1 ip netns exec server ip link set s1 up ovs_add_flow "test_flow_set" flowset \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_flow_set" flowset \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 local fwd_flow="ufid:00000001-0002-0003-0004-000500060007" fwd_flow="$fwd_flow,in_port(1),eth(),eth_type(0x0800),ipv4()" ovs_add_flow "test_flow_set" flowset "$fwd_flow" '2' \ || return 1 ovs_add_flow "test_flow_set" flowset \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 info "verify initial forwarding" ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 || return 1 info "mod-flow with new actions (change to drop)" ovs_mod_flow "test_flow_set" flowset "$fwd_flow" 'drop' \ || return 1 info "verify traffic is now dropped" ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 >/dev/null 2>&1 \ && { info "FAIL: ping should fail after mod-flow to drop" return 1; } info "mod-flow without actions" ovs_mod_flow "test_flow_set" flowset "$fwd_flow" || return 1 info "verify flow retained drop action via dump" python3 "$ovs_base/ovs-dpctl.py" dump-flows flowset \ | grep -q "actions:drop" || \ { info "FAIL: flow not showing drop action"; return 1; } info "verify drop actions unchanged" ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 >/dev/null 2>&1 \ && { info "FAIL: ping should still fail after no-actions set" return 1; } return 0} test_action_set() { sbx_add "test_action_set" || return $? ovs_add_dp "test_action_set" settest || return 1 info "create namespaces" for ns in client server; do ovs_add_netns_and_veths "test_action_set" "settest" "$ns" \ "${ns:0:1}0" "${ns:0:1}1" || return 1 done ip netns exec client ip addr add 10.0.0.1/24 dev c1 ip netns exec client ip link set c1 up ip netns exec server ip addr add 10.0.0.2/24 dev s1 ip netns exec server ip link set s1 up ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 info "verify connectivity without SET" ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 || return 1 ovs_del_flows "test_action_set" settest ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 info "set ipv4 dst to unreachable address" ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'set(ipv4(dst=10.0.0.99)),2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 info "verify ping fails with rewritten dst" ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 >/dev/null 2>&1 \ && { info "FAIL: ping should fail with dst rewritten" return 1; } ovs_del_flows "test_action_set" settest ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 info "verify connectivity restored without SET" ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 || return 1 return 0} # trunc test# - trunc(14): truncate to ETH_HLEN, strips IP payload, ping fails# - trunc(1) and trunc(13): kernel rejects below ETH_HLEN (EINVAL)# - restore normal forwarding and verify recoverytest_trunc() { sbx_add "test_trunc" || return $? ovs_add_dp "test_trunc" trunctest || return 1 info "create namespaces" for ns in client server; do ovs_add_netns_and_veths "test_trunc" "trunctest" \ "$ns" "${ns:0:1}0" "${ns:0:1}1" || return 1 done ip netns exec client ip addr add 10.0.0.1/24 dev c1 ip netns exec client ip link set c1 up ip netns exec server ip addr add 10.0.0.2/24 dev s1 ip netns exec server ip link set s1 up ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_trunc" trunctest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ '2' || return 1 ovs_add_flow "test_trunc" trunctest \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' \ '1' || return 1 info "verify connectivity without truncation" ovs_sbx "test_trunc" ip netns exec client \ ping -c 1 -W 2 10.0.0.2 || return 1 # trunc below ETH_HLEN must be rejected by the kernel info "verify trunc(1) is rejected" ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'trunc(1),2' &> /dev/null \ && { info "trunc(1) should be rejected"; return 1; } info "verify trunc(13) is rejected" ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'trunc(13),2' &> /dev/null \ && { info "trunc(13) should be rejected"; return 1; } ovs_del_flows "test_trunc" trunctest ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_trunc" trunctest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 Lines 1–500 of 1493. Load more
#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # # OVS kernel module self tests trap ovs_exit_sig EXIT TERM INT ERR # Kselftest framework requirement - SKIP code is 4. ksft_skip=4 PAUSE_ON_FAIL=no VERBOSE=0 TRACING=0 WAIT_TIMEOUT=5 if test "X$KSFT_MACHINE_SLOW" == "Xyes"; then WAIT_TIMEOUT=10 fi tests=" arp_ping eth-arp: Basic arp ping between two NS ct_connect_v4 ip4-ct-xon: Basic ipv4 tcp connection using ct connect_v4 ip4-xon: Basic ipv4 ping between two NS nat_connect_v4 ip4-nat-xon: Basic ipv4 tcp connection via NAT nat_related_v4 ip4-nat-related: ICMP related matches work with SNAT netlink_checks ovsnl: validate netlink attrs and settings upcall_interfaces ovs: test the upcall interfaces tunnel_metadata ovs: test extraction of tunnel metadata drop_reason drop: test drop reasons are emitted pop_vlan vlan: POP_VLAN action strips tag dec_ttl ttl: dec_ttl decrements IP TTL flow_set flow-set: Flow modify action_set set: SET action rewrites fields trunc trunc: output truncation icmpv6 icmpv6: ICMPv6 echo type match sctp_connect_v4 sctp: SCTP flow key matching psample psample: Sampling packets with psample" info() { [ "${ovs_dir}" != "" ] && echo "`date +"[%m-%d %H:%M:%S]"` $*" >> ${ovs_dir}/debug.log [ $VERBOSE = 0 ] || echo $* } ovs_wait() { info "waiting $WAIT_TIMEOUT s for: $@" if "$@" ; then info "wait succeeded immediately" return 0 fi # A quick re-check helps speed up small races in fast systems. # However, fractional sleeps might not necessarily work. local start=0 sleep 0.1 || { sleep 1; start=1; } for (( i=start; i<WAIT_TIMEOUT; i++ )); do if "$@" ; then info "wait succeeded after $i seconds" return 0 fi sleep 1 done info "wait failed after $i seconds" return 1 } ovs_base=`pwd` sbxs= sbx_add () { info "adding sandbox '$1'" sbxs="$sbxs $1" NO_BIN=0 # Create sandbox. local d="$ovs_base"/$1 if [ -e $d ]; then info "removing $d" rm -rf "$d" fi mkdir "$d" || return 1 ovs_setenv $1 } ovs_exit_sig() { [ -e ${ovs_dir}/cleanup ] && . "$ovs_dir/cleanup" } on_exit() { echo "$1" > ${ovs_dir}/cleanup.tmp cat ${ovs_dir}/cleanup >> ${ovs_dir}/cleanup.tmp mv ${ovs_dir}/cleanup.tmp ${ovs_dir}/cleanup } ovs_setenv() { sandbox=$1 ovs_dir=$ovs_base${1:+/$1}; export ovs_dir test -e ${ovs_dir}/cleanup || : > ${ovs_dir}/cleanup } ovs_sbx() { if test "X$2" != X; then (ovs_setenv $1; shift; info "run cmd: $@"; "$@" >> ${ovs_dir}/debug.log) else ovs_setenv $1 fi } ovs_add_dp () { info "Adding DP/Bridge IF: sbx:$1 dp:$2 {$3, $4, $5}" sbxname="$1" shift ovs_sbx "$sbxname" python3 $ovs_base/ovs-dpctl.py add-dp $* on_exit "ovs_sbx $sbxname python3 $ovs_base/ovs-dpctl.py del-dp $1;" } ovs_add_if () { info "Adding IF to DP: br:$3 if:$4 ($2)" if [ "$5" != "-u" ]; then ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-if \ -t "$2" "$3" "$4" || return 1 else python3 $ovs_base/ovs-dpctl.py add-if \ -u -t "$2" "$3" "$4" >$ovs_dir/$4.out 2>$ovs_dir/$4.err & pid=$! on_exit "ovs_sbx $1 kill -TERM $pid 2>/dev/null" fi } ovs_del_if () { info "Deleting IF from DP: br:$2 if:$3" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-if "$2" "$3" || return 1 } ovs_netns_spawn_daemon() { sbx=$1 shift netns=$1 shift if [ "$netns" == "_default" ]; then $* >> $ovs_dir/stdout 2>> $ovs_dir/stderr & else ip netns exec $netns $* >> $ovs_dir/stdout 2>> $ovs_dir/stderr & fi pid=$! ovs_sbx "$sbx" on_exit "kill -TERM $pid 2>/dev/null" } ovs_spawn_daemon() { sbx=$1 shift ovs_netns_spawn_daemon $sbx "_default" $* } ovs_add_netns_and_veths () { info "Adding netns attached: sbx:$1 dp:$2 {$3, $4, $5}" ovs_sbx "$1" ip netns add "$3" || return 1 on_exit "ovs_sbx $1 ip netns del $3" ovs_sbx "$1" ip link add "$4" type veth peer name "$5" || return 1 on_exit "ovs_sbx $1 ip link del $4 >/dev/null 2>&1" ovs_sbx "$1" ip link set "$4" up || return 1 ovs_sbx "$1" ip link set "$5" netns "$3" || return 1 ovs_sbx "$1" ip netns exec "$3" ip link set "$5" up || return 1 if [ "$6" != "" ]; then ovs_sbx "$1" ip netns exec "$3" ip addr add "$6" dev "$5" \ || return 1 fi if [ "$7" != "-u" ]; then ovs_add_if "$1" "netdev" "$2" "$4" || return 1 else ovs_add_if "$1" "netdev" "$2" "$4" -u || return 1 fi if [ $TRACING -eq 1 ]; then ovs_netns_spawn_daemon "$1" "$3" tcpdump -l -i any -s 6553 ovs_wait grep -q "listening on any" ${ovs_dir}/stderr fi return 0 } ovs_add_flow () { info "Adding flow to DP: sbx:$1 br:$2 flow:$3 act:$4" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-flow "$2" "$3" "$4" if [ $? -ne 0 ]; then info "Flow [ $3 : $4 ] failed" return 1 fi return 0 } ovs_mod_flow () { if [ -n "$4" ]; then info "Modifying flow: sbx:$1 br:$2 flow:$3 act:$4" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \ mod-flow "$2" "$3" "$4" else info "Modifying flow (no actions): sbx:$1 br:$2 flow:$3" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \ mod-flow "$2" "$3" fi if [ $? -ne 0 ]; then info "Flow modify [ $3 ] failed" return 1 fi return 0 } ovs_del_flows () { info "Deleting all flows from DP: sbx:$1 br:$2" ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-flows "$2" return 0 } ovs_drop_record_and_run () { local sbx=$1 shift perf record -a -q -e skb:kfree_skb -o ${ovs_dir}/perf.data $* \ >> ${ovs_dir}/stdout 2>> ${ovs_dir}/stderr return $? } ovs_drop_reason_count() { local reason=$1 local perf_output=`perf script -i ${ovs_dir}/perf.data -F trace:event,trace` local pattern="skb:kfree_skb:.*reason: $reason" return `echo "$perf_output" | grep "$pattern" | wc -l` } ovs_test_flow_fails () { ERR_MSG="Flow actions may not be safe on all matching packets" PRE_TEST=$(dmesg | grep -c "${ERR_MSG}") ovs_add_flow $@ &> /dev/null $@ && return 1 POST_TEST=$(dmesg | grep -c "${ERR_MSG}") if [ "$PRE_TEST" == "$POST_TEST" ]; then return 1 fi return 0 } usage() { echo echo "$0 [OPTIONS] [TEST]..." echo "If no TEST argument is given, all tests will be run." echo echo "Options" echo " -t: capture traffic via tcpdump" echo " -v: verbose" echo " -p: pause on failure" echo echo "Available tests${tests}" exit 1 } test_dec_ttl() { sbx_add "test_dec_ttl" || return $? ovs_add_dp "test_dec_ttl" decttl || return 1 info "create namespaces" for ns in client server; do ovs_add_netns_and_veths "test_dec_ttl" "decttl" "$ns" \ "${ns:0:1}0" "${ns:0:1}1" || return 1 done ip netns exec client ip addr add 10.0.0.1/24 dev c1 ip netns exec client ip link set c1 up ip netns exec server ip addr add 10.0.0.2/24 dev s1 ip netns exec server ip link set s1 up # Probe: check if kernel supports dec_ttl action. ovs_add_flow "test_dec_ttl" decttl \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'dec_ttl(le_1())' &>/dev/null if [ $? -ne 0 ]; then info "no support for dec_ttl - skipping" ovs_exit_sig return $ksft_skip fi ovs_del_flows "test_dec_ttl" decttl # ARP flows (bidirectional) ovs_add_flow "test_dec_ttl" decttl \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_dec_ttl" decttl \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 # IP flows with dec_ttl action ovs_add_flow "test_dec_ttl" decttl \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'dec_ttl(le_1()),2' || return 1 ovs_add_flow "test_dec_ttl" decttl \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' \ 'dec_ttl(le_1()),1' || return 1 info "verify connectivity with dec_ttl" ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 || return 1 info "verify TTL=1 is dropped by dec_ttl" ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \ -t 1 10.0.0.2 >/dev/null 2>&1 \ && { info "FAIL: ping should fail with TTL=1 and dec_ttl" return 1; } return 0 } test_flow_set() { sbx_add "test_flow_set" || return $? ovs_add_dp "test_flow_set" flowset || return 1 info "create namespaces" for ns in client server; do ovs_add_netns_and_veths "test_flow_set" "flowset" "$ns" \ "${ns:0:1}0" "${ns:0:1}1" || return 1 done ip netns exec client ip addr add 10.0.0.1/24 dev c1 ip netns exec client ip link set c1 up ip netns exec server ip addr add 10.0.0.2/24 dev s1 ip netns exec server ip link set s1 up ovs_add_flow "test_flow_set" flowset \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_flow_set" flowset \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 local fwd_flow="ufid:00000001-0002-0003-0004-000500060007" fwd_flow="$fwd_flow,in_port(1),eth(),eth_type(0x0800),ipv4()" ovs_add_flow "test_flow_set" flowset "$fwd_flow" '2' \ || return 1 ovs_add_flow "test_flow_set" flowset \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 info "verify initial forwarding" ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 || return 1 info "mod-flow with new actions (change to drop)" ovs_mod_flow "test_flow_set" flowset "$fwd_flow" 'drop' \ || return 1 info "verify traffic is now dropped" ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 >/dev/null 2>&1 \ && { info "FAIL: ping should fail after mod-flow to drop" return 1; } info "mod-flow without actions" ovs_mod_flow "test_flow_set" flowset "$fwd_flow" || return 1 info "verify flow retained drop action via dump" python3 "$ovs_base/ovs-dpctl.py" dump-flows flowset \ | grep -q "actions:drop" || \ { info "FAIL: flow not showing drop action"; return 1; } info "verify drop actions unchanged" ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 >/dev/null 2>&1 \ && { info "FAIL: ping should still fail after no-actions set" return 1; } return 0 } test_action_set() { sbx_add "test_action_set" || return $? ovs_add_dp "test_action_set" settest || return 1 info "create namespaces" for ns in client server; do ovs_add_netns_and_veths "test_action_set" "settest" "$ns" \ "${ns:0:1}0" "${ns:0:1}1" || return 1 done ip netns exec client ip addr add 10.0.0.1/24 dev c1 ip netns exec client ip link set c1 up ip netns exec server ip addr add 10.0.0.2/24 dev s1 ip netns exec server ip link set s1 up ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 info "verify connectivity without SET" ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 || return 1 ovs_del_flows "test_action_set" settest ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 info "set ipv4 dst to unreachable address" ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'set(ipv4(dst=10.0.0.99)),2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 info "verify ping fails with rewritten dst" ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 >/dev/null 2>&1 \ && { info "FAIL: ping should fail with dst rewritten" return 1; } ovs_del_flows "test_action_set" settest ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1 ovs_add_flow "test_action_set" settest \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 info "verify connectivity restored without SET" ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \ 10.0.0.2 || return 1 return 0 } # trunc test # - trunc(14): truncate to ETH_HLEN, strips IP payload, ping fails # - trunc(1) and trunc(13): kernel rejects below ETH_HLEN (EINVAL) # - restore normal forwarding and verify recovery test_trunc() { sbx_add "test_trunc" || return $? ovs_add_dp "test_trunc" trunctest || return 1 info "create namespaces" for ns in client server; do ovs_add_netns_and_veths "test_trunc" "trunctest" \ "$ns" "${ns:0:1}0" "${ns:0:1}1" || return 1 done ip netns exec client ip addr add 10.0.0.1/24 dev c1 ip netns exec client ip link set c1 up ip netns exec server ip addr add 10.0.0.2/24 dev s1 ip netns exec server ip link set s1 up ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_trunc" trunctest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ '2' || return 1 ovs_add_flow "test_trunc" trunctest \ 'in_port(2),eth(),eth_type(0x0800),ipv4()' \ '1' || return 1 info "verify connectivity without truncation" ovs_sbx "test_trunc" ip netns exec client \ ping -c 1 -W 2 10.0.0.2 || return 1 # trunc below ETH_HLEN must be rejected by the kernel info "verify trunc(1) is rejected" ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'trunc(1),2' &> /dev/null \ && { info "trunc(1) should be rejected"; return 1; } info "verify trunc(13) is rejected" ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ 'trunc(13),2' &> /dev/null \ && { info "trunc(13) should be rejected"; return 1; } ovs_del_flows "test_trunc" trunctest ovs_add_flow "test_trunc" trunctest \ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 ovs_add_flow "test_trunc" trunctest \ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1