Path: blob/master/tools/testing/selftests/drivers/net/microchip/ksz9477_qos.sh
26292 views
#!/bin/bash1# SPDX-License-Identifier: GPL-2.02# Copyright (c) 2024 Pengutronix, Oleksij Rempel <[email protected]>34# The script is adopted to work with the Microchip KSZ switch driver.56ETH_FCS_LEN=478WAIT_TIME=19NUM_NETIFS=410REQUIRE_JQ="yes"11REQUIRE_MZ="yes"12STABLE_MAC_ADDRS=yes13NETIF_CREATE=no14lib_dir=$(dirname $0)/../../../net/forwarding15source $lib_dir/tc_common.sh16source $lib_dir/lib.sh1718require_command dcb1920h1=${NETIFS[p1]}21swp1=${NETIFS[p2]}22swp2=${NETIFS[p3]}23h2=${NETIFS[p4]}2425H1_IPV4="192.0.2.1"26H2_IPV4="192.0.2.2"27H1_IPV6="2001:db8:1::1"28H2_IPV6="2001:db8:1::2"2930# On h1_ and h2_create do not set IP addresses to avoid interaction with the31# system, to keep packet counters clean.32h1_create()33{34simple_if_init $h135sysctl_set net.ipv6.conf.${h1}.disable_ipv6 136# Get the MAC address of the interface to use it with mausezahn37h1_mac=$(ip -j link show dev ${h1} | jq -e '.[].address')38}3940h1_destroy()41{42sysctl_restore net.ipv6.conf.${h1}.disable_ipv643simple_if_fini $h144}4546h2_create()47{48simple_if_init $h249sysctl_set net.ipv6.conf.${h2}.disable_ipv6 150h2_mac=$(ip -j link show dev ${h2} | jq -e '.[].address')51}5253h2_destroy()54{55sysctl_restore net.ipv6.conf.${h2}.disable_ipv656simple_if_fini $h257}5859switch_create()60{61ip link set ${swp1} up62ip link set ${swp2} up63sysctl_set net.ipv6.conf.${swp1}.disable_ipv6 164sysctl_set net.ipv6.conf.${swp2}.disable_ipv6 16566# Ports should trust VLAN PCP even with vlan_filtering=067ip link add br0 type bridge68ip link set ${swp1} master br069ip link set ${swp2} master br070ip link set br0 up71sysctl_set net.ipv6.conf.br0.disable_ipv6 172}7374switch_destroy()75{76sysctl_restore net.ipv6.conf.${swp2}.disable_ipv677sysctl_restore net.ipv6.conf.${swp1}.disable_ipv67879ip link del br080}8182setup_prepare()83{84vrf_prepare8586h1_create87h2_create88switch_create89}9091cleanup()92{93pre_cleanup9495h2_destroy96h1_destroy97switch_destroy9899vrf_cleanup100}101102set_apptrust_order()103{104local if_name=$1105local order=$2106107dcb apptrust set dev ${if_name} order ${order}108}109110# Function to extract a specified field from a given JSON stats string111extract_network_stat() {112local stats_json=$1113local field_name=$2114115echo $(echo "$stats_json" | jq -r "$field_name")116}117118run_test()119{120local test_name=$1;121local apptrust_order=$2;122local port_prio=$3;123local dscp_ipv=$4;124local dscp=$5;125local have_vlan=$6;126local pcp_ipv=$7;127local vlan_pcp=$8;128local ip_v6=$9129130local rx_ipv131local tx_ipv132133RET=0134135# Send some packet to populate the switch MAC table136$MZ ${h2} -a ${h2_mac} -b ${h1_mac} -p 64 -t icmp echores -c 1137138# Based on the apptrust order, set the expected Internal Priority values139# for the RX and TX paths.140if [ "${apptrust_order}" == "" ]; then141echo "Apptrust order not set."142rx_ipv=${port_prio}143tx_ipv=${port_prio}144elif [ "${apptrust_order}" == "dscp" ]; then145echo "Apptrust order is DSCP."146rx_ipv=${dscp_ipv}147tx_ipv=${dscp_ipv}148elif [ "${apptrust_order}" == "pcp" ]; then149echo "Apptrust order is PCP."150rx_ipv=${pcp_ipv}151tx_ipv=${pcp_ipv}152elif [ "${apptrust_order}" == "pcp dscp" ]; then153echo "Apptrust order is PCP DSCP."154if [ ${have_vlan} -eq 1 ]; then155rx_ipv=$((dscp_ipv > pcp_ipv ? dscp_ipv : pcp_ipv))156tx_ipv=${pcp_ipv}157else158rx_ipv=${dscp_ipv}159tx_ipv=${dscp_ipv}160fi161else162RET=1163echo "Error: Unknown apptrust order ${apptrust_order}"164log_test "${test_name}"165return166fi167168# Most/all? of the KSZ switches do not provide per-TC counters. There169# are only tx_hi and rx_hi counters, which are used to count packets170# which are considered as high priority and most likely not assigned171# to the queue 0.172# On the ingress path, packets seem to get high priority status173# independently of the DSCP or PCP global mapping. On the egress path,174# the high priority status is assigned based on the DSCP or PCP global175# map configuration.176# The thresholds for the high priority status are not documented, but177# it seems that the switch considers packets as high priority on the178# ingress path if detected Internal Priority is greater than 0. On the179# egress path, the switch considers packets as high priority if180# detected Internal Priority is greater than 1.181if [ ${rx_ipv} -ge 1 ]; then182local expect_rx_high_prio=1183else184local expect_rx_high_prio=0185fi186187if [ ${tx_ipv} -ge 2 ]; then188local expect_tx_high_prio=1189else190local expect_tx_high_prio=0191fi192193# Use ip tool to get the current switch packet counters. ethool stats194# need to be recalculated to get the correct values.195local swp1_stats=$(ip -s -j link show dev ${swp1})196local swp2_stats=$(ip -s -j link show dev ${swp2})197local swp1_rx_packets_before=$(extract_network_stat "$swp1_stats" \198'.[0].stats64.rx.packets')199local swp1_rx_bytes_before=$(extract_network_stat "$swp1_stats" \200'.[0].stats64.rx.bytes')201local swp2_tx_packets_before=$(extract_network_stat "$swp2_stats" \202'.[0].stats64.tx.packets')203local swp2_tx_bytes_before=$(extract_network_stat "$swp2_stats" \204'.[0].stats64.tx.bytes')205local swp1_rx_hi_before=$(ethtool_stats_get ${swp1} "rx_hi")206local swp2_tx_hi_before=$(ethtool_stats_get ${swp2} "tx_hi")207208# Assamble the mausezahn command based on the test parameters209# For the testis with ipv4 or ipv6, use icmp response packets,210# to avoid interaction with the system, to keep packet counters211# clean.212if [ ${ip_v6} -eq 0 ]; then213local ip="-a ${h1_mac} -b ${h2_mac} -A ${H1_IPV4} \214-B ${H2_IPV4} -t icmp unreach,code=1,dscp=${dscp}"215else216local ip="-6 -a ${h1_mac} -b ${h2_mac} -A ${H1_IPV6} \217-B ${H2_IPV6} -t icmp6 type=1,code=0,dscp=${dscp}"218fi219220if [ ${have_vlan} -eq 1 ]; then221local vlan_pcp_opt="-Q ${vlan_pcp}:0"222else223local vlan_pcp_opt=""224fi225$MZ ${h1} ${ip} -c ${PING_COUNT} -d 10msec ${vlan_pcp_opt}226227# Wait until the switch packet counters are updated228sleep 6229230local swp1_stats=$(ip -s -j link show dev ${swp1})231local swp2_stats=$(ip -s -j link show dev ${swp2})232233local swp1_rx_packets_after=$(extract_network_stat "$swp1_stats" \234'.[0].stats64.rx.packets')235local swp1_rx_bytes_after=$(extract_network_stat "$swp1_stats" \236'.[0].stats64.rx.bytes')237local swp2_tx_packets_after=$(extract_network_stat "$swp2_stats" \238'.[0].stats64.tx.packets')239local swp2_tx_bytes_after=$(extract_network_stat "$swp2_stats" \240'.[0].stats64.tx.bytes')241242local swp1_rx_packets_diff=$((${swp1_rx_packets_after} - \243${swp1_rx_packets_before}))244local swp2_tx_packets_diff=$((${swp2_tx_packets_after} - \245${swp2_tx_packets_before}))246247local swp1_rx_hi_after=$(ethtool_stats_get ${swp1} "rx_hi")248local swp2_tx_hi_after=$(ethtool_stats_get ${swp2} "tx_hi")249250# Test if any packets were received on swp1, we will rx before and after251if [ ${swp1_rx_packets_diff} -lt ${PING_COUNT} ]; then252echo "Not expected amount of received packets on ${swp1}"253echo "before ${swp1_rx_packets_before} after ${swp1_rx_packets_after}"254RET=1255fi256257# Test if any packets were transmitted on swp2, we will tx before and after258if [ ${swp2_tx_packets_diff} -lt ${PING_COUNT} ]; then259echo "Not expected amount of transmitted packets on ${swp2}"260echo "before ${swp2_tx_packets_before} after ${swp2_tx_packets_after}"261RET=1262fi263264# tx/rx_hi counted in bytes. So, we need to compare the difference in bytes265local swp1_rx_bytes_diff=$(($swp1_rx_bytes_after - $swp1_rx_bytes_before))266local swp2_tx_bytes_diff=$(($swp2_tx_bytes_after - $swp2_tx_bytes_before))267local swp1_rx_hi_diff=$(($swp1_rx_hi_after - $swp1_rx_hi_before))268local swp2_tx_hi_diff=$(($swp2_tx_hi_after - $swp2_tx_hi_before))269270if [ ${expect_rx_high_prio} -eq 1 ]; then271swp1_rx_hi_diff=$((${swp1_rx_hi_diff} - \272${swp1_rx_packets_diff} * ${ETH_FCS_LEN}))273if [ ${swp1_rx_hi_diff} -ne ${swp1_rx_bytes_diff} ]; then274echo "Not expected amount of high priority packets received on ${swp1}"275echo "RX hi diff: ${swp1_rx_hi_diff}, expected RX bytes diff: ${swp1_rx_bytes_diff}"276RET=1277fi278else279if [ ${swp1_rx_hi_diff} -ne 0 ]; then280echo "Unexpected amount of high priority packets received on ${swp1}"281echo "RX hi diff: ${swp1_rx_hi_diff}, expected 0"282RET=1283fi284fi285286if [ ${expect_tx_high_prio} -eq 1 ]; then287swp2_tx_hi_diff=$((${swp2_tx_hi_diff} - \288${swp2_tx_packets_diff} * ${ETH_FCS_LEN}))289if [ ${swp2_tx_hi_diff} -ne ${swp2_tx_bytes_diff} ]; then290echo "Not expected amount of high priority packets transmitted on ${swp2}"291echo "TX hi diff: ${swp2_tx_hi_diff}, expected TX bytes diff: ${swp2_tx_bytes_diff}"292RET=1293fi294else295if [ ${swp2_tx_hi_diff} -ne 0 ]; then296echo "Unexpected amount of high priority packets transmitted on ${swp2}"297echo "TX hi diff: ${swp2_tx_hi_diff}, expected 0"298RET=1299fi300fi301302log_test "${test_name}"303}304305run_test_dscp()306{307# IPv4 test308run_test "$1" "$2" "$3" "$4" "$5" 0 0 0 0309# IPv6 test310run_test "$1" "$2" "$3" "$4" "$5" 0 0 0 1311}312313run_test_dscp_pcp()314{315# IPv4 test316run_test "$1" "$2" "$3" "$4" "$5" 1 "$6" "$7" 0317# IPv6 test318run_test "$1" "$2" "$3" "$4" "$5" 1 "$6" "$7" 1319}320321port_default_prio_get()322{323local if_name=$1324local prio325326prio="$(dcb -j app show dev ${if_name} default-prio | \327jq '.default_prio[]')"328if [ -z "${prio}" ]; then329prio=0330fi331332echo ${prio}333}334335test_port_default()336{337local orig_apptrust=$(port_get_default_apptrust ${swp1})338local orig_prio=$(port_default_prio_get ${swp1})339local apptrust_order=""340341RET=0342343# Make sure no other priority sources will interfere with the test344set_apptrust_order ${swp1} "${apptrust_order}"345346for val in $(seq 0 7); do347dcb app replace dev ${swp1} default-prio ${val}348if [ $val -ne $(port_default_prio_get ${swp1}) ]; then349RET=1350break351fi352353run_test_dscp "Port-default QoS classification, prio: ${val}" \354"${apptrust_order}" ${val} 0 0355done356357set_apptrust_order ${swp1} "${orig_apptrust}"358if [[ "$orig_apptrust" != "$(port_get_default_apptrust ${swp1})" ]]; then359RET=1360fi361362dcb app replace dev ${swp1} default-prio ${orig_prio}363if [ $orig_prio -ne $(port_default_prio_get ${swp1}) ]; then364RET=1365fi366367log_test "Port-default QoS classification"368}369370port_get_default_apptrust()371{372local if_name=$1373374dcb -j apptrust show dev ${if_name} | jq -r '.order[]' | \375tr '\n' ' ' | xargs376}377378test_port_apptrust()379{380local original_dscp_prios_swp1=$(get_dscp_prios ${swp1})381local orig_apptrust=$(port_get_default_apptrust ${swp1})382local orig_port_prio=$(port_default_prio_get ${swp1})383local order_variants=("pcp dscp" "dscp" "pcp")384local apptrust_order385local port_prio386local dscp_prio387local pcp_prio388local dscp389local pcp390391RET=0392393# First, test if apptrust configuration as taken by the kernel394for order in "${order_variants[@]}"; do395set_apptrust_order ${swp1} "${order}"396if [[ "$order" != "$(port_get_default_apptrust ${swp1})" ]]; then397RET=1398break399fi400done401402log_test "Apptrust, supported variants"403404# To test if the apptrust configuration is working as expected, we need405# to set DSCP priorities for the switch port.406init_dscp_prios "${swp1}" "${original_dscp_prios_swp1}"407408# Start with a simple test where all apptrust sources are disabled409# default port priority is 0, DSCP priority is mapped to 7.410# No high priority packets should be received or transmitted.411port_prio=0412dscp_prio=7413dscp=4414415dcb app replace dev ${swp1} default-prio ${port_prio}416dcb app replace dev ${swp1} dscp-prio ${dscp}:${dscp_prio}417418apptrust_order=""419set_apptrust_order ${swp1} "${apptrust_order}"420# Test with apptrust sources disabled, Packets should get port default421# priority which is 0422run_test_dscp "Apptrust, all disabled. DSCP-prio ${dscp}:${dscp_prio}" \423"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}424425apptrust_order="pcp"426set_apptrust_order ${swp1} "${apptrust_order}"427# If PCP is enabled, packets should get PCP priority, which is not428# set in this test (no VLAN tags are present in the packet). No high429# priority packets should be received or transmitted.430run_test_dscp "Apptrust, PCP enabled. DSCP-prio ${dscp}:${dscp_prio}" \431"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}432433apptrust_order="dscp"434set_apptrust_order ${swp1} "${apptrust_order}"435# If DSCP is enabled, packets should get DSCP priority which is set to 7436# in this test. High priority packets should be received and transmitted.437run_test_dscp "Apptrust, DSCP enabled. DSCP-prio ${dscp}:${dscp_prio}" \438"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}439440apptrust_order="pcp dscp"441set_apptrust_order ${swp1} "${apptrust_order}"442# If PCP and DSCP are enabled, PCP would have higher apptrust priority443# so packets should get PCP priority. But in this test VLAN PCP is not444# set, so it should get DSCP priority which is set to 7. High priority445# packets should be received and transmitted.446run_test_dscp "Apptrust, PCP and DSCP are enabled. DSCP-prio ${dscp}:${dscp_prio}" \447"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}448449# If VLAN PCP is set, it should have higher apptrust priority than DSCP450# so packets should get VLAN PCP priority. Send packets with VLAN PCP451# set to 0, DSCP set to 7. Packets should get VLAN PCP priority.452# No high priority packets should be transmitted. Due to nature of the453# switch, high priority packets will be received.454pcp_prio=0455pcp=0456run_test_dscp_pcp "Apptrust, PCP and DSCP are enabled. PCP ${pcp_prio}, DSCP-prio ${dscp}:${dscp_prio}" \457"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp} ${pcp_prio} ${pcp}458459# If VLAN PCP is set to 7, it should have higher apptrust priority than460# DSCP so packets should get VLAN PCP priority. Send packets with VLAN461# PCP set to 7, DSCP set to 7. Packets should get VLAN PCP priority.462# High priority packets should be received and transmitted.463pcp_prio=7464pcp=7465run_test_dscp_pcp "Apptrust, PCP and DSCP are enabled. PCP ${pcp_prio}, DSCP-prio ${dscp}:${dscp_prio}" \466"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp} ${pcp_prio} ${pcp}467# Now make sure that the switch is able to handle the case where DSCP468# priority is set to 0 and PCP priority is set to 7. Packets should get469# PCP priority. High priority packets should be received and transmitted.470dscp_prio=0471dcb app replace dev ${swp1} dscp-prio ${dscp}:${dscp_prio}472run_test_dscp_pcp "Apptrust, PCP and DSCP are enabled. PCP ${pcp_prio}, DSCP-prio ${dscp}:${dscp_prio}" \473"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp} ${pcp_prio} ${pcp}474# If both VLAN PCP and DSCP are set to 0, packets should get 0 priority.475# No high priority packets should be received or transmitted.476pcp_prio=0477pcp=0478run_test_dscp_pcp "Apptrust, PCP and DSCP are enabled. PCP ${pcp_prio}, DSCP-prio ${dscp}:${dscp_prio}" \479"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp} ${pcp_prio} ${pcp}480481# Restore original priorities482if ! restore_priorities "${swp1}" "${original_dscp_prios_swp1}"; then483RET=1484fi485486set_apptrust_order ${swp1} "${orig_apptrust}"487if [ "$orig_apptrust" != "$(port_get_default_apptrust ${swp1})" ]; then488RET=1489fi490491dcb app replace dev ${swp1} default-prio ${orig_port_prio}492if [ $orig_port_prio -ne $(port_default_prio_get ${swp1}) ]; then493RET=1494fi495496log_test "Apptrust, restore original settings"497}498499# Function to get current DSCP priorities500get_dscp_prios() {501local if_name=$1502dcb -j app show dev ${if_name} | jq -c '.dscp_prio'503}504505# Function to set a specific DSCP priority on a device506replace_dscp_prio() {507local if_name=$1508local dscp=$2509local prio=$3510dcb app replace dev ${if_name} dscp-prio ${dscp}:${prio}511}512513# Function to compare DSCP maps514compare_dscp_maps() {515local old_json=$1516local new_json=$2517local dscp=$3518local prio=$4519520# Create a modified old_json with the expected change for comparison521local modified_old_json=$(echo "$old_json" |522jq --argjson dscp $dscp --argjson prio $prio \523'map(if .[0] == $dscp then [$dscp, $prio] else . end)' |524tr -d " \n")525526# Compare new_json with the modified_old_json527if [[ "$modified_old_json" == "$new_json" ]]; then528return 0529else530return 1531fi532}533534# Function to set DSCP priorities535set_and_verify_dscp() {536local port=$1537local dscp=$2538local new_prio=$3539540local old_prios=$(get_dscp_prios $port)541542replace_dscp_prio "$port" $dscp $new_prio543544# Fetch current settings and compare545local current_prios=$(get_dscp_prios $port)546if ! compare_dscp_maps "$old_prios" "$current_prios" $dscp $new_prio; then547echo "Error: Unintended changes detected in DSCP map for $port after setting DSCP $dscp to $new_prio."548return 1549fi550return 0551}552553# Function to restore original priorities554restore_priorities() {555local port=$1556local original_prios=$2557558echo "Removing test artifacts for $port"559local current_prios=$(get_dscp_prios $port)560local prio_str=$(echo "$current_prios" |561jq -r 'map("\(.[0]):\(.[1])") | join(" ")')562dcb app del dev $port dscp-prio $prio_str563564echo "Restoring original DSCP priorities for $port"565local restore_str=$(echo "$original_prios" |566jq -r 'map("\(.[0]):\(.[1])") | join(" ")')567dcb app add dev $port dscp-prio $restore_str568569local current_prios=$(get_dscp_prios $port)570if [[ "$original_prios" != "$current_prios" ]]; then571echo "Error: Failed to restore original DSCP priorities for $port"572return 1573fi574return 0575}576577# Initialize DSCP priorities. Set them to predictable values for testing.578init_dscp_prios() {579local port=$1580local original_prios=$2581582echo "Removing any existing DSCP priority mappins for $port"583local prio_str=$(echo "$original_prios" |584jq -r 'map("\(.[0]):\(.[1])") | join(" ")')585dcb app del dev $port dscp-prio $prio_str586587# Initialize DSCP priorities list588local dscp_prios=""589for dscp in {0..63}; do590dscp_prios+=("$dscp:0")591done592593echo "Setting initial DSCP priorities map to 0 for $port"594dcb app add dev $port dscp-prio ${dscp_prios[@]}595}596597# Main function to test global DSCP map across specified ports598test_global_dscp_map() {599local ports=("$swp1" "$swp2")600local original_dscp_prios_port0=$(get_dscp_prios ${ports[0]})601local orig_apptrust=$(port_get_default_apptrust ${swp1})602local orig_port_prio=$(port_default_prio_get ${swp1})603local apptrust_order="dscp"604local port_prio=0605local dscp_prio606local dscp607608RET=0609610set_apptrust_order ${swp1} "${apptrust_order}"611dcb app replace dev ${swp1} default-prio ${port_prio}612613# Initialize DSCP priorities614init_dscp_prios "${ports[0]}" "$original_dscp_prios_port0"615616# Loop over each DSCP index617for dscp in {0..63}; do618# and test each Internal Priority value619for dscp_prio in {0..7}; do620# do it for each port. This is to test if the global DSCP map621# is accessible from all ports.622for port in "${ports[@]}"; do623if ! set_and_verify_dscp "$port" $dscp $dscp_prio; then624RET=1625fi626done627628# Test if the DSCP priority is correctly applied to the packets629run_test_dscp "DSCP (${dscp}) QoS classification, prio: ${dscp_prio}" \630"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}631if [ ${RET} -eq 1 ]; then632break633fi634done635done636637# Restore original priorities638if ! restore_priorities "${ports[0]}" "${original_dscp_prios_port0}"; then639RET=1640fi641642set_apptrust_order ${swp1} "${orig_apptrust}"643if [[ "$orig_apptrust" != "$(port_get_default_apptrust ${swp1})" ]]; then644RET=1645fi646647dcb app replace dev ${swp1} default-prio ${orig_port_prio}648if [ $orig_port_prio -ne $(port_default_prio_get ${swp1}) ]; then649RET=1650fi651652log_test "DSCP global map"653}654655trap cleanup EXIT656657ALL_TESTS="658test_port_default659test_port_apptrust660test_global_dscp_map661"662663setup_prepare664setup_wait665tests_run666667exit $EXIT_STATUS668669670