From 544921efd4e4b1f135c87335dd59114a302c574d Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 19 Mar 2026 19:40:54 +0100 Subject: [PATCH 1/3] netdevsim: move TC offload code to a dedicated file This commit has no functional change. Reviewed-by: Jamal Hadi Salim Signed-off-by: Davide Caratti Link: https://patch.msgid.link/b7881fd53f8a5d8eff4eae8121576c3cd60c2ed7.1773945414.git.dcaratti@redhat.com Signed-off-by: Jakub Kicinski --- drivers/net/netdevsim/Makefile | 2 +- drivers/net/netdevsim/netdev.c | 51 --------------------------- drivers/net/netdevsim/netdevsim.h | 3 ++ drivers/net/netdevsim/tc.c | 57 +++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 52 deletions(-) create mode 100644 drivers/net/netdevsim/tc.c diff --git a/drivers/net/netdevsim/Makefile b/drivers/net/netdevsim/Makefile index 14a553e000ec..87718204fb4d 100644 --- a/drivers/net/netdevsim/Makefile +++ b/drivers/net/netdevsim/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_NETDEVSIM) += netdevsim.o netdevsim-objs := \ - netdev.o dev.o ethtool.o fib.o bus.o health.o hwstats.o udp_tunnels.o + netdev.o dev.o ethtool.o fib.o bus.o health.o hwstats.o udp_tunnels.o tc.o ifeq ($(CONFIG_BPF_SYSCALL),y) netdevsim-objs += \ diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 3645ebde049a..c71b8d116f18 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -202,12 +202,6 @@ static int nsim_change_mtu(struct net_device *dev, int new_mtu) return 0; } -static int -nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) -{ - return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv); -} - static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac) { struct netdevsim *ns = netdev_priv(dev); @@ -338,51 +332,6 @@ static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state) return 0; } -static void nsim_taprio_stats(struct tc_taprio_qopt_stats *stats) -{ - stats->window_drops = 0; - stats->tx_overruns = 0; -} - -static int nsim_setup_tc_taprio(struct net_device *dev, - struct tc_taprio_qopt_offload *offload) -{ - int err = 0; - - switch (offload->cmd) { - case TAPRIO_CMD_REPLACE: - case TAPRIO_CMD_DESTROY: - break; - case TAPRIO_CMD_STATS: - nsim_taprio_stats(&offload->stats); - break; - default: - err = -EOPNOTSUPP; - } - - return err; -} - -static LIST_HEAD(nsim_block_cb_list); - -static int -nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) -{ - struct netdevsim *ns = netdev_priv(dev); - - switch (type) { - case TC_SETUP_QDISC_TAPRIO: - return nsim_setup_tc_taprio(dev, type_data); - case TC_SETUP_BLOCK: - return flow_block_cb_setup_simple(type_data, - &nsim_block_cb_list, - nsim_setup_tc_block_cb, - ns, ns, true); - default: - return -EOPNOTSUPP; - } -} - static int nsim_set_features(struct net_device *dev, netdev_features_t features) { diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index f767fc8a7505..c904e14f6b3f 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -455,6 +455,9 @@ static inline void nsim_psp_handle_ext(struct sk_buff *skb, struct skb_ext *psp_ext) {} #endif +int nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, + void *type_data); + struct nsim_bus_dev { struct device dev; struct list_head list; diff --git a/drivers/net/netdevsim/tc.c b/drivers/net/netdevsim/tc.c new file mode 100644 index 000000000000..8a1960f5f99e --- /dev/null +++ b/drivers/net/netdevsim/tc.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include "netdevsim.h" + +static int +nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) +{ + return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv); +} + +static void nsim_taprio_stats(struct tc_taprio_qopt_stats *stats) +{ + stats->window_drops = 0; + stats->tx_overruns = 0; +} + +static int nsim_setup_tc_taprio(struct net_device *dev, + struct tc_taprio_qopt_offload *offload) +{ + int err = 0; + + switch (offload->cmd) { + case TAPRIO_CMD_REPLACE: + case TAPRIO_CMD_DESTROY: + break; + case TAPRIO_CMD_STATS: + nsim_taprio_stats(&offload->stats); + break; + default: + err = -EOPNOTSUPP; + } + + return err; +} + +static LIST_HEAD(nsim_block_cb_list); + +int +nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) +{ + struct netdevsim *ns = netdev_priv(dev); + + switch (type) { + case TC_SETUP_QDISC_TAPRIO: + return nsim_setup_tc_taprio(dev, type_data); + case TC_SETUP_BLOCK: + return flow_block_cb_setup_simple(type_data, + &nsim_block_cb_list, + nsim_setup_tc_block_cb, + ns, ns, true); + default: + return -EOPNOTSUPP; + } +} From abdf5133bfa12c45d402f7b73d39bca772f3644a Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 19 Mar 2026 19:40:55 +0100 Subject: [PATCH 2/3] netdevsim: support tc-ets offload Extend netdevsim to accept ndo_setup_tc(TC_SETUP_QDISC_ETS) calls, so that it's possible to run tdc on ETS offload code path. Reviewed-by: Jamal Hadi Salim Signed-off-by: Davide Caratti Link: https://patch.msgid.link/d04086cd0204d4aaf6524e972198faa1a4e5d657.1773945414.git.dcaratti@redhat.com Signed-off-by: Jakub Kicinski --- drivers/net/netdevsim/tc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/netdevsim/tc.c b/drivers/net/netdevsim/tc.c index 8a1960f5f99e..8f013a5895a2 100644 --- a/drivers/net/netdevsim/tc.c +++ b/drivers/net/netdevsim/tc.c @@ -2,6 +2,7 @@ #include #include +#include #include "netdevsim.h" @@ -36,6 +37,25 @@ static int nsim_setup_tc_taprio(struct net_device *dev, return err; } +static int nsim_setup_tc_ets(struct net_device *dev, + struct tc_ets_qopt_offload *offload) +{ + int err = 0; + + switch (offload->command) { + case TC_ETS_REPLACE: + case TC_ETS_DESTROY: + break; + case TC_ETS_STATS: + _bstats_update(offload->stats.bstats, 0, 0); + break; + default: + err = -EOPNOTSUPP; + } + + return err; +} + static LIST_HEAD(nsim_block_cb_list); int @@ -46,6 +66,8 @@ nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) switch (type) { case TC_SETUP_QDISC_TAPRIO: return nsim_setup_tc_taprio(dev, type_data); + case TC_SETUP_QDISC_ETS: + return nsim_setup_tc_ets(dev, type_data); case TC_SETUP_BLOCK: return flow_block_cb_setup_simple(type_data, &nsim_block_cb_list, From 5754a1c9f9b6e298791c4bb34263f37dfe93ee35 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 19 Mar 2026 19:40:56 +0100 Subject: [PATCH 3/3] tc-testing: add a test case for ETS offload While reviewing the fix for unintentional u32 overflows in ets offload code, Jamal said: [...] > otherwise a tdc test should cover it fine (when you get to the > netdevsim change perhaps) Extend tdc to allow setting hw-tc-offload via ethtool, and add a test case to reproduce the division by zero fixed in [1]. [1] https://lore.kernel.org/all/CAM0EoMm17wsYZmdFLshH3_-GrZtzd=i0xnoO2yiVB=-N4761mw@mail.gmail.com/ Suggested-by: Jamal Hadi Salim Reviewed-by: Jamal Hadi Salim Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Signed-off-by: Davide Caratti Link: https://patch.msgid.link/39129c374cbd00147b8c5afc04db59db62b50acc.1773945414.git.dcaratti@redhat.com Signed-off-by: Jakub Kicinski --- .../tc-testing/tc-tests/qdiscs/ets.json | 23 +++++++++++++++++++ tools/testing/selftests/tc-testing/tdc.py | 3 +++ .../selftests/tc-testing/tdc_config.py | 1 + 3 files changed, 27 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/ets.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/ets.json index a5d94cdec605..ee09e6d6fdf3 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/ets.json +++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/ets.json @@ -984,5 +984,28 @@ "matchCount": "1", "teardown": [ ] + }, + { + "id": "41f5", + "name": "ETS offload where the sum of quanta wraps u32", + "category": [ + "qdisc", + "ets" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + "echo \"1 1 4\" > /sys/bus/netdevsim/new_device", + "$ETHTOOL -K $ETH hw-tc-offload on" + ], + "cmdUnderTest": "$TC qdisc add dev $ETH root ets quanta 4294967294 1 1", + "expExitCode": "0", + "verifyCmd": "$TC qdisc show dev $ETH", + "matchPattern": "qdisc ets .*bands 3 quanta 4294967294 1 1", + "matchCount": "1", + "teardown": [ + "echo \"1\" > /sys/bus/netdevsim/del_device" + ] } ] diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 4f255cec0c22..81b4ac3f050c 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -755,6 +755,9 @@ def check_default_settings(args, remaining, pm): NAMES['DEV2'] = args.device if 'TIMEOUT' not in NAMES: NAMES['TIMEOUT'] = None + if 'ETHTOOL' in NAMES and not os.path.isfile(NAMES['ETHTOOL']): + print(f"The specified ethtool path {NAMES['ETHTOOL']} does not exist.") + exit(1) if not os.path.isfile(NAMES['TC']): print("The specified tc path " + NAMES['TC'] + " does not exist.") exit(1) diff --git a/tools/testing/selftests/tc-testing/tdc_config.py b/tools/testing/selftests/tc-testing/tdc_config.py index ccb0f06ef9e3..9488b03cbc2c 100644 --- a/tools/testing/selftests/tc-testing/tdc_config.py +++ b/tools/testing/selftests/tc-testing/tdc_config.py @@ -17,6 +17,7 @@ NAMES = { 'DEV1': 'v0p1', 'DEV2': '', 'DUMMY': 'dummy1', + 'ETHTOOL': '/usr/sbin/ethtool', 'ETH': 'eth0', 'BATCH_FILE': './batch.txt', 'BATCH_DIR': 'tmp',