Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/drivers/net/ocelot/psfp.sh
26298 views
1
#!/bin/bash
2
# SPDX-License-Identifier: GPL-2.0
3
# Copyright 2021-2022 NXP
4
5
# Note: On LS1028A, in lack of enough user ports, this setup requires patching
6
# the device tree to use the second CPU port as a user port
7
8
WAIT_TIME=1
9
NUM_NETIFS=4
10
STABLE_MAC_ADDRS=yes
11
NETIF_CREATE=no
12
lib_dir=$(dirname $0)/../../../net/forwarding
13
source $lib_dir/tc_common.sh
14
source $lib_dir/lib.sh
15
source $lib_dir/tsn_lib.sh
16
17
UDS_ADDRESS_H1="/var/run/ptp4l_h1"
18
UDS_ADDRESS_SWP1="/var/run/ptp4l_swp1"
19
20
# Tunables
21
NUM_PKTS=1000
22
STREAM_VID=100
23
STREAM_PRIO=6
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 etc
26
CYCLE_TIME_NS=10000000
27
# Create two Gate Control List entries, one OPEN and one CLOSE, of equal
28
# durations
29
GATE_DURATION_NS=$((${CYCLE_TIME_NS} / 2))
30
# Give 2/3 of the cycle time to user space and 1/3 to the kernel
31
FUDGE_FACTOR=$((${CYCLE_TIME_NS} / 3))
32
# Shift the isochron base time by half the gate time, so that packets are
33
# always received by swp1 close to the middle of the time slot, to minimize
34
# inaccuracies due to network sync
35
SHIFT_TIME_NS=$((${GATE_DURATION_NS} / 2))
36
37
h1=${NETIFS[p1]}
38
swp1=${NETIFS[p2]}
39
swp2=${NETIFS[p3]}
40
h2=${NETIFS[p4]}
41
42
H1_IPV4="192.0.2.1"
43
H2_IPV4="192.0.2.2"
44
H1_IPV6="2001:db8:1::1"
45
H2_IPV6="2001:db8:1::2"
46
47
# Chain number exported by the ocelot driver for
48
# Per-Stream Filtering and Policing filters
49
PSFP()
50
{
51
echo 30000
52
}
53
54
psfp_chain_create()
55
{
56
local if_name=$1
57
58
tc qdisc add dev $if_name clsact
59
60
tc filter add dev $if_name ingress chain 0 pref 49152 flower \
61
skip_sw action goto chain $(PSFP)
62
}
63
64
psfp_chain_destroy()
65
{
66
local if_name=$1
67
68
tc qdisc del dev $if_name clsact
69
}
70
71
psfp_filter_check()
72
{
73
local expected=$1
74
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}" ]; then
83
printf "Expected filter to match on %d packets but matched on %d instead\n" \
84
"${expected}" "${packets}"
85
fi
86
87
echo "Hardware filter reports ${drops} drops"
88
}
89
90
h1_create()
91
{
92
simple_if_init $h1 $H1_IPV4/24 $H1_IPV6/64
93
}
94
95
h1_destroy()
96
{
97
simple_if_fini $h1 $H1_IPV4/24 $H1_IPV6/64
98
}
99
100
h2_create()
101
{
102
simple_if_init $h2 $H2_IPV4/24 $H2_IPV6/64
103
}
104
105
h2_destroy()
106
{
107
simple_if_fini $h2 $H2_IPV4/24 $H2_IPV6/64
108
}
109
110
switch_create()
111
{
112
local h2_mac_addr=$(mac_get $h2)
113
114
ip link set ${swp1} up
115
ip link set ${swp2} up
116
117
ip link add br0 type bridge vlan_filtering 1
118
ip link set ${swp1} master br0
119
ip link set ${swp2} master br0
120
ip link set br0 up
121
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 bridge
125
# FDB, and not be removed
126
bridge fdb add dev ${swp2} \
127
${h2_mac_addr} vlan ${STREAM_VID} static master
128
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 -1
137
}
138
139
switch_destroy()
140
{
141
psfp_chain_destroy ${swp1}
142
ip link del br0
143
}
144
145
txtime_setup()
146
{
147
local if_name=$1
148
149
tc qdisc add dev ${if_name} clsact
150
# Classify PTP on TC 7 and isochron on TC 6
151
tc filter add dev ${if_name} egress protocol 0x88f7 \
152
flower action skbedit priority 7
153
tc filter add dev ${if_name} egress protocol 802.1Q \
154
flower vlan_ethtype 0xdead action skbedit priority 6
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 1@6 1@7 \
157
map 0 1 2 3 4 5 6 7 \
158
hw 1
159
# 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
164
txtime_cleanup()
165
{
166
local if_name=$1
167
168
tc qdisc del dev ${if_name} root
169
tc qdisc del dev ${if_name} clsact
170
}
171
172
setup_prepare()
173
{
174
vrf_prepare
175
176
h1_create
177
h2_create
178
switch_create
179
180
txtime_setup ${h1}
181
182
# Set up swp1 as a master PHC for h1, synchronized to the local
183
# CLOCK_REALTIME.
184
phc2sys_start ${UDS_ADDRESS_SWP1}
185
186
# Assumption true for LS1028A: h1 and h2 use the same PHC. So by
187
# synchronizing h1 to swp1 via PTP, h2 is also implicitly synchronized
188
# 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 test
193
psfp_filter_check 0
194
}
195
196
cleanup()
197
{
198
pre_cleanup
199
200
ptp4l_stop ${swp1}
201
ptp4l_stop ${h1}
202
phc2sys_stop
203
isochron_recv_stop
204
205
txtime_cleanup ${h1}
206
207
h2_destroy
208
h1_destroy
209
switch_destroy
210
211
vrf_cleanup
212
}
213
214
debug_incorrectly_dropped_packets()
215
{
216
local isochron_dat=$1
217
local dropped_seqids
218
local seqid
219
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}; do
230
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
done
236
}
237
238
debug_incorrectly_received_packets()
239
{
240
local isochron_dat=$1
241
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
251
run_test()
252
{
253
local base_time=$1
254
local expected=$2
255
local test_name=$3
256
local debug=$4
257
local isochron_dat="$(mktemp)"
258
local extra_args=""
259
local received
260
261
isochron_do \
262
"${h1}" \
263
"${h2}" \
264
"${UDS_ADDRESS_H1}" \
265
"" \
266
"${base_time}" \
267
"${CYCLE_TIME_NS}" \
268
"${SHIFT_TIME_NS}" \
269
"${GATE_DURATION_NS}" \
270
"${NUM_PKTS}" \
271
"${STREAM_VID}" \
272
"${STREAM_PRIO}" \
273
"" \
274
"${isochron_dat}"
275
276
received=$(isochron_report_num_received "${isochron_dat}")
277
if [ "${received}" = "${expected}" ]; then
278
RET=0
279
else
280
RET=1
281
echo "Expected isochron to receive ${expected} packets but received ${received}"
282
fi
283
284
log_test "${test_name}"
285
286
if [ "$RET" = "1" ]; then
287
${debug} "${isochron_dat}"
288
fi
289
290
rm ${isochron_dat} 2> /dev/null
291
}
292
293
test_gate_in_band()
294
{
295
# Send packets in-band with the OPEN gate entry
296
run_test 0.000000000 ${NUM_PKTS} "In band" \
297
debug_incorrectly_dropped_packets
298
299
psfp_filter_check ${NUM_PKTS}
300
}
301
302
test_gate_out_of_band()
303
{
304
# Send packets in-band with the CLOSE gate entry
305
run_test 0.005000000 0 "Out of band" \
306
debug_incorrectly_received_packets
307
308
psfp_filter_check $((2 * ${NUM_PKTS}))
309
}
310
311
trap cleanup EXIT
312
313
ALL_TESTS="
314
test_gate_in_band
315
test_gate_out_of_band
316
"
317
318
setup_prepare
319
setup_wait
320
321
tests_run
322
323
exit $EXIT_STATUS
324
325