162306a36Sopenharmony_ci#!/bin/bash 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 362306a36Sopenharmony_ci# Copyright 2021-2022 NXP 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci# Note: On LS1028A, in lack of enough user ports, this setup requires patching 662306a36Sopenharmony_ci# the device tree to use the second CPU port as a user port 762306a36Sopenharmony_ci 862306a36Sopenharmony_ciWAIT_TIME=1 962306a36Sopenharmony_ciNUM_NETIFS=4 1062306a36Sopenharmony_ciSTABLE_MAC_ADDRS=yes 1162306a36Sopenharmony_ciNETIF_CREATE=no 1262306a36Sopenharmony_cilib_dir=$(dirname $0)/../../../net/forwarding 1362306a36Sopenharmony_cisource $lib_dir/tc_common.sh 1462306a36Sopenharmony_cisource $lib_dir/lib.sh 1562306a36Sopenharmony_cisource $lib_dir/tsn_lib.sh 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciUDS_ADDRESS_H1="/var/run/ptp4l_h1" 1862306a36Sopenharmony_ciUDS_ADDRESS_SWP1="/var/run/ptp4l_swp1" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci# Tunables 2162306a36Sopenharmony_ciNUM_PKTS=1000 2262306a36Sopenharmony_ciSTREAM_VID=100 2362306a36Sopenharmony_ciSTREAM_PRIO=6 2462306a36Sopenharmony_ci# Use a conservative cycle of 10 ms to allow the test to still pass when the 2562306a36Sopenharmony_ci# kernel has some extra overhead like lockdep etc 2662306a36Sopenharmony_ciCYCLE_TIME_NS=10000000 2762306a36Sopenharmony_ci# Create two Gate Control List entries, one OPEN and one CLOSE, of equal 2862306a36Sopenharmony_ci# durations 2962306a36Sopenharmony_ciGATE_DURATION_NS=$((${CYCLE_TIME_NS} / 2)) 3062306a36Sopenharmony_ci# Give 2/3 of the cycle time to user space and 1/3 to the kernel 3162306a36Sopenharmony_ciFUDGE_FACTOR=$((${CYCLE_TIME_NS} / 3)) 3262306a36Sopenharmony_ci# Shift the isochron base time by half the gate time, so that packets are 3362306a36Sopenharmony_ci# always received by swp1 close to the middle of the time slot, to minimize 3462306a36Sopenharmony_ci# inaccuracies due to network sync 3562306a36Sopenharmony_ciSHIFT_TIME_NS=$((${GATE_DURATION_NS} / 2)) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cih1=${NETIFS[p1]} 3862306a36Sopenharmony_ciswp1=${NETIFS[p2]} 3962306a36Sopenharmony_ciswp2=${NETIFS[p3]} 4062306a36Sopenharmony_cih2=${NETIFS[p4]} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciH1_IPV4="192.0.2.1" 4362306a36Sopenharmony_ciH2_IPV4="192.0.2.2" 4462306a36Sopenharmony_ciH1_IPV6="2001:db8:1::1" 4562306a36Sopenharmony_ciH2_IPV6="2001:db8:1::2" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci# Chain number exported by the ocelot driver for 4862306a36Sopenharmony_ci# Per-Stream Filtering and Policing filters 4962306a36Sopenharmony_ciPSFP() 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci echo 30000 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cipsfp_chain_create() 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci local if_name=$1 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci tc qdisc add dev $if_name clsact 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci tc filter add dev $if_name ingress chain 0 pref 49152 flower \ 6162306a36Sopenharmony_ci skip_sw action goto chain $(PSFP) 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cipsfp_chain_destroy() 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci local if_name=$1 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci tc qdisc del dev $if_name clsact 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cipsfp_filter_check() 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci local expected=$1 7462306a36Sopenharmony_ci local packets="" 7562306a36Sopenharmony_ci local drops="" 7662306a36Sopenharmony_ci local stats="" 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci stats=$(tc -j -s filter show dev ${swp1} ingress chain $(PSFP) pref 1) 7962306a36Sopenharmony_ci packets=$(echo ${stats} | jq ".[1].options.actions[].stats.packets") 8062306a36Sopenharmony_ci drops=$(echo ${stats} | jq ".[1].options.actions[].stats.drops") 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if ! [ "${packets}" = "${expected}" ]; then 8362306a36Sopenharmony_ci printf "Expected filter to match on %d packets but matched on %d instead\n" \ 8462306a36Sopenharmony_ci "${expected}" "${packets}" 8562306a36Sopenharmony_ci fi 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci echo "Hardware filter reports ${drops} drops" 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cih1_create() 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci simple_if_init $h1 $H1_IPV4/24 $H1_IPV6/64 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cih1_destroy() 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci simple_if_fini $h1 $H1_IPV4/24 $H1_IPV6/64 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cih2_create() 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci simple_if_init $h2 $H2_IPV4/24 $H2_IPV6/64 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cih2_destroy() 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci simple_if_fini $h2 $H2_IPV4/24 $H2_IPV6/64 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ciswitch_create() 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci local h2_mac_addr=$(mac_get $h2) 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ip link set ${swp1} up 11562306a36Sopenharmony_ci ip link set ${swp2} up 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ip link add br0 type bridge vlan_filtering 1 11862306a36Sopenharmony_ci ip link set ${swp1} master br0 11962306a36Sopenharmony_ci ip link set ${swp2} master br0 12062306a36Sopenharmony_ci ip link set br0 up 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci bridge vlan add dev ${swp2} vid ${STREAM_VID} 12362306a36Sopenharmony_ci bridge vlan add dev ${swp1} vid ${STREAM_VID} 12462306a36Sopenharmony_ci # PSFP on Ocelot requires the filter to also be added to the bridge 12562306a36Sopenharmony_ci # FDB, and not be removed 12662306a36Sopenharmony_ci bridge fdb add dev ${swp2} \ 12762306a36Sopenharmony_ci ${h2_mac_addr} vlan ${STREAM_VID} static master 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci psfp_chain_create ${swp1} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci tc filter add dev ${swp1} ingress chain $(PSFP) pref 1 \ 13262306a36Sopenharmony_ci protocol 802.1Q flower skip_sw \ 13362306a36Sopenharmony_ci dst_mac ${h2_mac_addr} vlan_id ${STREAM_VID} \ 13462306a36Sopenharmony_ci action gate base-time 0.000000000 \ 13562306a36Sopenharmony_ci sched-entry OPEN ${GATE_DURATION_NS} -1 -1 \ 13662306a36Sopenharmony_ci sched-entry CLOSE ${GATE_DURATION_NS} -1 -1 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ciswitch_destroy() 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci psfp_chain_destroy ${swp1} 14262306a36Sopenharmony_ci ip link del br0 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_citxtime_setup() 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci local if_name=$1 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci tc qdisc add dev ${if_name} clsact 15062306a36Sopenharmony_ci # Classify PTP on TC 7 and isochron on TC 6 15162306a36Sopenharmony_ci tc filter add dev ${if_name} egress protocol 0x88f7 \ 15262306a36Sopenharmony_ci flower action skbedit priority 7 15362306a36Sopenharmony_ci tc filter add dev ${if_name} egress protocol 802.1Q \ 15462306a36Sopenharmony_ci flower vlan_ethtype 0xdead action skbedit priority 6 15562306a36Sopenharmony_ci tc qdisc add dev ${if_name} handle 100: parent root mqprio num_tc 8 \ 15662306a36Sopenharmony_ci queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ 15762306a36Sopenharmony_ci map 0 1 2 3 4 5 6 7 \ 15862306a36Sopenharmony_ci hw 1 15962306a36Sopenharmony_ci # Set up TC 6 for SO_TXTIME. tc-mqprio queues count from 1. 16062306a36Sopenharmony_ci tc qdisc replace dev ${if_name} parent 100:$((${STREAM_PRIO} + 1)) etf \ 16162306a36Sopenharmony_ci clockid CLOCK_TAI offload delta ${FUDGE_FACTOR} 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_citxtime_cleanup() 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci local if_name=$1 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci tc qdisc del dev ${if_name} root 16962306a36Sopenharmony_ci tc qdisc del dev ${if_name} clsact 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cisetup_prepare() 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci vrf_prepare 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci h1_create 17762306a36Sopenharmony_ci h2_create 17862306a36Sopenharmony_ci switch_create 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci txtime_setup ${h1} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci # Set up swp1 as a master PHC for h1, synchronized to the local 18362306a36Sopenharmony_ci # CLOCK_REALTIME. 18462306a36Sopenharmony_ci phc2sys_start ${UDS_ADDRESS_SWP1} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci # Assumption true for LS1028A: h1 and h2 use the same PHC. So by 18762306a36Sopenharmony_ci # synchronizing h1 to swp1 via PTP, h2 is also implicitly synchronized 18862306a36Sopenharmony_ci # to swp1 (and both to CLOCK_REALTIME). 18962306a36Sopenharmony_ci ptp4l_start ${h1} true ${UDS_ADDRESS_H1} 19062306a36Sopenharmony_ci ptp4l_start ${swp1} false ${UDS_ADDRESS_SWP1} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci # Make sure there are no filter matches at the beginning of the test 19362306a36Sopenharmony_ci psfp_filter_check 0 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cicleanup() 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci pre_cleanup 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ptp4l_stop ${swp1} 20162306a36Sopenharmony_ci ptp4l_stop ${h1} 20262306a36Sopenharmony_ci phc2sys_stop 20362306a36Sopenharmony_ci isochron_recv_stop 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci txtime_cleanup ${h1} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci h2_destroy 20862306a36Sopenharmony_ci h1_destroy 20962306a36Sopenharmony_ci switch_destroy 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci vrf_cleanup 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cidebug_incorrectly_dropped_packets() 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci local isochron_dat=$1 21762306a36Sopenharmony_ci local dropped_seqids 21862306a36Sopenharmony_ci local seqid 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci echo "Packets incorrectly dropped:" 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci dropped_seqids=$(isochron report \ 22362306a36Sopenharmony_ci --input-file "${isochron_dat}" \ 22462306a36Sopenharmony_ci --printf-format "%u RX hw %T\n" \ 22562306a36Sopenharmony_ci --printf-args "qR" | \ 22662306a36Sopenharmony_ci grep 'RX hw 0.000000000' | \ 22762306a36Sopenharmony_ci awk '{print $1}') 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci for seqid in ${dropped_seqids}; do 23062306a36Sopenharmony_ci isochron report \ 23162306a36Sopenharmony_ci --input-file "${isochron_dat}" \ 23262306a36Sopenharmony_ci --start ${seqid} --stop ${seqid} \ 23362306a36Sopenharmony_ci --printf-format "seqid %u scheduled for %T, HW TX timestamp %T\n" \ 23462306a36Sopenharmony_ci --printf-args "qST" 23562306a36Sopenharmony_ci done 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cidebug_incorrectly_received_packets() 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci local isochron_dat=$1 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci echo "Packets incorrectly received:" 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci isochron report \ 24562306a36Sopenharmony_ci --input-file "${isochron_dat}" \ 24662306a36Sopenharmony_ci --printf-format "seqid %u scheduled for %T, HW TX timestamp %T, HW RX timestamp %T\n" \ 24762306a36Sopenharmony_ci --printf-args "qSTR" | 24862306a36Sopenharmony_ci grep -v 'HW RX timestamp 0.000000000' 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cirun_test() 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci local base_time=$1 25462306a36Sopenharmony_ci local expected=$2 25562306a36Sopenharmony_ci local test_name=$3 25662306a36Sopenharmony_ci local debug=$4 25762306a36Sopenharmony_ci local isochron_dat="$(mktemp)" 25862306a36Sopenharmony_ci local extra_args="" 25962306a36Sopenharmony_ci local received 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci isochron_do \ 26262306a36Sopenharmony_ci "${h1}" \ 26362306a36Sopenharmony_ci "${h2}" \ 26462306a36Sopenharmony_ci "${UDS_ADDRESS_H1}" \ 26562306a36Sopenharmony_ci "" \ 26662306a36Sopenharmony_ci "${base_time}" \ 26762306a36Sopenharmony_ci "${CYCLE_TIME_NS}" \ 26862306a36Sopenharmony_ci "${SHIFT_TIME_NS}" \ 26962306a36Sopenharmony_ci "${NUM_PKTS}" \ 27062306a36Sopenharmony_ci "${STREAM_VID}" \ 27162306a36Sopenharmony_ci "${STREAM_PRIO}" \ 27262306a36Sopenharmony_ci "" \ 27362306a36Sopenharmony_ci "${isochron_dat}" 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci # Count all received packets by looking at the non-zero RX timestamps 27662306a36Sopenharmony_ci received=$(isochron report \ 27762306a36Sopenharmony_ci --input-file "${isochron_dat}" \ 27862306a36Sopenharmony_ci --printf-format "%u\n" --printf-args "R" | \ 27962306a36Sopenharmony_ci grep -w -v '0' | wc -l) 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if [ "${received}" = "${expected}" ]; then 28262306a36Sopenharmony_ci RET=0 28362306a36Sopenharmony_ci else 28462306a36Sopenharmony_ci RET=1 28562306a36Sopenharmony_ci echo "Expected isochron to receive ${expected} packets but received ${received}" 28662306a36Sopenharmony_ci fi 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci log_test "${test_name}" 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if [ "$RET" = "1" ]; then 29162306a36Sopenharmony_ci ${debug} "${isochron_dat}" 29262306a36Sopenharmony_ci fi 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci rm ${isochron_dat} 2> /dev/null 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_citest_gate_in_band() 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci # Send packets in-band with the OPEN gate entry 30062306a36Sopenharmony_ci run_test 0.000000000 ${NUM_PKTS} "In band" \ 30162306a36Sopenharmony_ci debug_incorrectly_dropped_packets 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci psfp_filter_check ${NUM_PKTS} 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_citest_gate_out_of_band() 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci # Send packets in-band with the CLOSE gate entry 30962306a36Sopenharmony_ci run_test 0.005000000 0 "Out of band" \ 31062306a36Sopenharmony_ci debug_incorrectly_received_packets 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci psfp_filter_check $((2 * ${NUM_PKTS})) 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_citrap cleanup EXIT 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ciALL_TESTS=" 31862306a36Sopenharmony_ci test_gate_in_band 31962306a36Sopenharmony_ci test_gate_out_of_band 32062306a36Sopenharmony_ci" 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cisetup_prepare 32362306a36Sopenharmony_cisetup_wait 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_citests_run 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ciexit $EXIT_STATUS 328