toeplitz.sh 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. #
  4. # extended toeplitz test: test rxhash plus, optionally, either (1) rss mapping
  5. # from rxhash to rx queue ('-rss') or (2) rps mapping from rxhash to cpu
  6. # ('-rps <rps_map>')
  7. #
  8. # irq-pattern-prefix can be derived from /sys/kernel/irq/*/action,
  9. # which is a driver-specific encoding.
  10. #
  11. # invoke as ./toeplitz.sh (-i <iface>) -u|-t -4|-6 \
  12. # [(-rss -irq_prefix <irq-pattern-prefix>)|(-rps <rps_map>)]
  13. source setup_loopback.sh
  14. readonly SERVER_IP4="192.168.1.200/24"
  15. readonly SERVER_IP6="fda8::1/64"
  16. readonly SERVER_MAC="aa:00:00:00:00:02"
  17. readonly CLIENT_IP4="192.168.1.100/24"
  18. readonly CLIENT_IP6="fda8::2/64"
  19. readonly CLIENT_MAC="aa:00:00:00:00:01"
  20. PORT=8000
  21. KEY="$(</proc/sys/net/core/netdev_rss_key)"
  22. TEST_RSS=false
  23. RPS_MAP=""
  24. PROTO_FLAG=""
  25. IP_FLAG=""
  26. DEV="eth0"
  27. # Return the number of rxqs among which RSS is configured to spread packets.
  28. # This is determined by reading the RSS indirection table using ethtool.
  29. get_rss_cfg_num_rxqs() {
  30. echo $(ethtool -x "${DEV}" |
  31. grep -E [[:space:]]+[0-9]+:[[:space:]]+ |
  32. cut -d: -f2- |
  33. awk '{$1=$1};1' |
  34. tr ' ' '\n' |
  35. sort -u |
  36. wc -l)
  37. }
  38. # Return a list of the receive irq handler cpus.
  39. # The list is ordered by the irqs, so first rxq-0 cpu, then rxq-1 cpu, etc.
  40. # Reads /sys/kernel/irq/ in order, so algorithm depends on
  41. # irq_{rxq-0} < irq_{rxq-1}, etc.
  42. get_rx_irq_cpus() {
  43. CPUS=""
  44. # sort so that irq 2 is read before irq 10
  45. SORTED_IRQS=$(for i in /sys/kernel/irq/*; do echo $i; done | sort -V)
  46. # Consider only as many queues as RSS actually uses. We assume that
  47. # if RSS_CFG_NUM_RXQS=N, then RSS uses rxqs 0-(N-1).
  48. RSS_CFG_NUM_RXQS=$(get_rss_cfg_num_rxqs)
  49. RXQ_COUNT=0
  50. for i in ${SORTED_IRQS}
  51. do
  52. [[ "${RXQ_COUNT}" -lt "${RSS_CFG_NUM_RXQS}" ]] || break
  53. # lookup relevant IRQs by action name
  54. [[ -e "$i/actions" ]] || continue
  55. cat "$i/actions" | grep -q "${IRQ_PATTERN}" || continue
  56. irqname=$(<"$i/actions")
  57. # does the IRQ get called
  58. irqcount=$(cat "$i/per_cpu_count" | tr -d '0,')
  59. [[ -n "${irqcount}" ]] || continue
  60. # lookup CPU
  61. irq=$(basename "$i")
  62. cpu=$(cat "/proc/irq/$irq/smp_affinity_list")
  63. if [[ -z "${CPUS}" ]]; then
  64. CPUS="${cpu}"
  65. else
  66. CPUS="${CPUS},${cpu}"
  67. fi
  68. RXQ_COUNT=$((RXQ_COUNT+1))
  69. done
  70. echo "${CPUS}"
  71. }
  72. get_disable_rfs_cmd() {
  73. echo "echo 0 > /proc/sys/net/core/rps_sock_flow_entries;"
  74. }
  75. get_set_rps_bitmaps_cmd() {
  76. CMD=""
  77. for i in /sys/class/net/${DEV}/queues/rx-*/rps_cpus
  78. do
  79. CMD="${CMD} echo $1 > ${i};"
  80. done
  81. echo "${CMD}"
  82. }
  83. get_disable_rps_cmd() {
  84. echo "$(get_set_rps_bitmaps_cmd 0)"
  85. }
  86. die() {
  87. echo "$1"
  88. exit 1
  89. }
  90. check_nic_rxhash_enabled() {
  91. local -r pattern="receive-hashing:\ on"
  92. ethtool -k "${DEV}" | grep -q "${pattern}" || die "rxhash must be enabled"
  93. }
  94. parse_opts() {
  95. local prog=$0
  96. shift 1
  97. while [[ "$1" =~ "-" ]]; do
  98. if [[ "$1" = "-irq_prefix" ]]; then
  99. shift
  100. IRQ_PATTERN="^$1-[0-9]*$"
  101. elif [[ "$1" = "-u" || "$1" = "-t" ]]; then
  102. PROTO_FLAG="$1"
  103. elif [[ "$1" = "-4" ]]; then
  104. IP_FLAG="$1"
  105. SERVER_IP="${SERVER_IP4}"
  106. CLIENT_IP="${CLIENT_IP4}"
  107. elif [[ "$1" = "-6" ]]; then
  108. IP_FLAG="$1"
  109. SERVER_IP="${SERVER_IP6}"
  110. CLIENT_IP="${CLIENT_IP6}"
  111. elif [[ "$1" = "-rss" ]]; then
  112. TEST_RSS=true
  113. elif [[ "$1" = "-rps" ]]; then
  114. shift
  115. RPS_MAP="$1"
  116. elif [[ "$1" = "-i" ]]; then
  117. shift
  118. DEV="$1"
  119. else
  120. die "Usage: ${prog} (-i <iface>) -u|-t -4|-6 \
  121. [(-rss -irq_prefix <irq-pattern-prefix>)|(-rps <rps_map>)]"
  122. fi
  123. shift
  124. done
  125. }
  126. setup() {
  127. setup_loopback_environment "${DEV}"
  128. # Set up server_ns namespace and client_ns namespace
  129. setup_macvlan_ns "${DEV}" server_ns server \
  130. "${SERVER_MAC}" "${SERVER_IP}"
  131. setup_macvlan_ns "${DEV}" client_ns client \
  132. "${CLIENT_MAC}" "${CLIENT_IP}"
  133. }
  134. cleanup() {
  135. cleanup_macvlan_ns server_ns server client_ns client
  136. cleanup_loopback "${DEV}"
  137. }
  138. parse_opts $0 $@
  139. setup
  140. trap cleanup EXIT
  141. check_nic_rxhash_enabled
  142. # Actual test starts here
  143. if [[ "${TEST_RSS}" = true ]]; then
  144. # RPS/RFS must be disabled because they move packets between cpus,
  145. # which breaks the PACKET_FANOUT_CPU identification of RSS decisions.
  146. eval "$(get_disable_rfs_cmd) $(get_disable_rps_cmd)" \
  147. ip netns exec server_ns ./toeplitz "${IP_FLAG}" "${PROTO_FLAG}" \
  148. -d "${PORT}" -i "${DEV}" -k "${KEY}" -T 1000 \
  149. -C "$(get_rx_irq_cpus)" -s -v &
  150. elif [[ ! -z "${RPS_MAP}" ]]; then
  151. eval "$(get_disable_rfs_cmd) $(get_set_rps_bitmaps_cmd ${RPS_MAP})" \
  152. ip netns exec server_ns ./toeplitz "${IP_FLAG}" "${PROTO_FLAG}" \
  153. -d "${PORT}" -i "${DEV}" -k "${KEY}" -T 1000 \
  154. -r "0x${RPS_MAP}" -s -v &
  155. else
  156. ip netns exec server_ns ./toeplitz "${IP_FLAG}" "${PROTO_FLAG}" \
  157. -d "${PORT}" -i "${DEV}" -k "${KEY}" -T 1000 -s -v &
  158. fi
  159. server_pid=$!
  160. ip netns exec client_ns ./toeplitz_client.sh "${PROTO_FLAG}" \
  161. "${IP_FLAG}" "${SERVER_IP%%/*}" "${PORT}" &
  162. client_pid=$!
  163. wait "${server_pid}"
  164. exit_code=$?
  165. kill -9 "${client_pid}"
  166. if [[ "${exit_code}" -eq 0 ]]; then
  167. echo "Test Succeeded!"
  168. fi
  169. exit "${exit_code}"