| #!/bin/bash | |
| # SPDX-License-Identifier: GPL-2.0 | |
| lib_dir=$(dirname $0)/../../../net/forwarding | |
| ALL_TESTS=" | |
| l3_reporting_test | |
| l3_fail_next_test | |
| l3_counter_test | |
| l3_rollback_test | |
| l3_monitor_test | |
| " | |
| NETDEVSIM_PATH=/sys/bus/netdevsim/ | |
| DEV_ADDR_1=1337 | |
| DEV_ADDR_2=1057 | |
| DEV_ADDR_3=5417 | |
| NUM_NETIFS=0 | |
| source $lib_dir/lib.sh | |
| DUMMY_IFINDEX= | |
| DEV_ADDR() | |
| { | |
| local n=$1; shift | |
| local var=DEV_ADDR_$n | |
| echo ${!var} | |
| } | |
| DEV() | |
| { | |
| echo netdevsim$(DEV_ADDR $1) | |
| } | |
| DEVLINK_DEV() | |
| { | |
| echo netdevsim/$(DEV $1) | |
| } | |
| SYSFS_NET_DIR() | |
| { | |
| echo /sys/bus/netdevsim/devices/$(DEV $1)/net/ | |
| } | |
| DEBUGFS_DIR() | |
| { | |
| echo /sys/kernel/debug/netdevsim/$(DEV $1)/ | |
| } | |
| nsim_add() | |
| { | |
| local n=$1; shift | |
| echo "$(DEV_ADDR $n) 1" > ${NETDEVSIM_PATH}/new_device | |
| while [ ! -d $(SYSFS_NET_DIR $n) ] ; do :; done | |
| } | |
| nsim_reload() | |
| { | |
| local n=$1; shift | |
| local ns=$1; shift | |
| devlink dev reload $(DEVLINK_DEV $n) netns $ns | |
| if [ $? -ne 0 ]; then | |
| echo "Failed to reload $(DEV $n) into netns \"testns1\"" | |
| exit 1 | |
| fi | |
| } | |
| nsim_del() | |
| { | |
| local n=$1; shift | |
| echo "$(DEV_ADDR $n)" > ${NETDEVSIM_PATH}/del_device | |
| } | |
| nsim_hwstats_toggle() | |
| { | |
| local action=$1; shift | |
| local instance=$1; shift | |
| local netdev=$1; shift | |
| local type=$1; shift | |
| local ifindex=$($IP -j link show dev $netdev | jq '.[].ifindex') | |
| echo $ifindex > $(DEBUGFS_DIR $instance)/hwstats/$type/$action | |
| } | |
| nsim_hwstats_enable() | |
| { | |
| nsim_hwstats_toggle enable_ifindex "$@" | |
| } | |
| nsim_hwstats_disable() | |
| { | |
| nsim_hwstats_toggle disable_ifindex "$@" | |
| } | |
| nsim_hwstats_fail_next_enable() | |
| { | |
| nsim_hwstats_toggle fail_next_enable "$@" | |
| } | |
| setup_prepare() | |
| { | |
| modprobe netdevsim &> /dev/null | |
| nsim_add 1 | |
| nsim_add 2 | |
| nsim_add 3 | |
| ip netns add testns1 | |
| if [ $? -ne 0 ]; then | |
| echo "Failed to add netns \"testns1\"" | |
| exit 1 | |
| fi | |
| nsim_reload 1 testns1 | |
| nsim_reload 2 testns1 | |
| nsim_reload 3 testns1 | |
| IP="ip -n testns1" | |
| $IP link add name dummy1 type dummy | |
| $IP link set dev dummy1 up | |
| DUMMY_IFINDEX=$($IP -j link show dev dummy1 | jq '.[].ifindex') | |
| } | |
| cleanup() | |
| { | |
| pre_cleanup | |
| $IP link del name dummy1 | |
| ip netns del testns1 | |
| nsim_del 3 | |
| nsim_del 2 | |
| nsim_del 1 | |
| modprobe -r netdevsim &> /dev/null | |
| } | |
| netdev_hwstats_used() | |
| { | |
| local netdev=$1; shift | |
| local type=$1; shift | |
| $IP -j stats show dev "$netdev" group offload subgroup hw_stats_info | | |
| jq '.[].info.l3_stats.used' | |
| } | |
| netdev_check_used() | |
| { | |
| local netdev=$1; shift | |
| local type=$1; shift | |
| [[ $(netdev_hwstats_used $netdev $type) == "true" ]] | |
| } | |
| netdev_check_unused() | |
| { | |
| local netdev=$1; shift | |
| local type=$1; shift | |
| [[ $(netdev_hwstats_used $netdev $type) == "false" ]] | |
| } | |
| netdev_hwstats_request() | |
| { | |
| local netdev=$1; shift | |
| local type=$1; shift | |
| $IP -j stats show dev "$netdev" group offload subgroup hw_stats_info | | |
| jq ".[].info.${type}_stats.request" | |
| } | |
| netdev_check_requested() | |
| { | |
| local netdev=$1; shift | |
| local type=$1; shift | |
| [[ $(netdev_hwstats_request $netdev $type) == "true" ]] | |
| } | |
| netdev_check_unrequested() | |
| { | |
| local netdev=$1; shift | |
| local type=$1; shift | |
| [[ $(netdev_hwstats_request $netdev $type) == "false" ]] | |
| } | |
| reporting_test() | |
| { | |
| local type=$1; shift | |
| local instance=1 | |
| RET=0 | |
| [[ -n $(netdev_hwstats_used dummy1 $type) ]] | |
| check_err $? "$type stats not reported" | |
| netdev_check_unused dummy1 $type | |
| check_err $? "$type stats reported as used before either device or netdevsim request" | |
| nsim_hwstats_enable $instance dummy1 $type | |
| netdev_check_unused dummy1 $type | |
| check_err $? "$type stats reported as used before device request" | |
| netdev_check_unrequested dummy1 $type | |
| check_err $? "$type stats reported as requested before device request" | |
| $IP stats set dev dummy1 ${type}_stats on | |
| netdev_check_used dummy1 $type | |
| check_err $? "$type stats reported as not used after both device and netdevsim request" | |
| netdev_check_requested dummy1 $type | |
| check_err $? "$type stats reported as not requested after device request" | |
| nsim_hwstats_disable $instance dummy1 $type | |
| netdev_check_unused dummy1 $type | |
| check_err $? "$type stats reported as used after netdevsim request withdrawn" | |
| nsim_hwstats_enable $instance dummy1 $type | |
| netdev_check_used dummy1 $type | |
| check_err $? "$type stats reported as not used after netdevsim request reenabled" | |
| $IP stats set dev dummy1 ${type}_stats off | |
| netdev_check_unused dummy1 $type | |
| check_err $? "$type stats reported as used after device request withdrawn" | |
| netdev_check_unrequested dummy1 $type | |
| check_err $? "$type stats reported as requested after device request withdrawn" | |
| nsim_hwstats_disable $instance dummy1 $type | |
| netdev_check_unused dummy1 $type | |
| check_err $? "$type stats reported as used after both requests withdrawn" | |
| log_test "Reporting of $type stats usage" | |
| } | |
| l3_reporting_test() | |
| { | |
| reporting_test l3 | |
| } | |
| __fail_next_test() | |
| { | |
| local instance=$1; shift | |
| local type=$1; shift | |
| RET=0 | |
| netdev_check_unused dummy1 $type | |
| check_err $? "$type stats reported as used before either device or netdevsim request" | |
| nsim_hwstats_enable $instance dummy1 $type | |
| nsim_hwstats_fail_next_enable $instance dummy1 $type | |
| netdev_check_unused dummy1 $type | |
| check_err $? "$type stats reported as used before device request" | |
| netdev_check_unrequested dummy1 $type | |
| check_err $? "$type stats reported as requested before device request" | |
| $IP stats set dev dummy1 ${type}_stats on 2>/dev/null | |
| check_fail $? "$type stats request not bounced as it should have been" | |
| netdev_check_unused dummy1 $type | |
| check_err $? "$type stats reported as used after bounce" | |
| netdev_check_unrequested dummy1 $type | |
| check_err $? "$type stats reported as requested after bounce" | |
| $IP stats set dev dummy1 ${type}_stats on | |
| check_err $? "$type stats request failed when it shouldn't have" | |
| netdev_check_used dummy1 $type | |
| check_err $? "$type stats reported as not used after both device and netdevsim request" | |
| netdev_check_requested dummy1 $type | |
| check_err $? "$type stats reported as not requested after device request" | |
| $IP stats set dev dummy1 ${type}_stats off | |
| nsim_hwstats_disable $instance dummy1 $type | |
| log_test "Injected failure of $type stats enablement (netdevsim #$instance)" | |
| } | |
| fail_next_test() | |
| { | |
| __fail_next_test 1 "$@" | |
| __fail_next_test 2 "$@" | |
| __fail_next_test 3 "$@" | |
| } | |
| l3_fail_next_test() | |
| { | |
| fail_next_test l3 | |
| } | |
| get_hwstat() | |
| { | |
| local netdev=$1; shift | |
| local type=$1; shift | |
| local selector=$1; shift | |
| $IP -j stats show dev $netdev group offload subgroup ${type}_stats | | |
| jq ".[0].stats64.${selector}" | |
| } | |
| counter_test() | |
| { | |
| local type=$1; shift | |
| local instance=1 | |
| RET=0 | |
| nsim_hwstats_enable $instance dummy1 $type | |
| $IP stats set dev dummy1 ${type}_stats on | |
| netdev_check_used dummy1 $type | |
| check_err $? "$type stats reported as not used after both device and netdevsim request" | |
| # Netdevsim counts 10pps on ingress. We should see maybe a couple | |
| # packets, unless things take a reeealy long time. | |
| local pkts=$(get_hwstat dummy1 l3 rx.packets) | |
| ((pkts < 10)) | |
| check_err $? "$type stats show >= 10 packets after first enablement" | |
| sleep 2.5 | |
| local pkts=$(get_hwstat dummy1 l3 rx.packets) | |
| ((pkts >= 20)) | |
| check_err $? "$type stats show < 20 packets after 2.5s passed" | |
| $IP stats set dev dummy1 ${type}_stats off | |
| sleep 2 | |
| $IP stats set dev dummy1 ${type}_stats on | |
| local pkts=$(get_hwstat dummy1 l3 rx.packets) | |
| ((pkts < 10)) | |
| check_err $? "$type stats show >= 10 packets after second enablement" | |
| $IP stats set dev dummy1 ${type}_stats off | |
| nsim_hwstats_fail_next_enable $instance dummy1 $type | |
| $IP stats set dev dummy1 ${type}_stats on 2>/dev/null | |
| check_fail $? "$type stats request not bounced as it should have been" | |
| sleep 2 | |
| $IP stats set dev dummy1 ${type}_stats on | |
| local pkts=$(get_hwstat dummy1 l3 rx.packets) | |
| ((pkts < 10)) | |
| check_err $? "$type stats show >= 10 packets after post-fail enablement" | |
| $IP stats set dev dummy1 ${type}_stats off | |
| log_test "Counter values in $type stats" | |
| } | |
| l3_counter_test() | |
| { | |
| counter_test l3 | |
| } | |
| rollback_test() | |
| { | |
| local type=$1; shift | |
| RET=0 | |
| nsim_hwstats_enable 1 dummy1 l3 | |
| nsim_hwstats_enable 2 dummy1 l3 | |
| nsim_hwstats_enable 3 dummy1 l3 | |
| # The three netdevsim instances are registered in order of their number | |
| # one after another. It is reasonable to expect that whatever | |
| # notifications take place hit no. 2 in between hitting nos. 1 and 3, | |
| # whatever the actual order. This allows us to test that a fail caused | |
| # by no. 2 does not leave the system in a partial state, and rolls | |
| # everything back. | |
| nsim_hwstats_fail_next_enable 2 dummy1 l3 | |
| $IP stats set dev dummy1 ${type}_stats on 2>/dev/null | |
| check_fail $? "$type stats request not bounced as it should have been" | |
| netdev_check_unused dummy1 $type | |
| check_err $? "$type stats reported as used after bounce" | |
| netdev_check_unrequested dummy1 $type | |
| check_err $? "$type stats reported as requested after bounce" | |
| sleep 2 | |
| $IP stats set dev dummy1 ${type}_stats on | |
| check_err $? "$type stats request not upheld as it should have been" | |
| local pkts=$(get_hwstat dummy1 l3 rx.packets) | |
| ((pkts < 10)) | |
| check_err $? "$type stats show $pkts packets after post-fail enablement" | |
| $IP stats set dev dummy1 ${type}_stats off | |
| nsim_hwstats_disable 3 dummy1 l3 | |
| nsim_hwstats_disable 2 dummy1 l3 | |
| nsim_hwstats_disable 1 dummy1 l3 | |
| log_test "Failure in $type stats enablement rolled back" | |
| } | |
| l3_rollback_test() | |
| { | |
| rollback_test l3 | |
| } | |
| l3_monitor_test() | |
| { | |
| hw_stats_monitor_test dummy1 l3 \ | |
| "nsim_hwstats_enable 1 dummy1 l3" \ | |
| "nsim_hwstats_disable 1 dummy1 l3" \ | |
| "$IP" | |
| } | |
| trap cleanup EXIT | |
| setup_prepare | |
| tests_run | |
| exit $EXIT_STATUS |