Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'selftests-hw-net-toeplitz-read-config-from-the-nic-directly'

Jakub Kicinski says:

====================
selftests: hw-net: toeplitz: read config from the NIC directly

First patch here tries to auto-disable building the iouring sample.
Our CI will still run the iouring test(s), of course, but it looks
like the liburing updates aren't very quick in distroes and having
to hack around it when developing unrelated tests is a bit annoying.

Remaining 4 patches iron out running the Toeplitz hash test against
real NICs. I tested mlx5, bnxt and fbnic, they all pass now.
I switched to using YNL directly in the C code, can't see a reason
to get the info in Python and pass it to C via argv. The old code
likely did this because it predates YNL.
====================

Link: https://patch.msgid.link/20251121040259.3647749-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+98 -18
+20 -3
tools/testing/selftests/drivers/net/hw/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0+ OR MIT 2 2 3 + # Check if io_uring supports zero-copy receive 4 + HAS_IOURING_ZCRX := $(shell \ 5 + echo -e '#include <liburing.h>\n' \ 6 + 'void *func = (void *)io_uring_register_ifq;\n' \ 7 + 'int main() {return 0;}' | \ 8 + $(CC) -luring -x c - -o /dev/null 2>&1 && echo y) 9 + 10 + ifeq ($(HAS_IOURING_ZCRX),y) 11 + COND_GEN_FILES += iou-zcrx 12 + else 13 + $(warning excluding iouring tests, liburing not installed or too old) 14 + endif 15 + 3 16 TEST_GEN_FILES := \ 4 - iou-zcrx \ 5 - toeplitz \ 17 + $(COND_GEN_FILES) \ 6 18 # end of TEST_GEN_FILES 7 19 8 20 TEST_PROGS = \ ··· 54 42 # 55 43 56 44 # YNL files, must be before "include ..lib.mk" 57 - YNL_GEN_FILES := ncdevmem 45 + YNL_GEN_FILES := \ 46 + ncdevmem \ 47 + toeplitz \ 48 + # end of YNL_GEN_FILES 58 49 TEST_GEN_FILES += $(YNL_GEN_FILES) 59 50 TEST_GEN_FILES += $(patsubst %.c,%.o,$(wildcard *.bpf.c)) 60 51 ··· 73 58 74 59 include ../../../net/bpf.mk 75 60 61 + ifeq ($(HAS_IOURING_ZCRX),y) 76 62 $(OUTPUT)/iou-zcrx: LDLIBS += -luring 63 + endif
+63 -2
tools/testing/selftests/drivers/net/hw/toeplitz.c
··· 52 52 #include <sys/types.h> 53 53 #include <unistd.h> 54 54 55 + #include <ynl.h> 56 + #include "ethtool-user.h" 57 + 55 58 #include "../../../kselftest.h" 56 59 #include "../../../net/lib/ksft.h" 57 60 ··· 68 65 #define FOUR_TUPLE_MAX_LEN ((sizeof(struct in6_addr) * 2) + (sizeof(uint16_t) * 2)) 69 66 70 67 #define RSS_MAX_CPUS (1 << 16) /* real constraint is PACKET_FANOUT_MAX */ 68 + #define RSS_MAX_INDIR (1 << 16) 71 69 72 70 #define RPS_MAX_CPUS 16UL /* must be a power of 2 */ 73 71 ··· 106 102 static unsigned int rx_irq_cpus[RSS_MAX_CPUS]; /* map from rxq to cpu */ 107 103 static int rps_silo_to_cpu[RPS_MAX_CPUS]; 108 104 static unsigned char toeplitz_key[TOEPLITZ_KEY_MAX_LEN]; 105 + static unsigned int rss_indir_tbl[RSS_MAX_INDIR]; 106 + static unsigned int rss_indir_tbl_size; 109 107 static struct ring_state rings[RSS_MAX_CPUS]; 110 108 111 109 static inline uint32_t toeplitz(const unsigned char *four_tuple, ··· 136 130 /* Compare computed cpu with arrival cpu from packet_fanout_cpu */ 137 131 static void verify_rss(uint32_t rx_hash, int cpu) 138 132 { 139 - int queue = rx_hash % cfg_num_queues; 133 + int queue; 134 + 135 + if (rss_indir_tbl_size) 136 + queue = rss_indir_tbl[rx_hash % rss_indir_tbl_size]; 137 + else 138 + queue = rx_hash % cfg_num_queues; 140 139 141 140 log_verbose(" rxq %d (cpu %d)", queue, rx_irq_cpus[queue]); 142 141 if (rx_irq_cpus[queue] != cpu) { ··· 494 483 rps_silo_to_cpu[cfg_num_rps_cpus++] = i; 495 484 } 496 485 486 + static void read_rss_dev_info_ynl(void) 487 + { 488 + struct ethtool_rss_get_req *req; 489 + struct ethtool_rss_get_rsp *rsp; 490 + struct ynl_sock *ys; 491 + 492 + ys = ynl_sock_create(&ynl_ethtool_family, NULL); 493 + if (!ys) 494 + error(1, errno, "ynl_sock_create failed"); 495 + 496 + req = ethtool_rss_get_req_alloc(); 497 + if (!req) 498 + error(1, errno, "ethtool_rss_get_req_alloc failed"); 499 + 500 + ethtool_rss_get_req_set_header_dev_name(req, cfg_ifname); 501 + 502 + rsp = ethtool_rss_get(ys, req); 503 + if (!rsp) 504 + error(1, ys->err.code, "YNL: %s", ys->err.msg); 505 + 506 + if (!rsp->_len.hkey) 507 + error(1, 0, "RSS key not available for %s", cfg_ifname); 508 + 509 + if (rsp->_len.hkey < TOEPLITZ_KEY_MIN_LEN || 510 + rsp->_len.hkey > TOEPLITZ_KEY_MAX_LEN) 511 + error(1, 0, "RSS key length %u out of bounds [%u, %u]", 512 + rsp->_len.hkey, TOEPLITZ_KEY_MIN_LEN, 513 + TOEPLITZ_KEY_MAX_LEN); 514 + 515 + memcpy(toeplitz_key, rsp->hkey, rsp->_len.hkey); 516 + 517 + if (rsp->_count.indir > RSS_MAX_INDIR) 518 + error(1, 0, "RSS indirection table too large (%u > %u)", 519 + rsp->_count.indir, RSS_MAX_INDIR); 520 + 521 + /* If indir table not available we'll fallback to simple modulo math */ 522 + if (rsp->_count.indir) { 523 + memcpy(rss_indir_tbl, rsp->indir, 524 + rsp->_count.indir * sizeof(rss_indir_tbl[0])); 525 + rss_indir_tbl_size = rsp->_count.indir; 526 + 527 + log_verbose("RSS indirection table size: %u\n", 528 + rss_indir_tbl_size); 529 + } 530 + 531 + ethtool_rss_get_rsp_free(rsp); 532 + ethtool_rss_get_req_free(req); 533 + ynl_sock_destroy(ys); 534 + } 535 + 497 536 static void parse_opts(int argc, char **argv) 498 537 { 499 538 static struct option long_options[] = { ··· 612 551 } 613 552 614 553 if (!have_toeplitz) 615 - error(1, 0, "Must supply rss key ('-k')"); 554 + read_rss_dev_info_ynl(); 616 555 617 556 num_cpus = get_nprocs(); 618 557 if (num_cpus > RSS_MAX_CPUS)
+15 -13
tools/testing/selftests/drivers/net/hw/toeplitz.py
··· 17 17 from lib.py import ksft_in 18 18 from lib.py import ksft_variants, KsftNamedVariant, KsftSkipEx, KsftFailEx 19 19 20 + # "define" for the ID of the Toeplitz hash function 21 + ETH_RSS_HASH_TOP = 1 22 + 20 23 21 24 def _check_rps_and_rfs_not_configured(cfg): 22 25 """Verify that RPS is not already configured.""" ··· 35 32 val = fp.read().strip() 36 33 if val != "0": 37 34 raise KsftSkipEx(f"RFS already configured {rfs_file}: {val}") 38 - 39 - 40 - def _get_rss_key(cfg): 41 - """ 42 - Read the RSS key from the device. 43 - Return a string in the traditional %02x:%02x:%02x:.. format. 44 - """ 45 - 46 - rss = cfg.ethnl.rss_get({"header": {"dev-index": cfg.ifindex}}) 47 - return ':'.join(f'{b:02x}' for b in rss["hkey"]) 48 35 49 36 50 37 def _get_cpu_for_irq(irq): ··· 146 153 # Check that rxhash is enabled 147 154 ksft_in("receive-hashing: on", cmd(f"ethtool -k {cfg.ifname}").stdout) 148 155 156 + rss = cfg.ethnl.rss_get({"header": {"dev-index": cfg.ifindex}}) 157 + # Make sure NIC is configured to use Toeplitz hash, and no key xfrm. 158 + if rss.get('hfunc') != ETH_RSS_HASH_TOP or rss.get('input-xfrm'): 159 + cfg.ethnl.rss_set({"header": {"dev-index": cfg.ifindex}, 160 + "hfunc": ETH_RSS_HASH_TOP, 161 + "input-xfrm": {}}) 162 + defer(cfg.ethnl.rss_set, {"header": {"dev-index": cfg.ifindex}, 163 + "hfunc": rss.get('hfunc'), 164 + "input-xfrm": rss.get('input-xfrm', {}) 165 + }) 166 + 149 167 port = rand_port(socket.SOCK_DGRAM) 150 - key = _get_rss_key(cfg) 151 168 152 169 toeplitz_path = cfg.test_dir / "toeplitz" 153 170 rx_cmd = [ ··· 166 163 proto_flag, 167 164 "-d", str(port), 168 165 "-i", cfg.ifname, 169 - "-k", key, 170 - "-T", "1000", 166 + "-T", "4000", 171 167 "-s", 172 168 "-v" 173 169 ]