summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/net/toeplitz.sh
blob: da5bfd834effed7654617a6e425ca41265319c66 (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
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# extended toeplitz test: test rxhash plus, optionally, either (1) rss mapping
# from rxhash to rx queue ('-rss') or (2) rps mapping from rxhash to cpu
# ('-rps <rps_map>')
#
# irq-pattern-prefix can be derived from /sys/kernel/irq/*/action,
# which is a driver-specific encoding.
#
# invoke as ./toeplitz.sh (-i <iface>) -u|-t -4|-6 \
# [(-rss -irq_prefix <irq-pattern-prefix>)|(-rps <rps_map>)]

source setup_loopback.sh
readonly SERVER_IP4="192.168.1.200/24"
readonly SERVER_IP6="fda8::1/64"
readonly SERVER_MAC="aa:00:00:00:00:02"

readonly CLIENT_IP4="192.168.1.100/24"
readonly CLIENT_IP6="fda8::2/64"
readonly CLIENT_MAC="aa:00:00:00:00:01"

PORT=8000
KEY="$(</proc/sys/net/core/netdev_rss_key)"
TEST_RSS=false
RPS_MAP=""
PROTO_FLAG=""
IP_FLAG=""
DEV="eth0"

# Return the number of rxqs among which RSS is configured to spread packets.
# This is determined by reading the RSS indirection table using ethtool.
get_rss_cfg_num_rxqs() {
	echo $(ethtool -x "${DEV}" |
		grep -E [[:space:]]+[0-9]+:[[:space:]]+ |
		cut -d: -f2- |
		awk '{$1=$1};1' |
		tr ' ' '\n' |
		sort -u |
		wc -l)
}

# Return a list of the receive irq handler cpus.
# The list is ordered by the irqs, so first rxq-0 cpu, then rxq-1 cpu, etc.
# Reads /sys/kernel/irq/ in order, so algorithm depends on
# irq_{rxq-0} < irq_{rxq-1}, etc.
get_rx_irq_cpus() {
	CPUS=""
	# sort so that irq 2 is read before irq 10
	SORTED_IRQS=$(for i in /sys/kernel/irq/*; do echo $i; done | sort -V)
	# Consider only as many queues as RSS actually uses. We assume that
	# if RSS_CFG_NUM_RXQS=N, then RSS uses rxqs 0-(N-1).
	RSS_CFG_NUM_RXQS=$(get_rss_cfg_num_rxqs)
	RXQ_COUNT=0

	for i in ${SORTED_IRQS}
	do
		[[ "${RXQ_COUNT}" -lt "${RSS_CFG_NUM_RXQS}" ]] || break
		# lookup relevant IRQs by action name
		[[ -e "$i/actions" ]] || continue
		cat "$i/actions" | grep -q "${IRQ_PATTERN}" || continue
		irqname=$(<"$i/actions")

		# does the IRQ get called
		irqcount=$(cat "$i/per_cpu_count" | tr -d '0,')
		[[ -n "${irqcount}" ]] || continue

		# lookup CPU
		irq=$(basename "$i")
		cpu=$(cat "/proc/irq/$irq/smp_affinity_list")

		if [[ -z "${CPUS}" ]]; then
			CPUS="${cpu}"
		else
			CPUS="${CPUS},${cpu}"
		fi
		RXQ_COUNT=$((RXQ_COUNT+1))
	done

	echo "${CPUS}"
}

get_disable_rfs_cmd() {
	echo "echo 0 > /proc/sys/net/core/rps_sock_flow_entries;"
}

get_set_rps_bitmaps_cmd() {
	CMD=""
	for i in /sys/class/net/${DEV}/queues/rx-*/rps_cpus
	do
		CMD="${CMD} echo $1 > ${i};"
	done

	echo "${CMD}"
}

get_disable_rps_cmd() {
	echo "$(get_set_rps_bitmaps_cmd 0)"
}

die() {
	echo "$1"
	exit 1
}

check_nic_rxhash_enabled() {
	local -r pattern="receive-hashing:\ on"

	ethtool -k "${DEV}" | grep -q "${pattern}" || die "rxhash must be enabled"
}

parse_opts() {
	local prog=$0
	shift 1

	while [[ "$1" =~ "-" ]]; do
		if [[ "$1" = "-irq_prefix" ]]; then
			shift
			IRQ_PATTERN="^$1-[0-9]*$"
		elif [[ "$1" = "-u" || "$1" = "-t" ]]; then
			PROTO_FLAG="$1"
		elif [[ "$1" = "-4" ]]; then
			IP_FLAG="$1"
			SERVER_IP="${SERVER_IP4}"
			CLIENT_IP="${CLIENT_IP4}"
		elif [[ "$1" = "-6" ]]; then
			IP_FLAG="$1"
			SERVER_IP="${SERVER_IP6}"
			CLIENT_IP="${CLIENT_IP6}"
		elif [[ "$1" = "-rss" ]]; then
			TEST_RSS=true
		elif [[ "$1" = "-rps" ]]; then
			shift
			RPS_MAP="$1"
		elif [[ "$1" = "-i" ]]; then
			shift
			DEV="$1"
		else
			die "Usage: ${prog} (-i <iface>) -u|-t -4|-6 \
			     [(-rss -irq_prefix <irq-pattern-prefix>)|(-rps <rps_map>)]"
		fi
		shift
	done
}

setup() {
	setup_loopback_environment "${DEV}"

	# Set up server_ns namespace and client_ns namespace
	setup_macvlan_ns "${DEV}" server_ns server \
	"${SERVER_MAC}" "${SERVER_IP}"
	setup_macvlan_ns "${DEV}" client_ns client \
	"${CLIENT_MAC}" "${CLIENT_IP}"
}

cleanup() {
	cleanup_macvlan_ns server_ns server client_ns client
	cleanup_loopback "${DEV}"
}

parse_opts $0 $@

setup
trap cleanup EXIT

check_nic_rxhash_enabled

# Actual test starts here
if [[ "${TEST_RSS}" = true ]]; then
	# RPS/RFS must be disabled because they move packets between cpus,
	# which breaks the PACKET_FANOUT_CPU identification of RSS decisions.
	eval "$(get_disable_rfs_cmd) $(get_disable_rps_cmd)" \
	  ip netns exec server_ns ./toeplitz "${IP_FLAG}" "${PROTO_FLAG}" \
	  -d "${PORT}" -i "${DEV}" -k "${KEY}" -T 1000 \
	  -C "$(get_rx_irq_cpus)" -s -v &
elif [[ ! -z "${RPS_MAP}" ]]; then
	eval "$(get_disable_rfs_cmd) $(get_set_rps_bitmaps_cmd ${RPS_MAP})" \
	  ip netns exec server_ns ./toeplitz "${IP_FLAG}" "${PROTO_FLAG}" \
	  -d "${PORT}" -i "${DEV}" -k "${KEY}" -T 1000 \
	  -r "0x${RPS_MAP}" -s -v &
else
	ip netns exec server_ns ./toeplitz "${IP_FLAG}" "${PROTO_FLAG}" \
	  -d "${PORT}" -i "${DEV}" -k "${KEY}" -T 1000 -s -v &
fi

server_pid=$!

ip netns exec client_ns ./toeplitz_client.sh "${PROTO_FLAG}" \
  "${IP_FLAG}" "${SERVER_IP%%/*}" "${PORT}" &

client_pid=$!

wait "${server_pid}"
exit_code=$?
kill -9 "${client_pid}"
if [[ "${exit_code}" -eq 0 ]]; then
	echo "Test Succeeded!"
fi
exit "${exit_code}"