aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools/testing/selftests/drivers
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-04-14 11:54:21 -0700
committerJakub Kicinski <kuba@kernel.org>2026-04-14 12:04:00 -0700
commit35c2c39832e569449b9192fa1afbbc4c66227af7 (patch)
tree35b026a5e0bda47904dd6e52ff970bc933b9c916 /tools/testing/selftests/drivers
parentnet: pse-pd: fix kernel-doc function name for pse_control_find_by_id() (diff)
parentnet: airoha: Add missing PPE configurations in airoha_ppe_hw_init() (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netdeveldavem/net-next
Merge in late fixes in preparation for the net-next PR. Conflicts: include/net/sch_generic.h a6bd339dbb351 ("net_sched: fix skb memory leak in deferred qdisc drops") ff2998f29f390 ("net: sched: introduce qdisc-specific drop reason tracing") https://lore.kernel.org/adz0iX85FHMz0HdO@sirena.org.uk drivers/net/ethernet/airoha/airoha_eth.c 1acdfbdb516b ("net: airoha: Fix VIP configuration for AN7583 SoC") bf3471e6e6c0 ("net: airoha: Make flow control source port mapping dependent on nbq parameter") Adjacent changes: drivers/net/ethernet/airoha/airoha_ppe.c f44218cd5e6a ("net: airoha: Reset PPE cpu port configuration in airoha_ppe_hw_init()") 7da62262ec96 ("inet: add ip_local_port_step_width sysctl to improve port usage distribution") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'tools/testing/selftests/drivers')
-rw-r--r--tools/testing/selftests/drivers/net/Makefile1
-rw-r--r--tools/testing/selftests/drivers/net/config2
-rw-r--r--tools/testing/selftests/drivers/net/lib/py/env.py9
-rwxr-xr-xtools/testing/selftests/drivers/net/macsec.py343
-rw-r--r--tools/testing/selftests/drivers/net/netdevsim/Makefile1
-rwxr-xr-xtools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh117
6 files changed, 355 insertions, 118 deletions
diff --git a/tools/testing/selftests/drivers/net/Makefile b/tools/testing/selftests/drivers/net/Makefile
index 7c7fa75b80c2..b72080c6d06b 100644
--- a/tools/testing/selftests/drivers/net/Makefile
+++ b/tools/testing/selftests/drivers/net/Makefile
@@ -12,6 +12,7 @@ TEST_GEN_FILES := \
TEST_PROGS := \
gro.py \
hds.py \
+ macsec.py \
napi_id.py \
napi_threaded.py \
netpoll_basic.py \
diff --git a/tools/testing/selftests/drivers/net/config b/tools/testing/selftests/drivers/net/config
index 77ccf83d87e0..fd16994366f4 100644
--- a/tools/testing/selftests/drivers/net/config
+++ b/tools/testing/selftests/drivers/net/config
@@ -3,8 +3,10 @@ CONFIG_DEBUG_INFO_BTF=y
CONFIG_DEBUG_INFO_BTF_MODULES=n
CONFIG_INET_PSP=y
CONFIG_IPV6=y
+CONFIG_MACSEC=m
CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_NETCONSOLE_EXTENDED_LOG=y
CONFIG_NETDEVSIM=m
+CONFIG_VLAN_8021Q=m
CONFIG_XDP_SOCKETS=y
diff --git a/tools/testing/selftests/drivers/net/lib/py/env.py b/tools/testing/selftests/drivers/net/lib/py/env.py
index 6a71c7e7f136..24ce122abd9c 100644
--- a/tools/testing/selftests/drivers/net/lib/py/env.py
+++ b/tools/testing/selftests/drivers/net/lib/py/env.py
@@ -258,6 +258,15 @@ class NetDrvEpEnv(NetDrvEnvBase):
if nsim_test is False and self._ns is not None:
raise KsftXfailEx("Test does not work on netdevsim")
+ def get_local_nsim_dev(self):
+ """Returns the local netdevsim device or None.
+ Using this method is discouraged, as it makes tests nsim-specific.
+ Standard interfaces available on all HW should ideally be used.
+ This method is intended for the few cases where nsim-specific
+ assertions need to be verified which cannot be verified otherwise.
+ """
+ return self._ns
+
def _require_cmd(self, comm, key, host=None):
cached = self._required_cmd.get(comm, {})
if cached.get(key) is None:
diff --git a/tools/testing/selftests/drivers/net/macsec.py b/tools/testing/selftests/drivers/net/macsec.py
new file mode 100755
index 000000000000..9a83d9542e04
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/macsec.py
@@ -0,0 +1,343 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+"""MACsec tests."""
+
+import os
+
+from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_raises
+from lib.py import ksft_variants, KsftNamedVariant
+from lib.py import CmdExitFailure, KsftSkipEx
+from lib.py import NetDrvEpEnv
+from lib.py import cmd, ip, defer, ethtool
+
+MACSEC_KEY = "12345678901234567890123456789012"
+MACSEC_VLAN_VID = 10
+
+# Unique prefix per run to avoid collisions in the shared netns.
+# Keep it short: IFNAMSIZ is 16 (incl. NUL), and VLAN names append ".<vid>".
+MACSEC_PFX = f"ms{os.getpid()}_"
+
+
+def _macsec_name(idx=0):
+ return f"{MACSEC_PFX}{idx}"
+
+
+def _get_macsec_offload(dev):
+ """Returns macsec offload mode string from ip -d link show."""
+ info = ip(f"-d link show dev {dev}", json=True)[0]
+ return info.get("linkinfo", {}).get("info_data", {}).get("offload")
+
+
+def _get_features(dev):
+ """Returns ethtool features dict for a device."""
+ return ethtool(f"-k {dev}", json=True)[0]
+
+
+def _require_ip_macsec(cfg):
+ """SKIP if iproute2 on local or remote lacks 'ip macsec' support."""
+ for host in [None, cfg.remote]:
+ out = cmd("ip macsec help", fail=False, host=host)
+ if "Usage" not in out.stdout + out.stderr:
+ where = "remote" if host else "local"
+ raise KsftSkipEx(f"iproute2 too old on {where},"
+ " missing macsec support")
+
+
+def _require_ip_macsec_offload():
+ """SKIP if local iproute2 doesn't understand 'ip macsec offload'."""
+ out = cmd("ip macsec help", fail=False)
+ if "offload" not in out.stdout + out.stderr:
+ raise KsftSkipEx("iproute2 too old, missing macsec offload")
+
+
+def _require_macsec_offload(cfg):
+ """SKIP if local device doesn't support macsec-hw-offload."""
+ _require_ip_macsec_offload()
+ try:
+ feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
+ except (CmdExitFailure, IndexError) as e:
+ raise KsftSkipEx(
+ f"can't query features: {e}") from e
+ if not feat.get("macsec-hw-offload", {}).get("active"):
+ raise KsftSkipEx("macsec-hw-offload not supported")
+
+
+def _get_mac(ifname, host=None):
+ """Gets MAC address of an interface."""
+ dev = ip(f"link show dev {ifname}", json=True, host=host)
+ return dev[0]["address"]
+
+
+def _setup_macsec_sa(cfg, name):
+ """Adds matching TX/RX SAs on both ends."""
+ local_mac = _get_mac(name)
+ remote_mac = _get_mac(name, host=cfg.remote)
+
+ ip(f"macsec add {name} tx sa 0 pn 1 on key 01 {MACSEC_KEY}")
+ ip(f"macsec add {name} rx port 1 address {remote_mac}")
+ ip(f"macsec add {name} rx port 1 address {remote_mac} "
+ f"sa 0 pn 1 on key 02 {MACSEC_KEY}")
+
+ ip(f"macsec add {name} tx sa 0 pn 1 on key 02 {MACSEC_KEY}",
+ host=cfg.remote)
+ ip(f"macsec add {name} rx port 1 address {local_mac}", host=cfg.remote)
+ ip(f"macsec add {name} rx port 1 address {local_mac} "
+ f"sa 0 pn 1 on key 01 {MACSEC_KEY}", host=cfg.remote)
+
+
+def _setup_macsec_devs(cfg, name, offload):
+ """Creates macsec devices on both ends.
+
+ Only the local device gets HW offload; the remote always uses software
+ MACsec since it may not support offload at all.
+ """
+ offload_arg = "mac" if offload else "off"
+
+ ip(f"link add link {cfg.ifname} {name} "
+ f"type macsec encrypt on offload {offload_arg}")
+ defer(ip, f"link del {name}")
+ ip(f"link add link {cfg.remote_ifname} {name} "
+ f"type macsec encrypt on", host=cfg.remote)
+ defer(ip, f"link del {name}", host=cfg.remote)
+
+
+def _set_offload(name, offload):
+ """Sets offload on the local macsec device only."""
+ offload_arg = "mac" if offload else "off"
+
+ ip(f"link set {name} type macsec encrypt on offload {offload_arg}")
+
+
+def _setup_vlans(cfg, name, vid):
+ """Adds VLANs on top of existing macsec devs."""
+ vlan_name = f"{name}.{vid}"
+
+ ip(f"link add link {name} {vlan_name} type vlan id {vid}")
+ defer(ip, f"link del {vlan_name}")
+ ip(f"link add link {name} {vlan_name} type vlan id {vid}", host=cfg.remote)
+ defer(ip, f"link del {vlan_name}", host=cfg.remote)
+
+
+def _setup_vlan_ips(cfg, name, vid):
+ """Adds VLANs and IPs and brings up the macsec + VLAN devices."""
+ local_ip = "198.51.100.1"
+ remote_ip = "198.51.100.2"
+ vlan_name = f"{name}.{vid}"
+
+ ip(f"addr add {local_ip}/24 dev {vlan_name}")
+ ip(f"addr add {remote_ip}/24 dev {vlan_name}", host=cfg.remote)
+ ip(f"link set {name} up")
+ ip(f"link set {name} up", host=cfg.remote)
+ ip(f"link set {vlan_name} up")
+ ip(f"link set {vlan_name} up", host=cfg.remote)
+
+ return vlan_name, remote_ip
+
+
+def test_offload_api(cfg) -> None:
+ """MACsec offload API: create SecY, add SA/rx, toggle offload."""
+
+ _require_macsec_offload(cfg)
+ ms0 = _macsec_name(0)
+ ms1 = _macsec_name(1)
+ ms2 = _macsec_name(2)
+
+ # Create 3 SecY with offload
+ ip(f"link add link {cfg.ifname} {ms0} type macsec "
+ f"port 4 encrypt on offload mac")
+ defer(ip, f"link del {ms0}")
+
+ ip(f"link add link {cfg.ifname} {ms1} type macsec "
+ f"address aa:bb:cc:dd:ee:ff port 5 encrypt on offload mac")
+ defer(ip, f"link del {ms1}")
+
+ ip(f"link add link {cfg.ifname} {ms2} type macsec "
+ f"sci abbacdde01020304 encrypt on offload mac")
+ defer(ip, f"link del {ms2}")
+
+ # Add TX SA
+ ip(f"macsec add {ms0} tx sa 0 pn 1024 on "
+ "key 01 12345678901234567890123456789012")
+
+ # Add RX SC + SA
+ ip(f"macsec add {ms0} rx port 1234 address 1c:ed:de:ad:be:ef")
+ ip(f"macsec add {ms0} rx port 1234 address 1c:ed:de:ad:be:ef "
+ "sa 0 pn 1 on key 00 0123456789abcdef0123456789abcdef")
+
+ # Can't disable offload when SAs are configured
+ with ksft_raises(CmdExitFailure):
+ ip(f"link set {ms0} type macsec offload off")
+ with ksft_raises(CmdExitFailure):
+ ip(f"macsec offload {ms0} off")
+
+ # Toggle offload via rtnetlink on SA-free device
+ ip(f"link set {ms2} type macsec offload off")
+ ip(f"link set {ms2} type macsec encrypt on offload mac")
+
+ # Toggle offload via genetlink
+ ip(f"macsec offload {ms2} off")
+ ip(f"macsec offload {ms2} mac")
+
+
+def test_max_secy(cfg) -> None:
+ """nsim-only test for max number of SecYs."""
+
+ cfg.require_nsim()
+ _require_ip_macsec_offload()
+ ms0 = _macsec_name(0)
+ ms1 = _macsec_name(1)
+ ms2 = _macsec_name(2)
+ ms3 = _macsec_name(3)
+
+ ip(f"link add link {cfg.ifname} {ms0} type macsec "
+ f"port 4 encrypt on offload mac")
+ defer(ip, f"link del {ms0}")
+
+ ip(f"link add link {cfg.ifname} {ms1} type macsec "
+ f"address aa:bb:cc:dd:ee:ff port 5 encrypt on offload mac")
+ defer(ip, f"link del {ms1}")
+
+ ip(f"link add link {cfg.ifname} {ms2} type macsec "
+ f"sci abbacdde01020304 encrypt on offload mac")
+ defer(ip, f"link del {ms2}")
+ with ksft_raises(CmdExitFailure):
+ ip(f"link add link {cfg.ifname} {ms3} "
+ f"type macsec port 8 encrypt on offload mac")
+
+
+def test_max_sc(cfg) -> None:
+ """nsim-only test for max number of SCs."""
+
+ cfg.require_nsim()
+ _require_ip_macsec_offload()
+ ms0 = _macsec_name(0)
+
+ ip(f"link add link {cfg.ifname} {ms0} type macsec "
+ f"port 4 encrypt on offload mac")
+ defer(ip, f"link del {ms0}")
+ ip(f"macsec add {ms0} rx port 1234 address 1c:ed:de:ad:be:ef")
+ with ksft_raises(CmdExitFailure):
+ ip(f"macsec add {ms0} rx port 1235 address 1c:ed:de:ad:be:ef")
+
+
+def test_offload_state(cfg) -> None:
+ """Offload state reflects configuration changes."""
+
+ _require_macsec_offload(cfg)
+ ms0 = _macsec_name(0)
+
+ # Create with offload on
+ ip(f"link add link {cfg.ifname} {ms0} type macsec "
+ f"encrypt on offload mac")
+ cleanup = defer(ip, f"link del {ms0}")
+
+ ksft_eq(_get_macsec_offload(ms0), "mac",
+ "created with offload: should be mac")
+ feats_on_1 = _get_features(ms0)
+
+ ip(f"link set {ms0} type macsec offload off")
+ ksft_eq(_get_macsec_offload(ms0), "off",
+ "offload disabled: should be off")
+ feats_off_1 = _get_features(ms0)
+
+ ip(f"link set {ms0} type macsec encrypt on offload mac")
+ ksft_eq(_get_macsec_offload(ms0), "mac",
+ "offload re-enabled: should be mac")
+ ksft_eq(_get_features(ms0), feats_on_1,
+ "features should match first offload-on snapshot")
+
+ # Delete and recreate without offload
+ cleanup.exec()
+ ip(f"link add link {cfg.ifname} {ms0} type macsec")
+ defer(ip, f"link del {ms0}")
+ ksft_eq(_get_macsec_offload(ms0), "off",
+ "created without offload: should be off")
+ ksft_eq(_get_features(ms0), feats_off_1,
+ "features should match first offload-off snapshot")
+
+ ip(f"link set {ms0} type macsec encrypt on offload mac")
+ ksft_eq(_get_macsec_offload(ms0), "mac",
+ "offload enabled after create: should be mac")
+ ksft_eq(_get_features(ms0), feats_on_1,
+ "features should match first offload-on snapshot")
+
+
+def _check_nsim_vid(cfg, vid, expected) -> None:
+ """Checks if a VLAN is present. Only works on netdevsim."""
+
+ nsim = cfg.get_local_nsim_dev()
+ if not nsim:
+ return
+
+ vlan_path = os.path.join(nsim.nsims[0].dfs_dir, "vlan")
+ with open(vlan_path, encoding="utf-8") as f:
+ vids = f.read()
+ found = f"ctag {vid}\n" in vids
+ ksft_eq(found, expected,
+ f"VLAN {vid} {'expected' if expected else 'not expected'}"
+ f" in debugfs")
+
+
+@ksft_variants([
+ KsftNamedVariant("offloaded", True),
+ KsftNamedVariant("software", False),
+])
+def test_vlan(cfg, offload) -> None:
+ """Ping through VLAN-over-macsec."""
+
+ _require_ip_macsec(cfg)
+ if offload:
+ _require_macsec_offload(cfg)
+ else:
+ _require_ip_macsec_offload()
+ name = _macsec_name()
+ _setup_macsec_devs(cfg, name, offload=offload)
+ _setup_macsec_sa(cfg, name)
+ _setup_vlans(cfg, name, MACSEC_VLAN_VID)
+ vlan_name, remote_ip = _setup_vlan_ips(cfg, name, MACSEC_VLAN_VID)
+ _check_nsim_vid(cfg, MACSEC_VLAN_VID, offload)
+ # nsim doesn't handle the data path for offloaded macsec, so skip
+ # the ping when offloaded on nsim.
+ if not offload or not cfg.get_local_nsim_dev():
+ cmd(f"ping -I {vlan_name} -c 1 -W 5 {remote_ip}")
+
+
+@ksft_variants([
+ KsftNamedVariant("on_to_off", True),
+ KsftNamedVariant("off_to_on", False),
+])
+def test_vlan_toggle(cfg, offload) -> None:
+ """Toggle offload: VLAN filters propagate/remove correctly."""
+
+ _require_ip_macsec(cfg)
+ _require_macsec_offload(cfg)
+ name = _macsec_name()
+ _setup_macsec_devs(cfg, name, offload=offload)
+ _setup_vlans(cfg, name, MACSEC_VLAN_VID)
+ _check_nsim_vid(cfg, MACSEC_VLAN_VID, offload)
+ _set_offload(name, offload=not offload)
+ _check_nsim_vid(cfg, MACSEC_VLAN_VID, not offload)
+ vlan_name, remote_ip = _setup_vlan_ips(cfg, name, MACSEC_VLAN_VID)
+ _setup_macsec_sa(cfg, name)
+ # nsim doesn't handle the data path for offloaded macsec, so skip
+ # the ping when the final state is offloaded on nsim.
+ if offload or not cfg.get_local_nsim_dev():
+ cmd(f"ping -I {vlan_name} -c 1 -W 5 {remote_ip}")
+
+
+def main() -> None:
+ """Main program."""
+ with NetDrvEpEnv(__file__) as cfg:
+ ksft_run([test_offload_api,
+ test_max_secy,
+ test_max_sc,
+ test_offload_state,
+ test_vlan,
+ test_vlan_toggle,
+ ], args=(cfg,))
+ ksft_exit()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/testing/selftests/drivers/net/netdevsim/Makefile b/tools/testing/selftests/drivers/net/netdevsim/Makefile
index 1a228c5430f5..9808c2fbae9e 100644
--- a/tools/testing/selftests/drivers/net/netdevsim/Makefile
+++ b/tools/testing/selftests/drivers/net/netdevsim/Makefile
@@ -11,7 +11,6 @@ TEST_PROGS := \
fib.sh \
fib_notifications.sh \
hw_stats_l3.sh \
- macsec-offload.sh \
nexthop.sh \
peer.sh \
psample.sh \
diff --git a/tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh b/tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh
deleted file mode 100755
index 98033e6667d2..000000000000
--- a/tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/bin/bash
-# SPDX-License-Identifier: GPL-2.0-only
-
-source ethtool-common.sh
-
-NSIM_NETDEV=$(make_netdev)
-MACSEC_NETDEV=macsec_nsim
-
-set -o pipefail
-
-if ! ethtool -k $NSIM_NETDEV | grep -q 'macsec-hw-offload: on'; then
- echo "SKIP: netdevsim doesn't support MACsec offload"
- exit 4
-fi
-
-if ! ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec offload mac 2>/dev/null; then
- echo "SKIP: couldn't create macsec device"
- exit 4
-fi
-ip link del $MACSEC_NETDEV
-
-#
-# test macsec offload API
-#
-
-ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}" type macsec port 4 offload mac
-check $?
-
-ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}2" type macsec address "aa:bb:cc:dd:ee:ff" port 5 offload mac
-check $?
-
-ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}3" type macsec sci abbacdde01020304 offload mac
-check $?
-
-ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}4" type macsec port 8 offload mac 2> /dev/null
-check $? '' '' 1
-
-ip macsec add "${MACSEC_NETDEV}" tx sa 0 pn 1024 on key 01 12345678901234567890123456789012
-check $?
-
-ip macsec add "${MACSEC_NETDEV}" rx port 1234 address "1c:ed:de:ad:be:ef"
-check $?
-
-ip macsec add "${MACSEC_NETDEV}" rx port 1234 address "1c:ed:de:ad:be:ef" sa 0 pn 1 on \
- key 00 0123456789abcdef0123456789abcdef
-check $?
-
-ip macsec add "${MACSEC_NETDEV}" rx port 1235 address "1c:ed:de:ad:be:ef" 2> /dev/null
-check $? '' '' 1
-
-# can't disable macsec offload when SAs are configured
-ip link set "${MACSEC_NETDEV}" type macsec offload off 2> /dev/null
-check $? '' '' 1
-
-ip macsec offload "${MACSEC_NETDEV}" off 2> /dev/null
-check $? '' '' 1
-
-# toggle macsec offload via rtnetlink
-ip link set "${MACSEC_NETDEV}2" type macsec offload off
-check $?
-
-ip link set "${MACSEC_NETDEV}2" type macsec offload mac
-check $?
-
-# toggle macsec offload via genetlink
-ip macsec offload "${MACSEC_NETDEV}2" off
-check $?
-
-ip macsec offload "${MACSEC_NETDEV}2" mac
-check $?
-
-for dev in ${MACSEC_NETDEV}{,2,3} ; do
- ip link del $dev
- check $?
-done
-
-
-#
-# test ethtool features when toggling offload
-#
-
-ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec offload mac
-TMP_FEATS_ON_1="$(ethtool -k $MACSEC_NETDEV)"
-
-ip link set $MACSEC_NETDEV type macsec offload off
-TMP_FEATS_OFF_1="$(ethtool -k $MACSEC_NETDEV)"
-
-ip link set $MACSEC_NETDEV type macsec offload mac
-TMP_FEATS_ON_2="$(ethtool -k $MACSEC_NETDEV)"
-
-[ "$TMP_FEATS_ON_1" = "$TMP_FEATS_ON_2" ]
-check $?
-
-ip link del $MACSEC_NETDEV
-
-ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec
-check $?
-
-TMP_FEATS_OFF_2="$(ethtool -k $MACSEC_NETDEV)"
-[ "$TMP_FEATS_OFF_1" = "$TMP_FEATS_OFF_2" ]
-check $?
-
-ip link set $MACSEC_NETDEV type macsec offload mac
-check $?
-
-TMP_FEATS_ON_3="$(ethtool -k $MACSEC_NETDEV)"
-[ "$TMP_FEATS_ON_1" = "$TMP_FEATS_ON_3" ]
-check $?
-
-
-if [ $num_errors -eq 0 ]; then
- echo "PASSED all $((num_passes)) checks"
- exit 0
-else
- echo "FAILED $num_errors/$((num_errors+num_passes)) checks"
- exit 1
-fi