cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

psfp.sh (7083B)


      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
      8WAIT_TIME=1
      9NUM_NETIFS=4
     10STABLE_MAC_ADDRS=yes
     11NETIF_CREATE=no
     12lib_dir=$(dirname $0)/../../../net/forwarding
     13source $lib_dir/tc_common.sh
     14source $lib_dir/lib.sh
     15source $lib_dir/tsn_lib.sh
     16
     17UDS_ADDRESS_H1="/var/run/ptp4l_h1"
     18UDS_ADDRESS_SWP1="/var/run/ptp4l_swp1"
     19
     20# Tunables
     21NUM_PKTS=1000
     22STREAM_VID=100
     23STREAM_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
     26CYCLE_TIME_NS=10000000
     27# Create two Gate Control List entries, one OPEN and one CLOSE, of equal
     28# durations
     29GATE_DURATION_NS=$((${CYCLE_TIME_NS} / 2))
     30# Give 2/3 of the cycle time to user space and 1/3 to the kernel
     31FUDGE_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
     35SHIFT_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 for
     48# Per-Stream Filtering and Policing filters
     49PSFP()
     50{
     51	echo 30000
     52}
     53
     54psfp_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
     64psfp_chain_destroy()
     65{
     66	local if_name=$1
     67
     68	tc qdisc del dev $if_name clsact
     69}
     70
     71psfp_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
     90h1_create()
     91{
     92	simple_if_init $h1 $H1_IPV4/24 $H1_IPV6/64
     93}
     94
     95h1_destroy()
     96{
     97	simple_if_fini $h1 $H1_IPV4/24 $H1_IPV6/64
     98}
     99
    100h2_create()
    101{
    102	simple_if_init $h2 $H2_IPV4/24 $H2_IPV6/64
    103}
    104
    105h2_destroy()
    106{
    107	simple_if_fini $h2 $H2_IPV4/24 $H2_IPV6/64
    108}
    109
    110switch_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
    139switch_destroy()
    140{
    141	psfp_chain_destroy ${swp1}
    142	ip link del br0
    143}
    144
    145txtime_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
    164txtime_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
    172setup_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 ${swp1} ${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
    196cleanup()
    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
    214debug_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
    238debug_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
    251run_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		"${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 timestamps
    276	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}" ]; then
    282		RET=0
    283	else
    284		RET=1
    285		echo "Expected isochron to receive ${expected} packets but received ${received}"
    286	fi
    287
    288	log_test "${test_name}"
    289
    290	if [ "$RET" = "1" ]; then
    291		${debug} "${isochron_dat}"
    292	fi
    293
    294	rm ${isochron_dat} 2> /dev/null
    295}
    296
    297test_gate_in_band()
    298{
    299	# Send packets in-band with the OPEN gate entry
    300	run_test 0.000000000 ${NUM_PKTS} "In band" \
    301		debug_incorrectly_dropped_packets
    302
    303	psfp_filter_check ${NUM_PKTS}
    304}
    305
    306test_gate_out_of_band()
    307{
    308	# Send packets in-band with the CLOSE gate entry
    309	run_test 0.005000000 0 "Out of band" \
    310		debug_incorrectly_received_packets
    311
    312	psfp_filter_check $((2 * ${NUM_PKTS}))
    313}
    314
    315trap cleanup EXIT
    316
    317ALL_TESTS="
    318	test_gate_in_band
    319	test_gate_out_of_band
    320"
    321
    322setup_prepare
    323setup_wait
    324
    325tests_run
    326
    327exit $EXIT_STATUS