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

Merge branch 'netdevsim-support-setting-a-permanent-address'

Toke Høiland-Jørgensen says:

====================
netdevsim: support setting a permanent address

Network management daemons that match on the device permanent address
currently have no virtual interface types to test against.
NetworkManager, in particular, has carried an out of tree patch to set
the permanent address on netdevsim devices to use in its CI for this
purpose.

This series adds support to netdevsim to set a permanent address on port
creation, and adds a test script to test setting and getting of the
different L2 address types.

v3: https://lore.kernel.org/20250706-netdevsim-perm_addr-v3-0-88123e2b2027@redhat.com
v2: https://lore.kernel.org/20250702-netdevsim-perm_addr-v2-0-66359a6288f0@redhat.com
v1: https://lore.kernel.org/20250203-netdevsim-perm_addr-v1-1-10084bc93044@redhat.com
====================

Link: https://patch.msgid.link/20250710-netdevsim-perm_addr-v4-0-c9db2fecf3bf@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+123 -18
+22 -4
drivers/net/netdevsim/bus.c
··· 66 66 const char *buf, size_t count) 67 67 { 68 68 struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 69 + u8 eth_addr[ETH_ALEN] = {}; 69 70 unsigned int port_index; 71 + bool addr_set = false; 70 72 int ret; 71 73 72 74 /* Prevent to use nsim_bus_dev before initialization. */ 73 75 if (!smp_load_acquire(&nsim_bus_dev->init)) 74 76 return -EBUSY; 75 - ret = kstrtouint(buf, 0, &port_index); 76 - if (ret) 77 - return ret; 78 77 79 - ret = nsim_drv_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 78 + ret = sscanf(buf, "%u %hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &port_index, 79 + &eth_addr[0], &eth_addr[1], &eth_addr[2], &eth_addr[3], 80 + &eth_addr[4], &eth_addr[5]); 81 + switch (ret) { 82 + case 7: 83 + if (!is_valid_ether_addr(eth_addr)) { 84 + pr_err("The supplied perm_addr is not a valid MAC address\n"); 85 + return -EINVAL; 86 + } 87 + addr_set = true; 88 + fallthrough; 89 + case 1: 90 + break; 91 + default: 92 + pr_err("Format for adding new port is \"id [perm_addr]\" (uint MAC).\n"); 93 + return -EINVAL; 94 + } 95 + 96 + ret = nsim_drv_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index, 97 + addr_set ? eth_addr : NULL); 80 98 return ret ? ret : count; 81 99 } 82 100
+7 -7
drivers/net/netdevsim/dev.c
··· 589 589 590 590 static int 591 591 __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 592 - unsigned int port_index); 592 + unsigned int port_index, u8 perm_addr[ETH_ALEN]); 593 593 static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port); 594 594 595 595 static int nsim_esw_legacy_enable(struct nsim_dev *nsim_dev, ··· 613 613 int i, err; 614 614 615 615 for (i = 0; i < nsim_dev_get_vfs(nsim_dev); i++) { 616 - err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_VF, i); 616 + err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_VF, i, NULL); 617 617 if (err) { 618 618 NL_SET_ERR_MSG_MOD(extack, "Failed to initialize VFs' netdevsim ports"); 619 619 pr_err("Failed to initialize VF id=%d. %d.\n", i, err); ··· 1396 1396 #define NSIM_DEV_TEST1_DEFAULT true 1397 1397 1398 1398 static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1399 - unsigned int port_index) 1399 + unsigned int port_index, u8 perm_addr[ETH_ALEN]) 1400 1400 { 1401 1401 struct devlink_port_attrs attrs = {}; 1402 1402 struct nsim_dev_port *nsim_dev_port; ··· 1433 1433 if (err) 1434 1434 goto err_dl_port_unregister; 1435 1435 1436 - nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); 1436 + nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port, perm_addr); 1437 1437 if (IS_ERR(nsim_dev_port->ns)) { 1438 1438 err = PTR_ERR(nsim_dev_port->ns); 1439 1439 goto err_port_debugfs_exit; ··· 1489 1489 int i, err; 1490 1490 1491 1491 for (i = 0; i < port_count; i++) { 1492 - err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i); 1492 + err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i, NULL); 1493 1493 if (err) 1494 1494 goto err_port_del_all; 1495 1495 } ··· 1745 1745 } 1746 1746 1747 1747 int nsim_drv_port_add(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1748 - unsigned int port_index) 1748 + unsigned int port_index, u8 perm_addr[ETH_ALEN]) 1749 1749 { 1750 1750 struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1751 1751 int err; ··· 1754 1754 if (__nsim_dev_port_lookup(nsim_dev, type, port_index)) 1755 1755 err = -EEXIST; 1756 1756 else 1757 - err = __nsim_dev_port_add(nsim_dev, type, port_index); 1757 + err = __nsim_dev_port_add(nsim_dev, type, port_index, perm_addr); 1758 1758 devl_unlock(priv_to_devlink(nsim_dev)); 1759 1759 return err; 1760 1760 }
+6 -3
drivers/net/netdevsim/netdev.c
··· 998 998 mock_phc_destroy(ns->phc); 999 999 } 1000 1000 1001 - struct netdevsim * 1002 - nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port) 1001 + struct netdevsim *nsim_create(struct nsim_dev *nsim_dev, 1002 + struct nsim_dev_port *nsim_dev_port, 1003 + u8 perm_addr[ETH_ALEN]) 1003 1004 { 1004 1005 struct net_device *dev; 1005 1006 struct netdevsim *ns; ··· 1010 1009 nsim_dev->nsim_bus_dev->num_queues); 1011 1010 if (!dev) 1012 1011 return ERR_PTR(-ENOMEM); 1012 + 1013 + if (perm_addr) 1014 + memcpy(dev->perm_addr, perm_addr, ETH_ALEN); 1013 1015 1014 1016 dev_net_set(dev, nsim_dev_net(nsim_dev)); 1015 1017 ns = netdev_priv(dev); ··· 1035 1031 ns->qr_dfs = debugfs_create_file("queue_reset", 0200, 1036 1032 nsim_dev_port->ddir, ns, 1037 1033 &nsim_qreset_fops); 1038 - 1039 1034 return ns; 1040 1035 1041 1036 err_free_netdev:
+5 -4
drivers/net/netdevsim/netdevsim.h
··· 143 143 struct netdev_net_notifier nn; 144 144 }; 145 145 146 - struct netdevsim * 147 - nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port); 146 + struct netdevsim *nsim_create(struct nsim_dev *nsim_dev, 147 + struct nsim_dev_port *nsim_dev_port, 148 + u8 perm_addr[ETH_ALEN]); 148 149 void nsim_destroy(struct netdevsim *ns); 149 150 bool netdev_is_nsim(struct net_device *dev); 150 151 ··· 363 362 int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev); 364 363 void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev); 365 364 int nsim_drv_port_add(struct nsim_bus_dev *nsim_bus_dev, 366 - enum nsim_dev_port_type type, 367 - unsigned int port_index); 365 + enum nsim_dev_port_type type, unsigned int port_index, 366 + u8 perm_addr[ETH_ALEN]); 368 367 int nsim_drv_port_del(struct nsim_bus_dev *nsim_bus_dev, 369 368 enum nsim_dev_port_type type, 370 369 unsigned int port_index);
+1
tools/testing/selftests/net/Makefile
··· 63 63 TEST_PROGS += rps_default_mask.sh 64 64 TEST_PROGS += big_tcp.sh 65 65 TEST_PROGS += netns-sysctl.sh 66 + TEST_PROGS += netdev-l2addr.sh 66 67 TEST_PROGS_EXTENDED := toeplitz_client.sh toeplitz.sh xfrm_policy_add_speed.sh 67 68 TEST_GEN_FILES = socket nettest 68 69 TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any
+23
tools/testing/selftests/net/lib.sh
··· 240 240 echo nsim$id 241 241 } 242 242 243 + create_netdevsim_port() { 244 + local nsim_id="$1" 245 + local ns="$2" 246 + local port_id="$3" 247 + local perm_addr="$4" 248 + local orig_dev 249 + local new_dev 250 + local nsim_path 251 + 252 + nsim_path="/sys/bus/netdevsim/devices/netdevsim$nsim_id" 253 + 254 + echo "$port_id $perm_addr" | ip netns exec "$ns" tee "$nsim_path"/new_port > /dev/null || return 1 255 + 256 + orig_dev=$(ip netns exec "$ns" find "$nsim_path"/net/ -maxdepth 1 -name 'e*' | tail -n 1) 257 + orig_dev=$(basename "$orig_dev") 258 + new_dev="nsim${nsim_id}p$port_id" 259 + 260 + ip -netns "$ns" link set dev "$orig_dev" name "$new_dev" 261 + ip -netns "$ns" link set dev "$new_dev" up 262 + 263 + echo "$new_dev" 264 + } 265 + 243 266 # Remove netdevsim with given id. 244 267 cleanup_netdevsim() { 245 268 local id="$1"
+59
tools/testing/selftests/net/netdev-l2addr.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + source lib.sh 5 + set -o pipefail 6 + 7 + NSIM_ADDR=2025 8 + TEST_ADDR="d0:be:d0:be:d0:00" 9 + 10 + RET_CODE=0 11 + 12 + cleanup() { 13 + cleanup_netdevsim "$NSIM_ADDR" 14 + cleanup_ns "$NS" 15 + } 16 + 17 + trap cleanup EXIT 18 + 19 + fail() { 20 + echo "ERROR: ${1:-unexpected return code} (ret: $_)" >&2 21 + RET_CODE=1 22 + } 23 + 24 + get_addr() 25 + { 26 + local type="$1" 27 + local dev="$2" 28 + local ns="$3" 29 + 30 + ip -j -n "$ns" link show dev "$dev" | jq -er ".[0].$type" 31 + } 32 + 33 + setup_ns NS 34 + 35 + nsim=$(create_netdevsim $NSIM_ADDR "$NS") 36 + 37 + get_addr address "$nsim" "$NS" >/dev/null || fail "Couldn't get ether addr" 38 + get_addr broadcast "$nsim" "$NS" >/dev/null || fail "Couldn't get brd addr" 39 + get_addr permaddr "$nsim" "$NS" >/dev/null && fail "Found perm_addr without setting it" 40 + 41 + ip -n "$NS" link set dev "$nsim" address "$TEST_ADDR" 42 + ip -n "$NS" link set dev "$nsim" brd "$TEST_ADDR" 43 + 44 + [[ "$(get_addr address "$nsim" "$NS")" == "$TEST_ADDR" ]] || fail "Couldn't set ether addr" 45 + [[ "$(get_addr broadcast "$nsim" "$NS")" == "$TEST_ADDR" ]] || fail "Couldn't set brd addr" 46 + 47 + if create_netdevsim_port "$NSIM_ADDR" "$NS" 2 "FF:FF:FF:FF:FF:FF" 2>/dev/null; then 48 + fail "Created netdevsim with broadcast permaddr" 49 + fi 50 + 51 + nsim_port=$(create_netdevsim_port "$NSIM_ADDR" "$NS" 2 "$TEST_ADDR") 52 + 53 + get_addr address "$nsim_port" "$NS" >/dev/null || fail "Couldn't get ether addr" 54 + get_addr broadcast "$nsim_port" "$NS" >/dev/null || fail "Couldn't get brd addr" 55 + [[ "$(get_addr permaddr "$nsim_port" "$NS")" == "$TEST_ADDR" ]] || fail "Couldn't get permaddr" 56 + 57 + cleanup_netdevsim "$NSIM_ADDR" "$NS" 58 + 59 + exit $RET_CODE