328 lines · bash
1#!/bin/bash2# SPDX-License-Identifier: GPL-2.03# Copyright 2021-2022 NXP4 5# Note: On LS1028A, in lack of enough user ports, this setup requires patching6# the device tree to use the second CPU port as a user port7 8WAIT_TIME=19NUM_NETIFS=410STABLE_MAC_ADDRS=yes11NETIF_CREATE=no12lib_dir=$(dirname $0)/../../../net/forwarding13source $lib_dir/tc_common.sh14source $lib_dir/lib.sh15source $lib_dir/tsn_lib.sh16 17UDS_ADDRESS_H1="/var/run/ptp4l_h1"18UDS_ADDRESS_SWP1="/var/run/ptp4l_swp1"19 20# Tunables21NUM_PKTS=100022STREAM_VID=10023STREAM_PRIO=624# Use a conservative cycle of 10 ms to allow the test to still pass when the25# kernel has some extra overhead like lockdep etc26CYCLE_TIME_NS=1000000027# Create two Gate Control List entries, one OPEN and one CLOSE, of equal28# durations29GATE_DURATION_NS=$((${CYCLE_TIME_NS} / 2))30# Give 2/3 of the cycle time to user space and 1/3 to the kernel31FUDGE_FACTOR=$((${CYCLE_TIME_NS} / 3))32# Shift the isochron base time by half the gate time, so that packets are33# always received by swp1 close to the middle of the time slot, to minimize34# inaccuracies due to network sync35SHIFT_TIME_NS=$((${GATE_DURATION_NS} / 2))36 37h1=${NETIFS[p1]}38swp1=${NETIFS[p2]}39swp2=${NETIFS[p3]}40h2=${NETIFS[p4]}41 42H1_IPV4="192.0.2.1"43H2_IPV4="192.0.2.2"44H1_IPV6="2001:db8:1::1"45H2_IPV6="2001:db8:1::2"46 47# Chain number exported by the ocelot driver for48# Per-Stream Filtering and Policing filters49PSFP()50{51 echo 3000052}53 54psfp_chain_create()55{56 local if_name=$157 58 tc qdisc add dev $if_name clsact59 60 tc filter add dev $if_name ingress chain 0 pref 49152 flower \61 skip_sw action goto chain $(PSFP)62}63 64psfp_chain_destroy()65{66 local if_name=$167 68 tc qdisc del dev $if_name clsact69}70 71psfp_filter_check()72{73 local expected=$174 local packets=""75 local drops=""76 local stats=""77 78 stats=$(tc -j -s filter show dev ${swp1} ingress chain $(PSFP) pref 1)79 packets=$(echo ${stats} | jq ".[1].options.actions[].stats.packets")80 drops=$(echo ${stats} | jq ".[1].options.actions[].stats.drops")81 82 if ! [ "${packets}" = "${expected}" ]; then83 printf "Expected filter to match on %d packets but matched on %d instead\n" \84 "${expected}" "${packets}"85 fi86 87 echo "Hardware filter reports ${drops} drops"88}89 90h1_create()91{92 simple_if_init $h1 $H1_IPV4/24 $H1_IPV6/6493}94 95h1_destroy()96{97 simple_if_fini $h1 $H1_IPV4/24 $H1_IPV6/6498}99 100h2_create()101{102 simple_if_init $h2 $H2_IPV4/24 $H2_IPV6/64103}104 105h2_destroy()106{107 simple_if_fini $h2 $H2_IPV4/24 $H2_IPV6/64108}109 110switch_create()111{112 local h2_mac_addr=$(mac_get $h2)113 114 ip link set ${swp1} up115 ip link set ${swp2} up116 117 ip link add br0 type bridge vlan_filtering 1118 ip link set ${swp1} master br0119 ip link set ${swp2} master br0120 ip link set br0 up121 122 bridge vlan add dev ${swp2} vid ${STREAM_VID}123 bridge vlan add dev ${swp1} vid ${STREAM_VID}124 # PSFP on Ocelot requires the filter to also be added to the bridge125 # FDB, and not be removed126 bridge fdb add dev ${swp2} \127 ${h2_mac_addr} vlan ${STREAM_VID} static master128 129 psfp_chain_create ${swp1}130 131 tc filter add dev ${swp1} ingress chain $(PSFP) pref 1 \132 protocol 802.1Q flower skip_sw \133 dst_mac ${h2_mac_addr} vlan_id ${STREAM_VID} \134 action gate base-time 0.000000000 \135 sched-entry OPEN ${GATE_DURATION_NS} -1 -1 \136 sched-entry CLOSE ${GATE_DURATION_NS} -1 -1137}138 139switch_destroy()140{141 psfp_chain_destroy ${swp1}142 ip link del br0143}144 145txtime_setup()146{147 local if_name=$1148 149 tc qdisc add dev ${if_name} clsact150 # Classify PTP on TC 7 and isochron on TC 6151 tc filter add dev ${if_name} egress protocol 0x88f7 \152 flower action skbedit priority 7153 tc filter add dev ${if_name} egress protocol 802.1Q \154 flower vlan_ethtype 0xdead action skbedit priority 6155 tc qdisc add dev ${if_name} handle 100: parent root mqprio num_tc 8 \156 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \157 map 0 1 2 3 4 5 6 7 \158 hw 1159 # Set up TC 6 for SO_TXTIME. tc-mqprio queues count from 1.160 tc qdisc replace dev ${if_name} parent 100:$((${STREAM_PRIO} + 1)) etf \161 clockid CLOCK_TAI offload delta ${FUDGE_FACTOR}162}163 164txtime_cleanup()165{166 local if_name=$1167 168 tc qdisc del dev ${if_name} root169 tc qdisc del dev ${if_name} clsact170}171 172setup_prepare()173{174 vrf_prepare175 176 h1_create177 h2_create178 switch_create179 180 txtime_setup ${h1}181 182 # Set up swp1 as a master PHC for h1, synchronized to the local183 # CLOCK_REALTIME.184 phc2sys_start ${UDS_ADDRESS_SWP1}185 186 # Assumption true for LS1028A: h1 and h2 use the same PHC. So by187 # synchronizing h1 to swp1 via PTP, h2 is also implicitly synchronized188 # to swp1 (and both to CLOCK_REALTIME).189 ptp4l_start ${h1} true ${UDS_ADDRESS_H1}190 ptp4l_start ${swp1} false ${UDS_ADDRESS_SWP1}191 192 # Make sure there are no filter matches at the beginning of the test193 psfp_filter_check 0194}195 196cleanup()197{198 pre_cleanup199 200 ptp4l_stop ${swp1}201 ptp4l_stop ${h1}202 phc2sys_stop203 isochron_recv_stop204 205 txtime_cleanup ${h1}206 207 h2_destroy208 h1_destroy209 switch_destroy210 211 vrf_cleanup212}213 214debug_incorrectly_dropped_packets()215{216 local isochron_dat=$1217 local dropped_seqids218 local seqid219 220 echo "Packets incorrectly dropped:"221 222 dropped_seqids=$(isochron report \223 --input-file "${isochron_dat}" \224 --printf-format "%u RX hw %T\n" \225 --printf-args "qR" | \226 grep 'RX hw 0.000000000' | \227 awk '{print $1}')228 229 for seqid in ${dropped_seqids}; do230 isochron report \231 --input-file "${isochron_dat}" \232 --start ${seqid} --stop ${seqid} \233 --printf-format "seqid %u scheduled for %T, HW TX timestamp %T\n" \234 --printf-args "qST"235 done236}237 238debug_incorrectly_received_packets()239{240 local isochron_dat=$1241 242 echo "Packets incorrectly received:"243 244 isochron report \245 --input-file "${isochron_dat}" \246 --printf-format "seqid %u scheduled for %T, HW TX timestamp %T, HW RX timestamp %T\n" \247 --printf-args "qSTR" |248 grep -v 'HW RX timestamp 0.000000000'249}250 251run_test()252{253 local base_time=$1254 local expected=$2255 local test_name=$3256 local debug=$4257 local isochron_dat="$(mktemp)"258 local extra_args=""259 local received260 261 isochron_do \262 "${h1}" \263 "${h2}" \264 "${UDS_ADDRESS_H1}" \265 "" \266 "${base_time}" \267 "${CYCLE_TIME_NS}" \268 "${SHIFT_TIME_NS}" \269 "${NUM_PKTS}" \270 "${STREAM_VID}" \271 "${STREAM_PRIO}" \272 "" \273 "${isochron_dat}"274 275 # Count all received packets by looking at the non-zero RX timestamps276 received=$(isochron report \277 --input-file "${isochron_dat}" \278 --printf-format "%u\n" --printf-args "R" | \279 grep -w -v '0' | wc -l)280 281 if [ "${received}" = "${expected}" ]; then282 RET=0283 else284 RET=1285 echo "Expected isochron to receive ${expected} packets but received ${received}"286 fi287 288 log_test "${test_name}"289 290 if [ "$RET" = "1" ]; then291 ${debug} "${isochron_dat}"292 fi293 294 rm ${isochron_dat} 2> /dev/null295}296 297test_gate_in_band()298{299 # Send packets in-band with the OPEN gate entry300 run_test 0.000000000 ${NUM_PKTS} "In band" \301 debug_incorrectly_dropped_packets302 303 psfp_filter_check ${NUM_PKTS}304}305 306test_gate_out_of_band()307{308 # Send packets in-band with the CLOSE gate entry309 run_test 0.005000000 0 "Out of band" \310 debug_incorrectly_received_packets311 312 psfp_filter_check $((2 * ${NUM_PKTS}))313}314 315trap cleanup EXIT316 317ALL_TESTS="318 test_gate_in_band319 test_gate_out_of_band320"321 322setup_prepare323setup_wait324 325tests_run326 327exit $EXIT_STATUS328