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}"
|