0001
0002
0003
0004
0005
0006
0007
0008 WAIT_TIME=1
0009 NUM_NETIFS=4
0010 STABLE_MAC_ADDRS=yes
0011 NETIF_CREATE=no
0012 lib_dir=$(dirname $0)/../../../net/forwarding
0013 source $lib_dir/tc_common.sh
0014 source $lib_dir/lib.sh
0015 source $lib_dir/tsn_lib.sh
0016
0017 UDS_ADDRESS_H1="/var/run/ptp4l_h1"
0018 UDS_ADDRESS_SWP1="/var/run/ptp4l_swp1"
0019
0020
0021 NUM_PKTS=1000
0022 STREAM_VID=100
0023 STREAM_PRIO=6
0024
0025
0026 CYCLE_TIME_NS=10000000
0027
0028
0029 GATE_DURATION_NS=$((${CYCLE_TIME_NS} / 2))
0030
0031 FUDGE_FACTOR=$((${CYCLE_TIME_NS} / 3))
0032
0033
0034
0035 SHIFT_TIME_NS=$((${GATE_DURATION_NS} / 2))
0036
0037 h1=${NETIFS[p1]}
0038 swp1=${NETIFS[p2]}
0039 swp2=${NETIFS[p3]}
0040 h2=${NETIFS[p4]}
0041
0042 H1_IPV4="192.0.2.1"
0043 H2_IPV4="192.0.2.2"
0044 H1_IPV6="2001:db8:1::1"
0045 H2_IPV6="2001:db8:1::2"
0046
0047
0048
0049 PSFP()
0050 {
0051 echo 30000
0052 }
0053
0054 psfp_chain_create()
0055 {
0056 local if_name=$1
0057
0058 tc qdisc add dev $if_name clsact
0059
0060 tc filter add dev $if_name ingress chain 0 pref 49152 flower \
0061 skip_sw action goto chain $(PSFP)
0062 }
0063
0064 psfp_chain_destroy()
0065 {
0066 local if_name=$1
0067
0068 tc qdisc del dev $if_name clsact
0069 }
0070
0071 psfp_filter_check()
0072 {
0073 local expected=$1
0074 local packets=""
0075 local drops=""
0076 local stats=""
0077
0078 stats=$(tc -j -s filter show dev ${swp1} ingress chain $(PSFP) pref 1)
0079 packets=$(echo ${stats} | jq ".[1].options.actions[].stats.packets")
0080 drops=$(echo ${stats} | jq ".[1].options.actions[].stats.drops")
0081
0082 if ! [ "${packets}" = "${expected}" ]; then
0083 printf "Expected filter to match on %d packets but matched on %d instead\n" \
0084 "${expected}" "${packets}"
0085 fi
0086
0087 echo "Hardware filter reports ${drops} drops"
0088 }
0089
0090 h1_create()
0091 {
0092 simple_if_init $h1 $H1_IPV4/24 $H1_IPV6/64
0093 }
0094
0095 h1_destroy()
0096 {
0097 simple_if_fini $h1 $H1_IPV4/24 $H1_IPV6/64
0098 }
0099
0100 h2_create()
0101 {
0102 simple_if_init $h2 $H2_IPV4/24 $H2_IPV6/64
0103 }
0104
0105 h2_destroy()
0106 {
0107 simple_if_fini $h2 $H2_IPV4/24 $H2_IPV6/64
0108 }
0109
0110 switch_create()
0111 {
0112 local h2_mac_addr=$(mac_get $h2)
0113
0114 ip link set ${swp1} up
0115 ip link set ${swp2} up
0116
0117 ip link add br0 type bridge vlan_filtering 1
0118 ip link set ${swp1} master br0
0119 ip link set ${swp2} master br0
0120 ip link set br0 up
0121
0122 bridge vlan add dev ${swp2} vid ${STREAM_VID}
0123 bridge vlan add dev ${swp1} vid ${STREAM_VID}
0124
0125
0126 bridge fdb add dev ${swp2} \
0127 ${h2_mac_addr} vlan ${STREAM_VID} static master
0128
0129 psfp_chain_create ${swp1}
0130
0131 tc filter add dev ${swp1} ingress chain $(PSFP) pref 1 \
0132 protocol 802.1Q flower skip_sw \
0133 dst_mac ${h2_mac_addr} vlan_id ${STREAM_VID} \
0134 action gate base-time 0.000000000 \
0135 sched-entry OPEN ${GATE_DURATION_NS} -1 -1 \
0136 sched-entry CLOSE ${GATE_DURATION_NS} -1 -1
0137 }
0138
0139 switch_destroy()
0140 {
0141 psfp_chain_destroy ${swp1}
0142 ip link del br0
0143 }
0144
0145 txtime_setup()
0146 {
0147 local if_name=$1
0148
0149 tc qdisc add dev ${if_name} clsact
0150
0151 tc filter add dev ${if_name} egress protocol 0x88f7 \
0152 flower action skbedit priority 7
0153 tc filter add dev ${if_name} egress protocol 802.1Q \
0154 flower vlan_ethtype 0xdead action skbedit priority 6
0155 tc qdisc add dev ${if_name} handle 100: parent root mqprio num_tc 8 \
0156 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \
0157 map 0 1 2 3 4 5 6 7 \
0158 hw 1
0159
0160 tc qdisc replace dev ${if_name} parent 100:$((${STREAM_PRIO} + 1)) etf \
0161 clockid CLOCK_TAI offload delta ${FUDGE_FACTOR}
0162 }
0163
0164 txtime_cleanup()
0165 {
0166 local if_name=$1
0167
0168 tc qdisc del dev ${if_name} root
0169 tc qdisc del dev ${if_name} clsact
0170 }
0171
0172 setup_prepare()
0173 {
0174 vrf_prepare
0175
0176 h1_create
0177 h2_create
0178 switch_create
0179
0180 txtime_setup ${h1}
0181
0182
0183
0184 phc2sys_start ${swp1} ${UDS_ADDRESS_SWP1}
0185
0186
0187
0188
0189 ptp4l_start ${h1} true ${UDS_ADDRESS_H1}
0190 ptp4l_start ${swp1} false ${UDS_ADDRESS_SWP1}
0191
0192
0193 psfp_filter_check 0
0194 }
0195
0196 cleanup()
0197 {
0198 pre_cleanup
0199
0200 ptp4l_stop ${swp1}
0201 ptp4l_stop ${h1}
0202 phc2sys_stop
0203 isochron_recv_stop
0204
0205 txtime_cleanup ${h1}
0206
0207 h2_destroy
0208 h1_destroy
0209 switch_destroy
0210
0211 vrf_cleanup
0212 }
0213
0214 debug_incorrectly_dropped_packets()
0215 {
0216 local isochron_dat=$1
0217 local dropped_seqids
0218 local seqid
0219
0220 echo "Packets incorrectly dropped:"
0221
0222 dropped_seqids=$(isochron report \
0223 --input-file "${isochron_dat}" \
0224 --printf-format "%u RX hw %T\n" \
0225 --printf-args "qR" | \
0226 grep 'RX hw 0.000000000' | \
0227 awk '{print $1}')
0228
0229 for seqid in ${dropped_seqids}; do
0230 isochron report \
0231 --input-file "${isochron_dat}" \
0232 --start ${seqid} --stop ${seqid} \
0233 --printf-format "seqid %u scheduled for %T, HW TX timestamp %T\n" \
0234 --printf-args "qST"
0235 done
0236 }
0237
0238 debug_incorrectly_received_packets()
0239 {
0240 local isochron_dat=$1
0241
0242 echo "Packets incorrectly received:"
0243
0244 isochron report \
0245 --input-file "${isochron_dat}" \
0246 --printf-format "seqid %u scheduled for %T, HW TX timestamp %T, HW RX timestamp %T\n" \
0247 --printf-args "qSTR" |
0248 grep -v 'HW RX timestamp 0.000000000'
0249 }
0250
0251 run_test()
0252 {
0253 local base_time=$1
0254 local expected=$2
0255 local test_name=$3
0256 local debug=$4
0257 local isochron_dat="$(mktemp)"
0258 local extra_args=""
0259 local received
0260
0261 isochron_do \
0262 "${h1}" \
0263 "${h2}" \
0264 "${UDS_ADDRESS_H1}" \
0265 "" \
0266 "${base_time}" \
0267 "${CYCLE_TIME_NS}" \
0268 "${SHIFT_TIME_NS}" \
0269 "${NUM_PKTS}" \
0270 "${STREAM_VID}" \
0271 "${STREAM_PRIO}" \
0272 "" \
0273 "${isochron_dat}"
0274
0275
0276 received=$(isochron report \
0277 --input-file "${isochron_dat}" \
0278 --printf-format "%u\n" --printf-args "R" | \
0279 grep -w -v '0' | wc -l)
0280
0281 if [ "${received}" = "${expected}" ]; then
0282 RET=0
0283 else
0284 RET=1
0285 echo "Expected isochron to receive ${expected} packets but received ${received}"
0286 fi
0287
0288 log_test "${test_name}"
0289
0290 if [ "$RET" = "1" ]; then
0291 ${debug} "${isochron_dat}"
0292 fi
0293
0294 rm ${isochron_dat} 2> /dev/null
0295 }
0296
0297 test_gate_in_band()
0298 {
0299
0300 run_test 0.000000000 ${NUM_PKTS} "In band" \
0301 debug_incorrectly_dropped_packets
0302
0303 psfp_filter_check ${NUM_PKTS}
0304 }
0305
0306 test_gate_out_of_band()
0307 {
0308
0309 run_test 0.005000000 0 "Out of band" \
0310 debug_incorrectly_received_packets
0311
0312 psfp_filter_check $((2 * ${NUM_PKTS}))
0313 }
0314
0315 trap cleanup EXIT
0316
0317 ALL_TESTS="
0318 test_gate_in_band
0319 test_gate_out_of_band
0320 "
0321
0322 setup_prepare
0323 setup_wait
0324
0325 tests_run
0326
0327 exit $EXIT_STATUS