[PATCH net-next 07/11] netdevsim: Add MAC loopback simulation
From: Björn Töpel <bjorn@kernel.org>
Date: 2026-03-10 10:48:35
Also in:
linux-kselftest, linux-rdma, lkml
Subsystem:
netdevsim, networking drivers, the rest · Maintainers:
Jakub Kicinski, Andrew Lunn, "David S. Miller", Eric Dumazet, Paolo Abeni, Linus Torvalds
Implement the three ethtool loopback ops for MAC-level loopback
simulation:
- get_loopback(): exact lookup by name ("mac")
- get_loopback_by()_index: enumerate (single entry at index 0)
- set_loopback(): update direction, return 1 if changed
The MAC loopback entry announces support for both near-end and far-end
support by default. State is stored in nsim_ethtool.mac_lb and exposed
via debugfs under ethtool/mac_lb/{supported,direction} for test
inspection and control.
Signed-off-by: Björn Töpel <bjorn@kernel.org>
---
drivers/net/netdevsim/ethtool.c | 64 +++++++++++++++++++++++++++++++
drivers/net/netdevsim/netdevsim.h | 4 ++
2 files changed, 68 insertions(+)
diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c
index 36a201533aae..84bc025885f7 100644
--- a/drivers/net/netdevsim/ethtool.c
+++ b/drivers/net/netdevsim/ethtool.c@@ -195,6 +195,58 @@ nsim_get_fec_stats(struct net_device *dev, struct ethtool_fec_stats *fec_stats, values[2].per_lane[3] = 0; } +static void nsim_fill_mac_lb_entry(struct netdevsim *ns, + struct ethtool_loopback_entry *entry) +{ + memset(entry, 0, sizeof(*entry)); + entry->component = ETHTOOL_LOOPBACK_COMPONENT_MAC; + strscpy(entry->name, "mac", sizeof(entry->name)); + entry->supported = ns->ethtool.mac_lb.supported; + entry->direction = ns->ethtool.mac_lb.direction; +} + +static int nsim_get_loopback(struct net_device *dev, const char *name, + u32 id, struct ethtool_loopback_entry *entry) +{ + struct netdevsim *ns = netdev_priv(dev); + + if (strcmp(name, "mac")) + return -EOPNOTSUPP; + + nsim_fill_mac_lb_entry(ns, entry); + return 0; +} + +static int nsim_get_loopback_by_index(struct net_device *dev, u32 index, + struct ethtool_loopback_entry *entry) +{ + struct netdevsim *ns = netdev_priv(dev); + + if (index > 0) + return -EOPNOTSUPP; + + nsim_fill_mac_lb_entry(ns, entry); + return 0; +} + +static int nsim_set_loopback(struct net_device *dev, + const struct ethtool_loopback_entry *entry, + struct netlink_ext_ack *extack) +{ + struct netdevsim *ns = netdev_priv(dev); + + if (strcmp(entry->name, "mac")) { + NL_SET_ERR_MSG(extack, "Unknown MAC loopback name"); + return -EOPNOTSUPP; + } + + if (ns->ethtool.mac_lb.direction == entry->direction) + return 0; + + ns->ethtool.mac_lb.direction = entry->direction; + return 1; +} + static int nsim_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info) {
@@ -222,6 +274,9 @@ static const struct ethtool_ops nsim_ethtool_ops = { .set_fecparam = nsim_set_fecparam, .get_fec_stats = nsim_get_fec_stats, .get_ts_info = nsim_get_ts_info, + .get_loopback = nsim_get_loopback, + .get_loopback_by_index = nsim_get_loopback_by_index, + .set_loopback = nsim_set_loopback, }; static void nsim_ethtool_ring_init(struct netdevsim *ns)
@@ -270,4 +325,13 @@ void nsim_ethtool_init(struct netdevsim *ns) &ns->ethtool.ring.rx_mini_max_pending); debugfs_create_u32("tx_max_pending", 0600, dir, &ns->ethtool.ring.tx_max_pending); + + ns->ethtool.mac_lb.supported = ETHTOOL_LOOPBACK_DIRECTION_NEAR_END | + ETHTOOL_LOOPBACK_DIRECTION_FAR_END; + + dir = debugfs_create_dir("mac_lb", ethtool); + debugfs_create_u32("supported", 0600, dir, + &ns->ethtool.mac_lb.supported); + debugfs_create_u32("direction", 0600, dir, + &ns->ethtool.mac_lb.direction); }
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index f767fc8a7505..2e322b9410d2 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h@@ -90,6 +90,10 @@ struct nsim_ethtool { struct ethtool_coalesce coalesce; struct ethtool_ringparam ring; struct ethtool_fecparam fec; + struct { + u32 supported; + u32 direction; + } mac_lb; }; struct nsim_rq {
--
2.53.0