1 #!/bin/bash 1 #!/bin/bash 2 # SPDX-License-Identifier: GPL-2.0 2 # SPDX-License-Identifier: GPL-2.0 3 # Copyright 2021-2022 NXP 3 # Copyright 2021-2022 NXP 4 4 5 # Note: On LS1028A, in lack of enough user por 5 # Note: On LS1028A, in lack of enough user ports, this setup requires patching 6 # the device tree to use the second CPU port a 6 # the device tree to use the second CPU port as a user port 7 7 8 WAIT_TIME=1 8 WAIT_TIME=1 9 NUM_NETIFS=4 9 NUM_NETIFS=4 10 STABLE_MAC_ADDRS=yes 10 STABLE_MAC_ADDRS=yes 11 NETIF_CREATE=no 11 NETIF_CREATE=no 12 lib_dir=$(dirname $0)/../../../net/forwarding 12 lib_dir=$(dirname $0)/../../../net/forwarding 13 source $lib_dir/tc_common.sh 13 source $lib_dir/tc_common.sh 14 source $lib_dir/lib.sh 14 source $lib_dir/lib.sh 15 source $lib_dir/tsn_lib.sh 15 source $lib_dir/tsn_lib.sh 16 16 17 UDS_ADDRESS_H1="/var/run/ptp4l_h1" 17 UDS_ADDRESS_H1="/var/run/ptp4l_h1" 18 UDS_ADDRESS_SWP1="/var/run/ptp4l_swp1" 18 UDS_ADDRESS_SWP1="/var/run/ptp4l_swp1" 19 19 20 # Tunables 20 # Tunables 21 NUM_PKTS=1000 21 NUM_PKTS=1000 22 STREAM_VID=100 22 STREAM_VID=100 23 STREAM_PRIO=6 23 STREAM_PRIO=6 24 # Use a conservative cycle of 10 ms to allow t 24 # Use a conservative cycle of 10 ms to allow the test to still pass when the 25 # kernel has some extra overhead like lockdep 25 # kernel has some extra overhead like lockdep etc 26 CYCLE_TIME_NS=10000000 26 CYCLE_TIME_NS=10000000 27 # Create two Gate Control List entries, one OP 27 # Create two Gate Control List entries, one OPEN and one CLOSE, of equal 28 # durations 28 # durations 29 GATE_DURATION_NS=$((${CYCLE_TIME_NS} / 2)) 29 GATE_DURATION_NS=$((${CYCLE_TIME_NS} / 2)) 30 # Give 2/3 of the cycle time to user space and 30 # Give 2/3 of the cycle time to user space and 1/3 to the kernel 31 FUDGE_FACTOR=$((${CYCLE_TIME_NS} / 3)) 31 FUDGE_FACTOR=$((${CYCLE_TIME_NS} / 3)) 32 # Shift the isochron base time by half the gat 32 # Shift the isochron base time by half the gate time, so that packets are 33 # always received by swp1 close to the middle 33 # always received by swp1 close to the middle of the time slot, to minimize 34 # inaccuracies due to network sync 34 # inaccuracies due to network sync 35 SHIFT_TIME_NS=$((${GATE_DURATION_NS} / 2)) 35 SHIFT_TIME_NS=$((${GATE_DURATION_NS} / 2)) 36 36 37 h1=${NETIFS[p1]} 37 h1=${NETIFS[p1]} 38 swp1=${NETIFS[p2]} 38 swp1=${NETIFS[p2]} 39 swp2=${NETIFS[p3]} 39 swp2=${NETIFS[p3]} 40 h2=${NETIFS[p4]} 40 h2=${NETIFS[p4]} 41 41 42 H1_IPV4="192.0.2.1" 42 H1_IPV4="192.0.2.1" 43 H2_IPV4="192.0.2.2" 43 H2_IPV4="192.0.2.2" 44 H1_IPV6="2001:db8:1::1" 44 H1_IPV6="2001:db8:1::1" 45 H2_IPV6="2001:db8:1::2" 45 H2_IPV6="2001:db8:1::2" 46 46 47 # Chain number exported by the ocelot driver f 47 # Chain number exported by the ocelot driver for 48 # Per-Stream Filtering and Policing filters 48 # Per-Stream Filtering and Policing filters 49 PSFP() 49 PSFP() 50 { 50 { 51 echo 30000 51 echo 30000 52 } 52 } 53 53 54 psfp_chain_create() 54 psfp_chain_create() 55 { 55 { 56 local if_name=$1 56 local if_name=$1 57 57 58 tc qdisc add dev $if_name clsact 58 tc qdisc add dev $if_name clsact 59 59 60 tc filter add dev $if_name ingress cha 60 tc filter add dev $if_name ingress chain 0 pref 49152 flower \ 61 skip_sw action goto chain $(PS 61 skip_sw action goto chain $(PSFP) 62 } 62 } 63 63 64 psfp_chain_destroy() 64 psfp_chain_destroy() 65 { 65 { 66 local if_name=$1 66 local if_name=$1 67 67 68 tc qdisc del dev $if_name clsact 68 tc qdisc del dev $if_name clsact 69 } 69 } 70 70 71 psfp_filter_check() 71 psfp_filter_check() 72 { 72 { 73 local expected=$1 73 local expected=$1 74 local packets="" 74 local packets="" 75 local drops="" 75 local drops="" 76 local stats="" 76 local stats="" 77 77 78 stats=$(tc -j -s filter show dev ${swp 78 stats=$(tc -j -s filter show dev ${swp1} ingress chain $(PSFP) pref 1) 79 packets=$(echo ${stats} | jq ".[1].opt 79 packets=$(echo ${stats} | jq ".[1].options.actions[].stats.packets") 80 drops=$(echo ${stats} | jq ".[1].optio 80 drops=$(echo ${stats} | jq ".[1].options.actions[].stats.drops") 81 81 82 if ! [ "${packets}" = "${expected}" ]; 82 if ! [ "${packets}" = "${expected}" ]; then 83 printf "Expected filter to mat 83 printf "Expected filter to match on %d packets but matched on %d instead\n" \ 84 "${expected}" "${packe 84 "${expected}" "${packets}" 85 fi 85 fi 86 86 87 echo "Hardware filter reports ${drops} 87 echo "Hardware filter reports ${drops} drops" 88 } 88 } 89 89 90 h1_create() 90 h1_create() 91 { 91 { 92 simple_if_init $h1 $H1_IPV4/24 $H1_IPV 92 simple_if_init $h1 $H1_IPV4/24 $H1_IPV6/64 93 } 93 } 94 94 95 h1_destroy() 95 h1_destroy() 96 { 96 { 97 simple_if_fini $h1 $H1_IPV4/24 $H1_IPV 97 simple_if_fini $h1 $H1_IPV4/24 $H1_IPV6/64 98 } 98 } 99 99 100 h2_create() 100 h2_create() 101 { 101 { 102 simple_if_init $h2 $H2_IPV4/24 $H2_IPV 102 simple_if_init $h2 $H2_IPV4/24 $H2_IPV6/64 103 } 103 } 104 104 105 h2_destroy() 105 h2_destroy() 106 { 106 { 107 simple_if_fini $h2 $H2_IPV4/24 $H2_IPV 107 simple_if_fini $h2 $H2_IPV4/24 $H2_IPV6/64 108 } 108 } 109 109 110 switch_create() 110 switch_create() 111 { 111 { 112 local h2_mac_addr=$(mac_get $h2) 112 local h2_mac_addr=$(mac_get $h2) 113 113 114 ip link set ${swp1} up 114 ip link set ${swp1} up 115 ip link set ${swp2} up 115 ip link set ${swp2} up 116 116 117 ip link add br0 type bridge vlan_filte 117 ip link add br0 type bridge vlan_filtering 1 118 ip link set ${swp1} master br0 118 ip link set ${swp1} master br0 119 ip link set ${swp2} master br0 119 ip link set ${swp2} master br0 120 ip link set br0 up 120 ip link set br0 up 121 121 122 bridge vlan add dev ${swp2} vid ${STRE 122 bridge vlan add dev ${swp2} vid ${STREAM_VID} 123 bridge vlan add dev ${swp1} vid ${STRE 123 bridge vlan add dev ${swp1} vid ${STREAM_VID} 124 # PSFP on Ocelot requires the filter t 124 # PSFP on Ocelot requires the filter to also be added to the bridge 125 # FDB, and not be removed 125 # FDB, and not be removed 126 bridge fdb add dev ${swp2} \ 126 bridge fdb add dev ${swp2} \ 127 ${h2_mac_addr} vlan ${STREAM_V 127 ${h2_mac_addr} vlan ${STREAM_VID} static master 128 128 129 psfp_chain_create ${swp1} 129 psfp_chain_create ${swp1} 130 130 131 tc filter add dev ${swp1} ingress chai 131 tc filter add dev ${swp1} ingress chain $(PSFP) pref 1 \ 132 protocol 802.1Q flower skip_sw 132 protocol 802.1Q flower skip_sw \ 133 dst_mac ${h2_mac_addr} vlan_id 133 dst_mac ${h2_mac_addr} vlan_id ${STREAM_VID} \ 134 action gate base-time 0.000000 134 action gate base-time 0.000000000 \ 135 sched-entry OPEN ${GATE_DURAT 135 sched-entry OPEN ${GATE_DURATION_NS} -1 -1 \ 136 sched-entry CLOSE ${GATE_DURAT 136 sched-entry CLOSE ${GATE_DURATION_NS} -1 -1 137 } 137 } 138 138 139 switch_destroy() 139 switch_destroy() 140 { 140 { 141 psfp_chain_destroy ${swp1} 141 psfp_chain_destroy ${swp1} 142 ip link del br0 142 ip link del br0 143 } 143 } 144 144 145 txtime_setup() 145 txtime_setup() 146 { 146 { 147 local if_name=$1 147 local if_name=$1 148 148 149 tc qdisc add dev ${if_name} clsact 149 tc qdisc add dev ${if_name} clsact 150 # Classify PTP on TC 7 and isochron on 150 # Classify PTP on TC 7 and isochron on TC 6 151 tc filter add dev ${if_name} egress pr 151 tc filter add dev ${if_name} egress protocol 0x88f7 \ 152 flower action skbedit priority 152 flower action skbedit priority 7 153 tc filter add dev ${if_name} egress pr 153 tc filter add dev ${if_name} egress protocol 802.1Q \ 154 flower vlan_ethtype 0xdead act 154 flower vlan_ethtype 0xdead action skbedit priority 6 155 tc qdisc add dev ${if_name} handle 100 155 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 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 \ 157 map 0 1 2 3 4 5 6 7 \ 158 hw 1 158 hw 1 159 # Set up TC 6 for SO_TXTIME. tc-mqprio 159 # Set up TC 6 for SO_TXTIME. tc-mqprio queues count from 1. 160 tc qdisc replace dev ${if_name} parent 160 tc qdisc replace dev ${if_name} parent 100:$((${STREAM_PRIO} + 1)) etf \ 161 clockid CLOCK_TAI offload delt 161 clockid CLOCK_TAI offload delta ${FUDGE_FACTOR} 162 } 162 } 163 163 164 txtime_cleanup() 164 txtime_cleanup() 165 { 165 { 166 local if_name=$1 166 local if_name=$1 167 167 168 tc qdisc del dev ${if_name} root 168 tc qdisc del dev ${if_name} root 169 tc qdisc del dev ${if_name} clsact 169 tc qdisc del dev ${if_name} clsact 170 } 170 } 171 171 172 setup_prepare() 172 setup_prepare() 173 { 173 { 174 vrf_prepare 174 vrf_prepare 175 175 176 h1_create 176 h1_create 177 h2_create 177 h2_create 178 switch_create 178 switch_create 179 179 180 txtime_setup ${h1} 180 txtime_setup ${h1} 181 181 182 # Set up swp1 as a master PHC for h1, 182 # Set up swp1 as a master PHC for h1, synchronized to the local 183 # CLOCK_REALTIME. 183 # CLOCK_REALTIME. 184 phc2sys_start ${UDS_ADDRESS_SWP1} 184 phc2sys_start ${UDS_ADDRESS_SWP1} 185 185 186 # Assumption true for LS1028A: h1 and 186 # Assumption true for LS1028A: h1 and h2 use the same PHC. So by 187 # synchronizing h1 to swp1 via PTP, h2 187 # synchronizing h1 to swp1 via PTP, h2 is also implicitly synchronized 188 # to swp1 (and both to CLOCK_REALTIME) 188 # to swp1 (and both to CLOCK_REALTIME). 189 ptp4l_start ${h1} true ${UDS_ADDRESS_H 189 ptp4l_start ${h1} true ${UDS_ADDRESS_H1} 190 ptp4l_start ${swp1} false ${UDS_ADDRES 190 ptp4l_start ${swp1} false ${UDS_ADDRESS_SWP1} 191 191 192 # Make sure there are no filter matche 192 # Make sure there are no filter matches at the beginning of the test 193 psfp_filter_check 0 193 psfp_filter_check 0 194 } 194 } 195 195 196 cleanup() 196 cleanup() 197 { 197 { 198 pre_cleanup 198 pre_cleanup 199 199 200 ptp4l_stop ${swp1} 200 ptp4l_stop ${swp1} 201 ptp4l_stop ${h1} 201 ptp4l_stop ${h1} 202 phc2sys_stop 202 phc2sys_stop 203 isochron_recv_stop 203 isochron_recv_stop 204 204 205 txtime_cleanup ${h1} 205 txtime_cleanup ${h1} 206 206 207 h2_destroy 207 h2_destroy 208 h1_destroy 208 h1_destroy 209 switch_destroy 209 switch_destroy 210 210 211 vrf_cleanup 211 vrf_cleanup 212 } 212 } 213 213 214 debug_incorrectly_dropped_packets() 214 debug_incorrectly_dropped_packets() 215 { 215 { 216 local isochron_dat=$1 216 local isochron_dat=$1 217 local dropped_seqids 217 local dropped_seqids 218 local seqid 218 local seqid 219 219 220 echo "Packets incorrectly dropped:" 220 echo "Packets incorrectly dropped:" 221 221 222 dropped_seqids=$(isochron report \ 222 dropped_seqids=$(isochron report \ 223 --input-file "${isochron_dat}" 223 --input-file "${isochron_dat}" \ 224 --printf-format "%u RX hw %T\n 224 --printf-format "%u RX hw %T\n" \ 225 --printf-args "qR" | \ 225 --printf-args "qR" | \ 226 grep 'RX hw 0.000000000' | \ 226 grep 'RX hw 0.000000000' | \ 227 awk '{print $1}') 227 awk '{print $1}') 228 228 229 for seqid in ${dropped_seqids}; do 229 for seqid in ${dropped_seqids}; do 230 isochron report \ 230 isochron report \ 231 --input-file "${isochr 231 --input-file "${isochron_dat}" \ 232 --start ${seqid} --sto 232 --start ${seqid} --stop ${seqid} \ 233 --printf-format "seqid 233 --printf-format "seqid %u scheduled for %T, HW TX timestamp %T\n" \ 234 --printf-args "qST" 234 --printf-args "qST" 235 done 235 done 236 } 236 } 237 237 238 debug_incorrectly_received_packets() 238 debug_incorrectly_received_packets() 239 { 239 { 240 local isochron_dat=$1 240 local isochron_dat=$1 241 241 242 echo "Packets incorrectly received:" 242 echo "Packets incorrectly received:" 243 243 244 isochron report \ 244 isochron report \ 245 --input-file "${isochron_dat}" 245 --input-file "${isochron_dat}" \ 246 --printf-format "seqid %u sche 246 --printf-format "seqid %u scheduled for %T, HW TX timestamp %T, HW RX timestamp %T\n" \ 247 --printf-args "qSTR" | 247 --printf-args "qSTR" | 248 grep -v 'HW RX timestamp 0.000 248 grep -v 'HW RX timestamp 0.000000000' 249 } 249 } 250 250 251 run_test() 251 run_test() 252 { 252 { 253 local base_time=$1 253 local base_time=$1 254 local expected=$2 254 local expected=$2 255 local test_name=$3 255 local test_name=$3 256 local debug=$4 256 local debug=$4 257 local isochron_dat="$(mktemp)" 257 local isochron_dat="$(mktemp)" 258 local extra_args="" 258 local extra_args="" 259 local received 259 local received 260 260 261 isochron_do \ 261 isochron_do \ 262 "${h1}" \ 262 "${h1}" \ 263 "${h2}" \ 263 "${h2}" \ 264 "${UDS_ADDRESS_H1}" \ 264 "${UDS_ADDRESS_H1}" \ 265 "" \ 265 "" \ 266 "${base_time}" \ 266 "${base_time}" \ 267 "${CYCLE_TIME_NS}" \ 267 "${CYCLE_TIME_NS}" \ 268 "${SHIFT_TIME_NS}" \ 268 "${SHIFT_TIME_NS}" \ 269 "${NUM_PKTS}" \ 269 "${NUM_PKTS}" \ 270 "${STREAM_VID}" \ 270 "${STREAM_VID}" \ 271 "${STREAM_PRIO}" \ 271 "${STREAM_PRIO}" \ 272 "" \ 272 "" \ 273 "${isochron_dat}" 273 "${isochron_dat}" 274 274 275 # Count all received packets by lookin 275 # Count all received packets by looking at the non-zero RX timestamps 276 received=$(isochron report \ 276 received=$(isochron report \ 277 --input-file "${isochron_dat}" 277 --input-file "${isochron_dat}" \ 278 --printf-format "%u\n" --print 278 --printf-format "%u\n" --printf-args "R" | \ 279 grep -w -v '0' | wc -l) 279 grep -w -v '0' | wc -l) 280 280 281 if [ "${received}" = "${expected}" ]; 281 if [ "${received}" = "${expected}" ]; then 282 RET=0 282 RET=0 283 else 283 else 284 RET=1 284 RET=1 285 echo "Expected isochron to rec 285 echo "Expected isochron to receive ${expected} packets but received ${received}" 286 fi 286 fi 287 287 288 log_test "${test_name}" 288 log_test "${test_name}" 289 289 290 if [ "$RET" = "1" ]; then 290 if [ "$RET" = "1" ]; then 291 ${debug} "${isochron_dat}" 291 ${debug} "${isochron_dat}" 292 fi 292 fi 293 293 294 rm ${isochron_dat} 2> /dev/null 294 rm ${isochron_dat} 2> /dev/null 295 } 295 } 296 296 297 test_gate_in_band() 297 test_gate_in_band() 298 { 298 { 299 # Send packets in-band with the OPEN g 299 # Send packets in-band with the OPEN gate entry 300 run_test 0.000000000 ${NUM_PKTS} "In b 300 run_test 0.000000000 ${NUM_PKTS} "In band" \ 301 debug_incorrectly_dropped_pack 301 debug_incorrectly_dropped_packets 302 302 303 psfp_filter_check ${NUM_PKTS} 303 psfp_filter_check ${NUM_PKTS} 304 } 304 } 305 305 306 test_gate_out_of_band() 306 test_gate_out_of_band() 307 { 307 { 308 # Send packets in-band with the CLOSE 308 # Send packets in-band with the CLOSE gate entry 309 run_test 0.005000000 0 "Out of band" \ 309 run_test 0.005000000 0 "Out of band" \ 310 debug_incorrectly_received_pac 310 debug_incorrectly_received_packets 311 311 312 psfp_filter_check $((2 * ${NUM_PKTS})) 312 psfp_filter_check $((2 * ${NUM_PKTS})) 313 } 313 } 314 314 315 trap cleanup EXIT 315 trap cleanup EXIT 316 316 317 ALL_TESTS=" 317 ALL_TESTS=" 318 test_gate_in_band 318 test_gate_in_band 319 test_gate_out_of_band 319 test_gate_out_of_band 320 " 320 " 321 321 322 setup_prepare 322 setup_prepare 323 setup_wait 323 setup_wait 324 324 325 tests_run 325 tests_run 326 326 327 exit $EXIT_STATUS 327 exit $EXIT_STATUS
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.