summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/drivers/net/microchip/ksz9477_qos.sh
blob: 82be5d013330199aad569552b093de3c91ae820e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2024 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>

# The script is adopted to work with the Microchip KSZ switch driver.

ETH_FCS_LEN=4

WAIT_TIME=1
NUM_NETIFS=4
REQUIRE_JQ="yes"
REQUIRE_MZ="yes"
STABLE_MAC_ADDRS=yes
NETIF_CREATE=no
lib_dir=$(dirname $0)/../../../net/forwarding
source $lib_dir/tc_common.sh
source $lib_dir/lib.sh

require_command dcb

h1=${NETIFS[p1]}
swp1=${NETIFS[p2]}
swp2=${NETIFS[p3]}
h2=${NETIFS[p4]}

H1_IPV4="192.0.2.1"
H2_IPV4="192.0.2.2"
H1_IPV6="2001:db8:1::1"
H2_IPV6="2001:db8:1::2"

# On h1_ and h2_create do not set IP addresses to avoid interaction with the
# system, to keep packet counters clean.
h1_create()
{
	simple_if_init $h1
	sysctl_set net.ipv6.conf.${h1}.disable_ipv6 1
	# Get the MAC address of the interface to use it with mausezahn
	h1_mac=$(ip -j link show dev ${h1} | jq -e '.[].address')
}

h1_destroy()
{
	sysctl_restore net.ipv6.conf.${h1}.disable_ipv6
	simple_if_fini $h1
}

h2_create()
{
	simple_if_init $h2
	sysctl_set net.ipv6.conf.${h2}.disable_ipv6 1
	h2_mac=$(ip -j link show dev ${h2} | jq -e '.[].address')
}

h2_destroy()
{
	sysctl_restore net.ipv6.conf.${h2}.disable_ipv6
	simple_if_fini $h2
}

switch_create()
{
	ip link set ${swp1} up
	ip link set ${swp2} up
	sysctl_set net.ipv6.conf.${swp1}.disable_ipv6 1
	sysctl_set net.ipv6.conf.${swp2}.disable_ipv6 1

	# Ports should trust VLAN PCP even with vlan_filtering=0
	ip link add br0 type bridge
	ip link set ${swp1} master br0
	ip link set ${swp2} master br0
	ip link set br0 up
	sysctl_set net.ipv6.conf.br0.disable_ipv6 1
}

switch_destroy()
{
	sysctl_restore net.ipv6.conf.${swp2}.disable_ipv6
	sysctl_restore net.ipv6.conf.${swp1}.disable_ipv6

	ip link del br0
}

setup_prepare()
{
	vrf_prepare

	h1_create
	h2_create
	switch_create
}

cleanup()
{
	pre_cleanup

	h2_destroy
	h1_destroy
	switch_destroy

	vrf_cleanup
}

set_apptrust_order()
{
	local if_name=$1
	local order=$2

	dcb apptrust set dev ${if_name} order ${order}
}

# Function to extract a specified field from a given JSON stats string
extract_network_stat() {
	local stats_json=$1
	local field_name=$2

	echo $(echo "$stats_json" | jq -r "$field_name")
}

run_test()
{
	local test_name=$1;
	local apptrust_order=$2;
	local port_prio=$3;
	local dscp_ipv=$4;
	local dscp=$5;
	local have_vlan=$6;
	local pcp_ipv=$7;
	local vlan_pcp=$8;
	local ip_v6=$9

	local rx_ipv
	local tx_ipv

	RET=0

	# Send some packet to populate the switch MAC table
	$MZ ${h2} -a ${h2_mac} -b ${h1_mac} -p 64 -t icmp echores -c 1

	# Based on the apptrust order, set the expected Internal Priority values
	# for the RX and TX paths.
	if [ "${apptrust_order}" == "" ]; then
		echo "Apptrust order not set."
		rx_ipv=${port_prio}
		tx_ipv=${port_prio}
	elif [ "${apptrust_order}" == "dscp" ]; then
		echo "Apptrust order is DSCP."
		rx_ipv=${dscp_ipv}
		tx_ipv=${dscp_ipv}
	elif [ "${apptrust_order}" == "pcp" ]; then
		echo "Apptrust order is PCP."
		rx_ipv=${pcp_ipv}
		tx_ipv=${pcp_ipv}
	elif [ "${apptrust_order}" == "pcp dscp" ]; then
		echo "Apptrust order is PCP DSCP."
		if [ ${have_vlan} -eq 1 ]; then
			rx_ipv=$((dscp_ipv > pcp_ipv ? dscp_ipv : pcp_ipv))
			tx_ipv=${pcp_ipv}
		else
			rx_ipv=${dscp_ipv}
			tx_ipv=${dscp_ipv}
		fi
	else
		RET=1
		echo "Error: Unknown apptrust order ${apptrust_order}"
		log_test "${test_name}"
		return
	fi

	# Most/all? of the KSZ switches do not provide per-TC counters. There
	# are only tx_hi and rx_hi counters, which are used to count packets
	# which are considered as high priority and most likely not assigned
	# to the queue 0.
	# On the ingress path, packets seem to get high priority status
	# independently of the DSCP or PCP global mapping. On the egress path,
	# the high priority status is assigned based on the DSCP or PCP global
	# map configuration.
	# The thresholds for the high priority status are not documented, but
	# it seems that the switch considers packets as high priority on the
	# ingress path if detected Internal Priority is greater than 0. On the
	# egress path, the switch considers packets as high priority if
	# detected Internal Priority is greater than 1.
	if [ ${rx_ipv} -ge 1 ]; then
		local expect_rx_high_prio=1
	else
		local expect_rx_high_prio=0
	fi

	if [ ${tx_ipv} -ge 2 ]; then
		local expect_tx_high_prio=1
	else
		local expect_tx_high_prio=0
	fi

	# Use ip tool to get the current switch packet counters. ethool stats
	# need to be recalculated to get the correct values.
	local swp1_stats=$(ip -s -j link show dev ${swp1})
	local swp2_stats=$(ip -s -j link show dev ${swp2})
	local swp1_rx_packets_before=$(extract_network_stat "$swp1_stats" \
				       '.[0].stats64.rx.packets')
	local swp1_rx_bytes_before=$(extract_network_stat "$swp1_stats" \
				     '.[0].stats64.rx.bytes')
	local swp2_tx_packets_before=$(extract_network_stat "$swp2_stats" \
				       '.[0].stats64.tx.packets')
	local swp2_tx_bytes_before=$(extract_network_stat "$swp2_stats" \
				     '.[0].stats64.tx.bytes')
	local swp1_rx_hi_before=$(ethtool_stats_get ${swp1} "rx_hi")
	local swp2_tx_hi_before=$(ethtool_stats_get ${swp2} "tx_hi")

	# Assamble the mausezahn command based on the test parameters
	# For the testis with ipv4 or ipv6, use icmp response packets,
	# to avoid interaction with the system, to keep packet counters
	# clean.
	if [ ${ip_v6} -eq 0 ]; then
		local ip="-a ${h1_mac} -b ${h2_mac} -A ${H1_IPV4} \
			  -B ${H2_IPV4} -t icmp unreach,code=1,dscp=${dscp}"
	else
		local ip="-6 -a ${h1_mac} -b ${h2_mac} -A ${H1_IPV6} \
			  -B ${H2_IPV6} -t icmp6 type=1,code=0,dscp=${dscp}"
	fi

	if [ ${have_vlan} -eq 1 ]; then
		local vlan_pcp_opt="-Q ${vlan_pcp}:0"
	else
		local vlan_pcp_opt=""
	fi
	$MZ ${h1} ${ip} -c ${PING_COUNT} -d 10msec ${vlan_pcp_opt}

	# Wait until the switch packet counters are updated
	sleep 6

	local swp1_stats=$(ip -s -j link show dev ${swp1})
	local swp2_stats=$(ip -s -j link show dev ${swp2})

	local swp1_rx_packets_after=$(extract_network_stat "$swp1_stats" \
				      '.[0].stats64.rx.packets')
	local swp1_rx_bytes_after=$(extract_network_stat "$swp1_stats" \
				    '.[0].stats64.rx.bytes')
	local swp2_tx_packets_after=$(extract_network_stat "$swp2_stats" \
				      '.[0].stats64.tx.packets')
	local swp2_tx_bytes_after=$(extract_network_stat "$swp2_stats" \
				    '.[0].stats64.tx.bytes')

	local swp1_rx_packets_diff=$((${swp1_rx_packets_after} - \
				      ${swp1_rx_packets_before}))
	local swp2_tx_packets_diff=$((${swp2_tx_packets_after} - \
				      ${swp2_tx_packets_before}))

	local swp1_rx_hi_after=$(ethtool_stats_get ${swp1} "rx_hi")
	local swp2_tx_hi_after=$(ethtool_stats_get ${swp2} "tx_hi")

	# Test if any packets were received on swp1, we will rx before and after
	if [ ${swp1_rx_packets_diff} -lt ${PING_COUNT} ]; then
		echo "Not expected amount of received packets on ${swp1}"
		echo "before ${swp1_rx_packets_before} after ${swp1_rx_packets_after}"
		RET=1
	fi

	# Test if any packets were transmitted on swp2, we will tx before and after
	if [ ${swp2_tx_packets_diff} -lt ${PING_COUNT} ]; then
		echo "Not expected amount of transmitted packets on ${swp2}"
		echo "before ${swp2_tx_packets_before} after ${swp2_tx_packets_after}"
		RET=1
	fi

	# tx/rx_hi counted in bytes. So, we need to compare the difference in bytes
	local swp1_rx_bytes_diff=$(($swp1_rx_bytes_after - $swp1_rx_bytes_before))
	local swp2_tx_bytes_diff=$(($swp2_tx_bytes_after - $swp2_tx_bytes_before))
	local swp1_rx_hi_diff=$(($swp1_rx_hi_after - $swp1_rx_hi_before))
	local swp2_tx_hi_diff=$(($swp2_tx_hi_after - $swp2_tx_hi_before))

	if [ ${expect_rx_high_prio} -eq 1 ]; then
		swp1_rx_hi_diff=$((${swp1_rx_hi_diff} - \
				   ${swp1_rx_packets_diff} * ${ETH_FCS_LEN}))
		if [ ${swp1_rx_hi_diff} -ne ${swp1_rx_bytes_diff} ]; then
			echo "Not expected amount of high priority packets received on ${swp1}"
			echo "RX hi diff: ${swp1_rx_hi_diff}, expected RX bytes diff: ${swp1_rx_bytes_diff}"
			RET=1
		fi
	else
		if [ ${swp1_rx_hi_diff} -ne 0 ]; then
			echo "Unexpected amount of high priority packets received on ${swp1}"
			echo "RX hi diff: ${swp1_rx_hi_diff}, expected 0"
			RET=1
		fi
	fi

	if [ ${expect_tx_high_prio} -eq 1 ]; then
		swp2_tx_hi_diff=$((${swp2_tx_hi_diff} - \
				   ${swp2_tx_packets_diff} * ${ETH_FCS_LEN}))
		if [ ${swp2_tx_hi_diff} -ne ${swp2_tx_bytes_diff} ]; then
			echo "Not expected amount of high priority packets transmitted on ${swp2}"
			echo "TX hi diff: ${swp2_tx_hi_diff}, expected TX bytes diff: ${swp2_tx_bytes_diff}"
			RET=1
		fi
	else
		if [ ${swp2_tx_hi_diff} -ne 0 ]; then
			echo "Unexpected amount of high priority packets transmitted on ${swp2}"
			echo "TX hi diff: ${swp2_tx_hi_diff}, expected 0"
			RET=1
		fi
	fi

	log_test "${test_name}"
}

run_test_dscp()
{
	# IPv4 test
	run_test "$1" "$2" "$3" "$4" "$5" 0 0 0 0
	# IPv6 test
	run_test "$1" "$2" "$3" "$4" "$5" 0 0 0 1
}

run_test_dscp_pcp()
{
	# IPv4 test
	run_test "$1" "$2" "$3" "$4" "$5" 1 "$6" "$7" 0
	# IPv6 test
	run_test "$1" "$2" "$3" "$4" "$5" 1 "$6" "$7" 1
}

port_default_prio_get()
{
	local if_name=$1
	local prio

	prio="$(dcb -j app show dev ${if_name} default-prio | \
		jq '.default_prio[]')"
	if [ -z "${prio}" ]; then
		prio=0
	fi

	echo ${prio}
}

test_port_default()
{
	local orig_apptrust=$(port_get_default_apptrust ${swp1})
	local orig_prio=$(port_default_prio_get ${swp1})
	local apptrust_order=""

	RET=0

	# Make sure no other priority sources will interfere with the test
	set_apptrust_order ${swp1} "${apptrust_order}"

	for val in $(seq 0 7); do
		dcb app replace dev ${swp1} default-prio ${val}
		if [ $val -ne $(port_default_prio_get ${swp1}) ]; then
			RET=1
			break
		fi

		run_test_dscp "Port-default QoS classification, prio: ${val}" \
			"${apptrust_order}" ${val} 0 0
	done

	set_apptrust_order ${swp1} "${orig_apptrust}"
	if [[ "$orig_apptrust" != "$(port_get_default_apptrust ${swp1})" ]]; then
		RET=1
	fi

	dcb app replace dev ${swp1} default-prio ${orig_prio}
	if [ $orig_prio -ne $(port_default_prio_get ${swp1}) ]; then
		RET=1
	fi

	log_test "Port-default QoS classification"
}

port_get_default_apptrust()
{
	local if_name=$1

	dcb -j apptrust show dev ${if_name} | jq -r '.order[]' | \
		tr '\n' ' ' | xargs
}

test_port_apptrust()
{
	local original_dscp_prios_swp1=$(get_dscp_prios ${swp1})
	local orig_apptrust=$(port_get_default_apptrust ${swp1})
	local orig_port_prio=$(port_default_prio_get ${swp1})
	local order_variants=("pcp dscp" "dscp" "pcp")
	local apptrust_order
	local port_prio
	local dscp_prio
	local pcp_prio
	local dscp
	local pcp

	RET=0

	# First, test if apptrust configuration as taken by the kernel
	for order in "${order_variants[@]}"; do
		set_apptrust_order ${swp1} "${order}"
		if [[ "$order" != "$(port_get_default_apptrust ${swp1})" ]]; then
			RET=1
			break
		fi
	done

	log_test "Apptrust, supported variants"

	# To test if the apptrust configuration is working as expected, we need
	# to set DSCP priorities for the switch port.
	init_dscp_prios "${swp1}" "${original_dscp_prios_swp1}"

	# Start with a simple test where all apptrust sources are disabled
	# default port priority is 0, DSCP priority is mapped to 7.
	# No high priority packets should be received or transmitted.
	port_prio=0
	dscp_prio=7
	dscp=4

	dcb app replace dev ${swp1} default-prio ${port_prio}
	dcb app replace dev ${swp1} dscp-prio ${dscp}:${dscp_prio}

	apptrust_order=""
	set_apptrust_order ${swp1} "${apptrust_order}"
	# Test with apptrust sources disabled, Packets should get port default
	# priority which is 0
	run_test_dscp "Apptrust, all disabled. DSCP-prio ${dscp}:${dscp_prio}" \
		"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}

	apptrust_order="pcp"
	set_apptrust_order ${swp1} "${apptrust_order}"
	# If PCP is enabled, packets should get PCP priority, which is not
	# set in this test (no VLAN tags are present in the packet). No high
	# priority packets should be received or transmitted.
	run_test_dscp "Apptrust, PCP enabled. DSCP-prio ${dscp}:${dscp_prio}" \
		"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}

	apptrust_order="dscp"
	set_apptrust_order ${swp1} "${apptrust_order}"
	# If DSCP is enabled, packets should get DSCP priority which is set to 7
	# in this test. High priority packets should be received and transmitted.
	run_test_dscp "Apptrust, DSCP enabled. DSCP-prio ${dscp}:${dscp_prio}" \
		"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}

	apptrust_order="pcp dscp"
	set_apptrust_order ${swp1} "${apptrust_order}"
	# If PCP and DSCP are enabled, PCP would have higher apptrust priority
	# so packets should get PCP priority. But in this test VLAN PCP is not
	# set, so it should get DSCP priority which is set to 7. High priority
	# packets should be received and transmitted.
	run_test_dscp "Apptrust, PCP and DSCP are enabled. DSCP-prio ${dscp}:${dscp_prio}" \
		"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}

	# If VLAN PCP is set, it should have higher apptrust priority than DSCP
	# so packets should get VLAN PCP priority. Send packets with VLAN PCP
	# set to 0, DSCP set to 7. Packets should get VLAN PCP priority.
	# No high priority packets should be transmitted. Due to nature of the
	# switch, high priority packets will be received.
	pcp_prio=0
	pcp=0
	run_test_dscp_pcp "Apptrust, PCP and DSCP are enabled. PCP ${pcp_prio}, DSCP-prio ${dscp}:${dscp_prio}" \
		"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp} ${pcp_prio} ${pcp}

	# If VLAN PCP is set to 7, it should have higher apptrust priority than
	# DSCP so packets should get VLAN PCP priority. Send packets with VLAN
	# PCP set to 7, DSCP set to 7. Packets should get VLAN PCP priority.
	# High priority packets should be received and transmitted.
	pcp_prio=7
	pcp=7
	run_test_dscp_pcp "Apptrust, PCP and DSCP are enabled. PCP ${pcp_prio}, DSCP-prio ${dscp}:${dscp_prio}" \
		"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp} ${pcp_prio} ${pcp}
	# Now make sure that the switch is able to handle the case where DSCP
	# priority is set to 0 and PCP priority is set to 7. Packets should get
	# PCP priority. High priority packets should be received and transmitted.
	dscp_prio=0
	dcb app replace dev ${swp1} dscp-prio ${dscp}:${dscp_prio}
	run_test_dscp_pcp "Apptrust, PCP and DSCP are enabled. PCP ${pcp_prio}, DSCP-prio ${dscp}:${dscp_prio}" \
		"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp} ${pcp_prio} ${pcp}
	# If both VLAN PCP and DSCP are set to 0, packets should get 0 priority.
	# No high priority packets should be received or transmitted.
	pcp_prio=0
	pcp=0
	run_test_dscp_pcp "Apptrust, PCP and DSCP are enabled. PCP ${pcp_prio}, DSCP-prio ${dscp}:${dscp_prio}" \
		"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp} ${pcp_prio} ${pcp}

	# Restore original priorities
	if ! restore_priorities "${swp1}" "${original_dscp_prios_swp1}"; then
		RET=1
	fi

	set_apptrust_order ${swp1} "${orig_apptrust}"
	if [ "$orig_apptrust" != "$(port_get_default_apptrust ${swp1})" ]; then
		RET=1
	fi

	dcb app replace dev ${swp1} default-prio ${orig_port_prio}
	if [ $orig_port_prio -ne $(port_default_prio_get ${swp1}) ]; then
		RET=1
	fi

	log_test "Apptrust, restore original settings"
}

# Function to get current DSCP priorities
get_dscp_prios() {
	local if_name=$1
	dcb -j app show dev ${if_name} | jq -c '.dscp_prio'
}

# Function to set a specific DSCP priority on a device
replace_dscp_prio() {
	local if_name=$1
	local dscp=$2
	local prio=$3
	dcb app replace dev ${if_name} dscp-prio ${dscp}:${prio}
}

# Function to compare DSCP maps
compare_dscp_maps() {
	local old_json=$1
	local new_json=$2
	local dscp=$3
	local prio=$4

	# Create a modified old_json with the expected change for comparison
	local modified_old_json=$(echo "$old_json" |
		jq --argjson dscp $dscp --argjson prio $prio \
			'map(if .[0] == $dscp then [$dscp, $prio] else . end)' |
		tr -d " \n")

	# Compare new_json with the modified_old_json
	if [[ "$modified_old_json" == "$new_json" ]]; then
		return 0
	else
		return 1
	fi
}

# Function to set DSCP priorities
set_and_verify_dscp() {
	local port=$1
	local dscp=$2
	local new_prio=$3

	local old_prios=$(get_dscp_prios $port)

	replace_dscp_prio "$port" $dscp $new_prio

	# Fetch current settings and compare
	local current_prios=$(get_dscp_prios $port)
	if ! compare_dscp_maps "$old_prios" "$current_prios" $dscp $new_prio; then
		echo "Error: Unintended changes detected in DSCP map for $port after setting DSCP $dscp to $new_prio."
		return 1
	fi
	return 0
}

# Function to restore original priorities
restore_priorities() {
	local port=$1
	local original_prios=$2

	echo "Removing test artifacts for $port"
	local current_prios=$(get_dscp_prios $port)
	local prio_str=$(echo "$current_prios" |
		jq -r 'map("\(.[0]):\(.[1])") | join(" ")')
	dcb app del dev $port dscp-prio $prio_str

	echo "Restoring original DSCP priorities for $port"
	local restore_str=$(echo "$original_prios" |
		jq -r 'map("\(.[0]):\(.[1])") | join(" ")')
	dcb app add dev $port dscp-prio $restore_str

	local current_prios=$(get_dscp_prios $port)
	if [[ "$original_prios" != "$current_prios" ]]; then
		echo "Error: Failed to restore original DSCP priorities for $port"
		return 1
	fi
	return 0
}

# Initialize DSCP priorities. Set them to predictable values for testing.
init_dscp_prios() {
	local port=$1
	local original_prios=$2

	echo "Removing any existing DSCP priority mappins for $port"
	local prio_str=$(echo "$original_prios" |
		jq -r 'map("\(.[0]):\(.[1])") | join(" ")')
	dcb app del dev $port dscp-prio $prio_str

	# Initialize DSCP priorities list
	local dscp_prios=""
	for dscp in {0..63}; do
		dscp_prios+=("$dscp:0")
	done

	echo "Setting initial DSCP priorities map to 0 for $port"
	dcb app add dev $port dscp-prio ${dscp_prios[@]}
}

# Main function to test global DSCP map across specified ports
test_global_dscp_map() {
	local ports=("$swp1" "$swp2")
	local original_dscp_prios_port0=$(get_dscp_prios ${ports[0]})
	local orig_apptrust=$(port_get_default_apptrust ${swp1})
	local orig_port_prio=$(port_default_prio_get ${swp1})
	local apptrust_order="dscp"
	local port_prio=0
	local dscp_prio
	local dscp

	RET=0

	set_apptrust_order ${swp1} "${apptrust_order}"
	dcb app replace dev ${swp1} default-prio ${port_prio}

	# Initialize DSCP priorities
	init_dscp_prios "${ports[0]}" "$original_dscp_prios_port0"

	# Loop over each DSCP index
	for dscp in {0..63}; do
		# and test each Internal Priority value
		for dscp_prio in {0..7}; do
			# do it for each port. This is to test if the global DSCP map
			# is accessible from all ports.
			for port in "${ports[@]}"; do
				if ! set_and_verify_dscp "$port" $dscp $dscp_prio; then
					RET=1
				fi
			done

			# Test if the DSCP priority is correctly applied to the packets
			run_test_dscp "DSCP (${dscp}) QoS classification, prio: ${dscp_prio}" \
				"${apptrust_order}" ${port_prio} ${dscp_prio} ${dscp}
			if [ ${RET} -eq 1 ]; then
				break
			fi
		done
	done

	# Restore original priorities
	if ! restore_priorities "${ports[0]}" "${original_dscp_prios_port0}"; then
		RET=1
	fi

	set_apptrust_order ${swp1} "${orig_apptrust}"
	if [[ "$orig_apptrust" != "$(port_get_default_apptrust ${swp1})" ]]; then
		RET=1
	fi

	dcb app replace dev ${swp1} default-prio ${orig_port_prio}
	if [ $orig_port_prio -ne $(port_default_prio_get ${swp1}) ]; then
		RET=1
	fi

	log_test "DSCP global map"
}

trap cleanup EXIT

ALL_TESTS="
	test_port_default
	test_port_apptrust
	test_global_dscp_map
"

setup_prepare
setup_wait
tests_run

exit $EXIT_STATUS