mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses
@ 2026-09-14  1:45 Yuyang Huang
  2026-09-14  1:45 ` [PATCH net-next v5 1/4] netlink: specs: rt-addr: fix the type of target-netnsid Yuyang Huang
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: Yuyang Huang @ 2026-09-14  1:45 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: Andrew Lunn, David S. Miller, David Ahern, Donald Hunter,
	Eric Dumazet, Ido Schimmel, Jacob Keller, Jakub Kicinski,
	Kuniyuki Iwashima, Nicolas Dichtel, Nikolaos Gkarlis,
	Paolo Abeni, Sabrina Dubroca, Shuah Khan, Simon Horman,
	Stanislav Fomichev, linux-kernel, linux-kselftest, netdev

"ip maddr show" prints three kinds of entries: link-layer, IPv4 and
IPv6. The IPv4 and IPv6 ones can be read over netlink today: IPv6 has
had RTM_GETMULTICAST for a long time and IPv4 got it in eb4e17a1d915
("netlink: support dumping IPv4 multicast addresses"), with IFA_MC_USERS
added later so the user count no longer has to come from procfs.

The link-layer list is the missing piece. dev->mc, the addresses
programmed into the device filter, is only exported via
/proc/net/dev_mcast, so iproute2 still carries a procfs parser just for
that. This series closes the gap so that "ip maddr show" can be served
from rtnetlink alone.

Patch 1 fixes the type of target-netnsid in the rt-addr spec. Patch 2
handles RTM_GETMULTICAST dumps with ifa_family set to AF_PACKET and
walks dev->mc under netif_addr_lock_bh(), no RTNL. The reply reuses
the ifaddrmsg format of the IPv4 and IPv6 dumps: IFA_MULTICAST carries
the raw link-layer address, IFA_MC_USERS the reference count, and a new
IFA_F_GLOBAL flag in IFA_FLAGS marks entries added explicitly, which is
the "static" column /proc/net/dev_mcast has and "ip maddr" prints. A
non-zero ifa_index limits the dump to one device and IFA_TARGET_NETNSID
selects another netns, like the IPv4 and IPv6 dumps.

Patch 3 updates the rt-addr spec and patch 4 adds a selftest that
checks the filter, the user count, the global flag and target-netnsid.

Nothing changes for other families. AF_PACKET dumps returned
-EOPNOTSUPP before, so iproute2 can keep the procfs fallback for older
kernels. I have the iproute2 side ready and will post it once this is
in; with it, "ip maddr show" does not open /proc/net at all.

Changes in v5:
- Filter the target-netnsid selftest dump by ifa-index, a new netns
  also contains the fallback tunnel devices

Changes in v4:
- Reset the resume offset when the device the dump stopped at is gone
- Use a tracked netns reference (put_net_track)
- Say ifa-family must be set in the spec doc, drop the AF_UNSPEC remark
- Close the netlink socket and guard the checks in the selftest
- Drop the Fixes tag

Changes in v3:
- Report the static bit as a new IFA_F_GLOBAL flag in IFA_FLAGS
  instead of IFA_F_PERMANENT
- Support IFA_TARGET_NETNSID and test it
- Describe global_use accurately, it is also set by dev_mc_add_excl()
- Fix the target-netnsid type in the rt-addr spec, as its own patch

Changes in v2:
- Always validate the request header, not only with strict checking
- Use a single "with" statement in the selftest (ruff)

Yuyang Huang (4):
  netlink: specs: rt-addr: fix the type of target-netnsid
  rtnetlink: add AF_PACKET multicast dumps
  netlink: specs: rt-addr: document AF_PACKET multicast dumps
  selftests: net: test AF_PACKET multicast dumps

 Documentation/netlink/specs/rt-addr.yaml |  17 ++-
 include/uapi/linux/if_addr.h             |   1 +
 net/core/rtnetlink.c                     | 174 +++++++++++++++++++++++
 tools/testing/selftests/net/rtnetlink.py |  75 +++++++++-
 4 files changed, 261 insertions(+), 6 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH net-next v5 1/4] netlink: specs: rt-addr: fix the type of target-netnsid
  2026-09-14  1:45 [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
@ 2026-09-14  1:45 ` Yuyang Huang
  2026-09-14  1:45 ` [PATCH net-next v5 2/4] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Yuyang Huang @ 2026-09-14  1:45 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: Andrew Lunn, David S. Miller, David Ahern, Donald Hunter,
	Eric Dumazet, Ido Schimmel, Jacob Keller, Jakub Kicinski,
	Kuniyuki Iwashima, Nicolas Dichtel, Nikolaos Gkarlis,
	Paolo Abeni, Sabrina Dubroca, Shuah Khan, Simon Horman,
	Stanislav Fomichev, linux-kernel, linux-kselftest, netdev

The kernel parses IFA_TARGET_NETNSID as NLA_S32 and rt-link.yaml
declares its target-netnsid as s32, but rt-addr.yaml has it as binary.

Signed-off-by: Yuyang Huang <sigefriedhyy@gmail.com>
Reviewed-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 Documentation/netlink/specs/rt-addr.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/netlink/specs/rt-addr.yaml b/Documentation/netlink/specs/rt-addr.yaml
index 0ecbd24c890c..17ead2203451 100644
--- a/Documentation/netlink/specs/rt-addr.yaml
+++ b/Documentation/netlink/specs/rt-addr.yaml
@@ -119,7 +119,7 @@ attribute-sets:
         type: u32
       -
         name: target-netnsid
-        type: binary
+        type: s32
       -
         name: proto
         type: u8
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH net-next v5 2/4] rtnetlink: add AF_PACKET multicast dumps
  2026-09-14  1:45 [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
  2026-09-14  1:45 ` [PATCH net-next v5 1/4] netlink: specs: rt-addr: fix the type of target-netnsid Yuyang Huang
@ 2026-09-14  1:45 ` Yuyang Huang
  2026-09-15 16:47   ` netdev-bot+sashiko
  2026-09-17  1:49   ` Jakub Kicinski
  2026-09-14  1:45 ` [PATCH net-next v5 3/4] netlink: specs: rt-addr: document " Yuyang Huang
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 13+ messages in thread
From: Yuyang Huang @ 2026-09-14  1:45 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: Andrew Lunn, David S. Miller, David Ahern, Donald Hunter,
	Eric Dumazet, Ido Schimmel, Jacob Keller, Jakub Kicinski,
	Kuniyuki Iwashima, Nicolas Dichtel, Nikolaos Gkarlis,
	Paolo Abeni, Sabrina Dubroca, Shuah Khan, Simon Horman,
	Stanislav Fomichev, linux-kernel, linux-kselftest, netdev

RTM_GETMULTICAST dumps IPv4 and IPv6 multicast group memberships, but
the device multicast list (dev->mc) is only available through
/proc/net/dev_mcast, so "ip maddr show" still has to parse procfs for
its link-layer entries.

Handle RTM_GETMULTICAST dumps with ifa_family set to AF_PACKET and
report every entry of dev->mc in the existing ifaddrmsg format:

  - IFA_MULTICAST carries the raw link-layer address
  - IFA_MC_USERS carries the entry reference count
  - IFA_F_GLOBAL in IFA_FLAGS reports netdev_hw_addr::global_use, set
    by dev_mc_add_global() (SIOCADDMULTI) and dev_mc_add_excl()
    ("bridge fdb add ... self"), i.e. entries added explicitly rather
    than by a protocol join. This is the static column of
    /proc/net/dev_mcast
  - ifa_scope is RT_SCOPE_LINK

This covers every column of /proc/net/dev_mcast. AF_PACKET is the
family iproute2 already uses for link-layer addresses ("ip -0").

The default FDB dump also walks dev->mc, but only for Ethernet devices
without an ndo_fdb_dump of their own, so bridge, vxlan or macvlan
devices never show their multicast filter there, and it has no users
count or global_use bit. Extending it would change "bridge fdb show"
output and add NDA_* attributes.

There are no legacy users of AF_PACKET requests, so they are always
validated: prefixlen, flags and scope must be zero and a non-zero
ifa_index restricts the dump to that device. IFA_TARGET_NETNSID selects
another netns like the IPv4 and IPv6 dumps and is the only attribute
accepted. The dump runs under RCU and netif_addr_lock_bh() and does not
need RTNL.

Signed-off-by: Yuyang Huang <sigefriedhyy@gmail.com>
Reviewed-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 include/uapi/linux/if_addr.h |   1 +
 net/core/rtnetlink.c         | 174 +++++++++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+)

diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h
index 7fb630b7fe31..0a1ad9ebb47b 100644
--- a/include/uapi/linux/if_addr.h
+++ b/include/uapi/linux/if_addr.h
@@ -57,6 +57,7 @@ enum {
 #define IFA_F_NOPREFIXROUTE	0x200
 #define IFA_F_MCAUTOJOIN	0x400
 #define IFA_F_STABLE_PRIVACY	0x800
+#define IFA_F_GLOBAL		0x1000
 
 struct ifa_cacheinfo {
 	__u32	ifa_prefered;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index be9d1625bac3..5f3e692a828b 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -4571,6 +4571,178 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
 	return skb->len ? : ret;
 }
 
+static int rtnl_fill_mcaddr(struct sk_buff *skb, const struct net_device *dev,
+			    const struct netdev_hw_addr *ha, u32 portid,
+			    u32 seq, unsigned int flags, int netnsid)
+{
+	u32 ifa_flags = ha->global_use ? IFA_F_GLOBAL : 0;
+	struct ifaddrmsg *ifm;
+	struct nlmsghdr *nlh;
+
+	nlh = nlmsg_put(skb, portid, seq, RTM_GETMULTICAST, sizeof(*ifm),
+			flags);
+	if (!nlh)
+		return -EMSGSIZE;
+
+	ifm = nlmsg_data(nlh);
+	ifm->ifa_family = AF_PACKET;
+	ifm->ifa_prefixlen = 0;
+	/* ifm->ifa_flags holds 8 bits, the full value is in IFA_FLAGS */
+	ifm->ifa_flags = (__u8)ifa_flags;
+	ifm->ifa_scope = RT_SCOPE_LINK;
+	ifm->ifa_index = dev->ifindex;
+
+	if ((netnsid >= 0 &&
+	     nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) ||
+	    nla_put(skb, IFA_MULTICAST, dev->addr_len, ha->addr) ||
+	    nla_put_u32(skb, IFA_MC_USERS, ha->refcount) ||
+	    nla_put_u32(skb, IFA_FLAGS, ifa_flags)) {
+		nlmsg_cancel(skb, nlh);
+		return -EMSGSIZE;
+	}
+
+	nlmsg_end(skb, nlh);
+	return 0;
+}
+
+static int rtnl_dump_mcaddr_dev(struct net_device *dev, struct sk_buff *skb,
+				struct netlink_callback *cb, int *s_addr_idx,
+				unsigned int flags, int netnsid)
+{
+	struct netdev_hw_addr *ha;
+	int addr_idx = 0;
+	int err = 0;
+
+	netif_addr_lock_bh(dev);
+	netdev_for_each_mc_addr(ha, dev) {
+		if (addr_idx < *s_addr_idx) {
+			addr_idx++;
+			continue;
+		}
+		err = rtnl_fill_mcaddr(skb, dev, ha, NETLINK_CB(cb->skb).portid,
+				       cb->nlh->nlmsg_seq, flags, netnsid);
+		if (err < 0)
+			break;
+		addr_idx++;
+	}
+	netif_addr_unlock_bh(dev);
+
+	*s_addr_idx = err < 0 ? addr_idx : 0;
+
+	return err;
+}
+
+struct rtnl_mcaddr_dump_filter {
+	struct net *tgt_net;
+	netns_tracker ns_tracker;
+	int netnsid;
+	int ifindex;
+};
+
+static const struct nla_policy rtnl_mcaddr_dump_policy[IFA_MAX + 1] = {
+	[IFA_TARGET_NETNSID]	= { .type = NLA_S32 },
+};
+
+static int rtnl_valid_dump_mcaddr_req(const struct nlmsghdr *nlh,
+				      struct sock *sk,
+				      struct rtnl_mcaddr_dump_filter *filter,
+				      struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[IFA_MAX + 1];
+	struct ifaddrmsg *ifm;
+	int err;
+
+	ifm = nlmsg_payload(nlh, sizeof(*ifm));
+	if (!ifm) {
+		NL_SET_ERR_MSG(extack,
+			       "Invalid header for multicast dump request");
+		return -EINVAL;
+	}
+
+	if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) {
+		NL_SET_ERR_MSG(extack,
+			       "Invalid values in multicast dump header");
+		return -EINVAL;
+	}
+
+	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX,
+			  rtnl_mcaddr_dump_policy, extack);
+	if (err < 0)
+		return err;
+
+	if (tb[IFA_TARGET_NETNSID]) {
+		struct net *net;
+
+		filter->netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]);
+		net = rtnl_get_net_ns_capable(sk, filter->netnsid);
+		if (IS_ERR(net)) {
+			NL_SET_ERR_MSG(extack,
+				       "Invalid target network namespace id");
+			return PTR_ERR(net);
+		}
+		netns_tracker_alloc(net, &filter->ns_tracker, GFP_KERNEL);
+		filter->tgt_net = net;
+	}
+
+	filter->ifindex = ifm->ifa_index;
+
+	return 0;
+}
+
+static int rtnl_dump_mcaddr(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct rtnl_mcaddr_dump_filter filter = {
+		.tgt_net = sock_net(skb->sk),
+		.netnsid = -1,
+	};
+	unsigned int flags = NLM_F_MULTI;
+	struct {
+		unsigned long ifindex;
+		int addr_idx;
+	} *ctx = (void *)cb->ctx;
+	unsigned long s_ifindex;
+	struct net_device *dev;
+	int err;
+
+	err = rtnl_valid_dump_mcaddr_req(cb->nlh, skb->sk, &filter,
+					 cb->extack);
+	if (err < 0)
+		return err;
+
+	rcu_read_lock();
+
+	if (filter.ifindex) {
+		cb->answer_flags |= NLM_F_DUMP_FILTERED;
+		flags |= NLM_F_DUMP_FILTERED;
+		dev = dev_get_by_index_rcu(filter.tgt_net, filter.ifindex);
+		if (!dev) {
+			err = -ENODEV;
+			goto out;
+		}
+		err = rtnl_dump_mcaddr_dev(dev, skb, cb, &ctx->addr_idx, flags,
+					   filter.netnsid);
+		goto out;
+	}
+
+	s_ifindex = ctx->ifindex;
+	for_each_netdev_dump(filter.tgt_net, dev, ctx->ifindex) {
+		/* The device the dump stopped at is gone, do not skip
+		 * entries of the next one.
+		 */
+		if (dev->ifindex != s_ifindex)
+			ctx->addr_idx = 0;
+		err = rtnl_dump_mcaddr_dev(dev, skb, cb, &ctx->addr_idx, flags,
+					   filter.netnsid);
+		if (err < 0)
+			break;
+	}
+out:
+	rcu_read_unlock();
+	if (filter.netnsid >= 0)
+		put_net_track(filter.tgt_net, &filter.ns_tracker);
+	return err;
+}
+
 struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
 				       unsigned int change,
 				       u32 event, gfp_t flags, int *new_nsid,
@@ -7256,6 +7428,8 @@ static const struct rtnl_msg_handler rtnetlink_rtnl_msg_handlers[] __initconst =
 	{.msgtype = RTM_SETSTATS, .doit = rtnl_stats_set},
 	{.msgtype = RTM_NEWLINKPROP, .doit = rtnl_newlinkprop},
 	{.msgtype = RTM_DELLINKPROP, .doit = rtnl_dellinkprop},
+	{.protocol = PF_PACKET, .msgtype = RTM_GETMULTICAST,
+	 .dumpit = rtnl_dump_mcaddr, .flags = RTNL_FLAG_DUMP_UNLOCKED},
 	{.protocol = PF_BRIDGE, .msgtype = RTM_GETLINK,
 	 .dumpit = rtnl_bridge_getlink},
 	{.protocol = PF_BRIDGE, .msgtype = RTM_DELLINK,
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH net-next v5 3/4] netlink: specs: rt-addr: document AF_PACKET multicast dumps
  2026-09-14  1:45 [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
  2026-09-14  1:45 ` [PATCH net-next v5 1/4] netlink: specs: rt-addr: fix the type of target-netnsid Yuyang Huang
  2026-09-14  1:45 ` [PATCH net-next v5 2/4] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
@ 2026-09-14  1:45 ` Yuyang Huang
  2026-09-15 16:47   ` netdev-bot+sashiko
  2026-09-14  1:45 ` [PATCH net-next v5 4/4] selftests: net: test " Yuyang Huang
  2026-09-17  1:47 ` [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses Jakub Kicinski
  4 siblings, 1 reply; 13+ messages in thread
From: Yuyang Huang @ 2026-09-14  1:45 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: Andrew Lunn, David S. Miller, David Ahern, Donald Hunter,
	Eric Dumazet, Ido Schimmel, Jacob Keller, Jakub Kicinski,
	Kuniyuki Iwashima, Nicolas Dichtel, Nikolaos Gkarlis,
	Paolo Abeni, Sabrina Dubroca, Shuah Khan, Simon Horman,
	Stanislav Fomichev, linux-kernel, linux-kselftest, netdev

Add the global flag, list the attributes the AF_PACKET dump uses and
describe how ifa-family selects IPv4, IPv6 or link-layer output for
RTM_GETMULTICAST.

Signed-off-by: Yuyang Huang <sigefriedhyy@gmail.com>
Reviewed-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 Documentation/netlink/specs/rt-addr.yaml | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/Documentation/netlink/specs/rt-addr.yaml b/Documentation/netlink/specs/rt-addr.yaml
index 17ead2203451..1a17e55d1cca 100644
--- a/Documentation/netlink/specs/rt-addr.yaml
+++ b/Documentation/netlink/specs/rt-addr.yaml
@@ -77,6 +77,8 @@ definitions:
         name: mcautojoin
       -
         name: stable-privacy
+      -
+        name: global
 
 attribute-sets:
   -
@@ -168,7 +170,13 @@ operations:
           attributes: *ifaddr-all
     -
       name: getmulticast
-      doc: Get / dump IPv4/IPv6 multicast addresses.
+      doc: |
+        Get / dump multicast addresses. ifa-family must select the address
+        family: AF_INET or AF_INET6 for the IP multicast groups joined on
+        a device, AF_PACKET for the link-layer multicast addresses in the
+        device filter. Link-layer entries added explicitly, e.g. with
+        SIOCADDMULTI or "bridge fdb add ... self", rather than by a
+        protocol join are reported with the global flag set.
       attribute-set: addr-attrs
       fixed-header: ifaddrmsg
       do:
@@ -181,10 +189,13 @@ operations:
             - multicast
             - mc-users
             - cacheinfo
+            - flags
+            - target-netnsid
       dump:
         request:
           value: 58
-          attributes: []
+          attributes:
+            - target-netnsid
         reply:
           value: 58
           attributes: *mcaddr-attrs
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH net-next v5 4/4] selftests: net: test AF_PACKET multicast dumps
  2026-09-14  1:45 [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
                   ` (2 preceding siblings ...)
  2026-09-14  1:45 ` [PATCH net-next v5 3/4] netlink: specs: rt-addr: document " Yuyang Huang
@ 2026-09-14  1:45 ` Yuyang Huang
  2026-09-14 16:04   ` Nicolas Dichtel
                     ` (2 more replies)
  2026-09-17  1:47 ` [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses Jakub Kicinski
  4 siblings, 3 replies; 13+ messages in thread
From: Yuyang Huang @ 2026-09-14  1:45 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: Andrew Lunn, David S. Miller, David Ahern, Donald Hunter,
	Eric Dumazet, Ido Schimmel, Jacob Keller, Jakub Kicinski,
	Kuniyuki Iwashima, Nicolas Dichtel, Nikolaos Gkarlis,
	Paolo Abeni, Sabrina Dubroca, Shuah Khan, Simon Horman,
	Stanislav Fomichev, linux-kernel, linux-kselftest, netdev

Dump the link-layer multicast addresses of a dummy device and verify
that ifa_index restricts the dump to that device, that the all-hosts
address joined on link up is listed without IFA_F_GLOBAL, that an
address added with SIOCADDMULTI is listed with IFA_F_GLOBAL and
IFA_MC_USERS, and that IFA_TARGET_NETNSID dumps another netns. Skip
when the kernel does not support AF_PACKET dumps.

Signed-off-by: Yuyang Huang <sigefriedhyy@gmail.com>
---
 tools/testing/selftests/net/rtnetlink.py | 75 +++++++++++++++++++++++-
 1 file changed, 72 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/net/rtnetlink.py b/tools/testing/selftests/net/rtnetlink.py
index 5cc3ebdcf08d..d69d375a2def 100755
--- a/tools/testing/selftests/net/rtnetlink.py
+++ b/tools/testing/selftests/net/rtnetlink.py
@@ -1,17 +1,21 @@
 #!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0
 
+import errno
 import socket
 import struct
 import time
 from lib.py import bkg, ip, ksft_exit, ksft_run, ksft_eq, ksft_ge, ksft_true, KsftSkipEx
-from lib.py import ksft_not_in, ksft_not_none
-from lib.py import CmdExitFailure, NetNS, NetNSEnter, RtnlAddrFamily, RtnlRouteFamily
+from lib.py import ksft_in, ksft_not_in, ksft_not_none
+from lib.py import CmdExitFailure, NetNS, NetNSEnter, NlError, RtnlAddrFamily, RtnlRouteFamily
 from lib.py import defer
 
 IPV4_ALL_HOSTS_MULTICAST = b'\xe0\x00\x00\x01'
 IPV4_TEST_MULTICAST = b'\xef\x01\x01\x01'
 IPV6_TEST_MULTICAST = bytes.fromhex('ff020000000000000000000000000123')
+ETH_ALL_HOSTS_MULTICAST = bytes.fromhex('01005e000001')
+ETH_TEST_MULTICAST_STR = '01:00:5e:01:01:01'
+ETH_TEST_MULTICAST = bytes.fromhex(ETH_TEST_MULTICAST_STR.replace(':', ''))
 
 
 def _users_for(rtnl: RtnlAddrFamily, family: int, grp: bytes, ifindex: int):
@@ -105,6 +109,70 @@ def dump_mcaddr6_check() -> None:
                 s2.close()
 
 
+def dump_mcaddr_l2_check() -> None:
+    """
+    Verify link-layer multicast addresses in an AF_PACKET RTM_GETMULTICAST
+    dump: the ifa-index filter, mc-users, the global flag and
+    target-netnsid.
+    """
+
+    with NetNS() as ns, NetNSEnter(str(ns)):
+        for ifname in ("dummy1", "dummy2"):
+            ip(f"link add name {ifname} type dummy")
+            ip(f"link set {ifname} up")
+        dev_idx = socket.if_nametoindex("dummy1")
+        ip(f"maddr add {ETH_TEST_MULTICAST_STR} dev dummy1")
+
+        rtnl = RtnlAddrFamily()
+        defer(rtnl.close)
+        try:
+            addresses = rtnl.getmulticast(
+                {"ifa-family": socket.AF_PACKET, "ifa-index": dev_idx},
+                dump=True)
+        except NlError as e:
+            if e.error == errno.EOPNOTSUPP:
+                raise KsftSkipEx(
+                    "kernel does not support AF_PACKET multicast dump")
+            raise
+
+        # dummy2 has entries as well, only dummy1 may be listed
+        ksft_eq({addr['ifa-index'] for addr in addresses}, {dev_idx},
+                "AF_PACKET multicast dump ignored ifa-index filter")
+
+        entries = {addr['multicast']: addr for addr in addresses}
+
+        # Bringing an Ethernet device up joins 224.0.0.1, which maps
+        # to 01:00:5e:00:00:01 in the device multicast list.
+        all_hosts = entries.get(ETH_ALL_HOSTS_MULTICAST)
+        ksft_not_none(all_hosts,
+                      "dummy1 does not have the all-hosts link-layer address")
+        if all_hosts is not None:
+            ksft_not_in('global', all_hosts['flags'],
+                        "protocol entry is global")
+
+        static = entries.get(ETH_TEST_MULTICAST)
+        ksft_not_none(static, "dummy1 does not have the SIOCADDMULTI address")
+        if static is not None:
+            ksft_eq(static['mc-users'], 1,
+                    "unexpected mc-users for the SIOCADDMULTI address")
+            ksft_in('global', static['flags'],
+                    "SIOCADDMULTI entry is not global")
+
+        # target-netnsid dumps another netns, ifa-index is relative to it
+        with NetNS() as peer:
+            ip(f"netns set {peer} 5")
+            ip("link add name dummy3 type dummy", ns=peer)
+            ip("link set dummy3 up", ns=peer)
+            peer_idx = ip("link show dummy3", json=True, ns=peer)[0]['ifindex']
+
+            addresses = rtnl.getmulticast(
+                {"ifa-family": socket.AF_PACKET, "target-netnsid": 5,
+                 "ifa-index": peer_idx}, dump=True)
+            ksft_eq({(addr['ifa-index'], addr['target-netnsid'])
+                     for addr in addresses}, {(peer_idx, 5)},
+                    "target-netnsid did not dump the peer netns")
+
+
 def ipv4_devconf_notify() -> None:
     """
     Configure an interface and set ipv4-devconf values through netlink
@@ -315,7 +383,8 @@ def ipv6_route_del_reason_absent() -> None:
 
 
 def main() -> None:
-    ksft_run([dump_mcaddr_check, dump_mcaddr6_check, ipv4_devconf_notify,
+    ksft_run([dump_mcaddr_check, dump_mcaddr6_check, dump_mcaddr_l2_check,
+              ipv4_devconf_notify,
               ipv6_route_del_reason_expired,
               ipv6_route_del_reason_ra_withdrawn,
               ipv6_route_del_reason_absent])
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next v5 4/4] selftests: net: test AF_PACKET multicast dumps
  2026-09-14  1:45 ` [PATCH net-next v5 4/4] selftests: net: test " Yuyang Huang
@ 2026-09-14 16:04   ` Nicolas Dichtel
  2026-09-15 16:47   ` netdev-bot+sashiko
  2026-09-17  1:54   ` Jakub Kicinski
  2 siblings, 0 replies; 13+ messages in thread
From: Nicolas Dichtel @ 2026-09-14 16:04 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: Andrew Lunn, David S. Miller, David Ahern, Donald Hunter,
	Eric Dumazet, Ido Schimmel, Jacob Keller, Jakub Kicinski,
	Kuniyuki Iwashima, Nikolaos Gkarlis, Paolo Abeni,
	Sabrina Dubroca, Shuah Khan, Simon Horman, Stanislav Fomichev,
	linux-kernel, linux-kselftest, netdev

Le 14/09/2026 à 03:45, Yuyang Huang a écrit :
> Dump the link-layer multicast addresses of a dummy device and verify
> that ifa_index restricts the dump to that device, that the all-hosts
> address joined on link up is listed without IFA_F_GLOBAL, that an
> address added with SIOCADDMULTI is listed with IFA_F_GLOBAL and
> IFA_MC_USERS, and that IFA_TARGET_NETNSID dumps another netns. Skip
> when the kernel does not support AF_PACKET dumps.
> 
> Signed-off-by: Yuyang Huang <sigefriedhyy@gmail.com>
Reviewed-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next v5 2/4] rtnetlink: add AF_PACKET multicast dumps
  2026-09-14  1:45 ` [PATCH net-next v5 2/4] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
@ 2026-09-15 16:47   ` netdev-bot+sashiko
  2026-09-17  1:49   ` Jakub Kicinski
  1 sibling, 0 replies; 13+ messages in thread
From: netdev-bot+sashiko @ 2026-09-15 16:47 UTC (permalink / raw)
  To: sigefriedhyy
  Cc: andrew+netdev, davem, dsahern, donald.hunter, edumazet, idosch,
	jacob.e.keller, kuba, kuniyu, nicolas.dichtel, nickgarlis,
	pabeni, sd, shuah, horms, sdf.kernel, linux-kernel,
	linux-kselftest, netdev

Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 1 · Low: 2

- [Medium] AF_PACKET RTM_GETMULTICAST dump
  (rtnl_dump_mcaddr()/rtnl_dump_mcaddr_dev(),…
- [Low] Commit "netlink: specs: rt-addr: fix the type of target-netnsid"
  (first patch of this series) changes Documentation/netlink/specs/rt-…
- [Low] Reported concern (validated as resolved within this series): the
  rt-addr YAML spec did not describe the new AF_PACKET RTM_GETMULTICAST…

--

rtnetlink: add AF_PACKET multicast dumps

This adds handling for RTM_GETMULTICAST dumps with ifa_family set to
AF_PACKET, reporting every entry of dev->mc in the existing ifaddrmsg
format.  A new IFA_F_GLOBAL uAPI flag reports netdev_hw_addr::global_use,
and the dump runs under RCU plus netif_addr_lock_bh() without RTNL.

> diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h
> index 7fb630b7fe311..0a1ad9ebb47be 100644
> --- a/include/uapi/linux/if_addr.h
> +++ b/include/uapi/linux/if_addr.h
> @@ -57,6 +57,7 @@ enum {
>  #define IFA_F_NOPREFIXROUTE	0x200
>  #define IFA_F_MCAUTOJOIN	0x400
>  #define IFA_F_STABLE_PRIVACY	0x800
> +#define IFA_F_GLOBAL		0x1000

[Severity: Low]

This isn't a bug, but at this commit Documentation/netlink/specs/rt-addr.yaml
has no "global" entry in the ifa-flags enum for bit 12, and the getmulticast
op still lists an empty dump-request attribute list plus a reply set without
"flags" or "target-netnsid".  Spec-driven decoders such as ynl therefore
cannot name the new flag or validate the new AF_PACKET reply.

The next patch in the series ("netlink: specs: rt-addr: document AF_PACKET
multicast dumps") adds all of that, so this looks like nothing more than a
transient state inside the series.  Would it be worth folding the two
patches, or does the ordering matter for something else?

>  
>  struct ifa_cacheinfo {
>  	__u32	ifa_prefered;
> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> index be9d1625bac31..5f3e692a828b8 100644
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -4571,6 +4571,178 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
>  	return skb->len ? : ret;
>  }
>  
> +static int rtnl_fill_mcaddr(struct sk_buff *skb, const struct net_device *dev,
> +			    const struct netdev_hw_addr *ha, u32 portid,
> +			    u32 seq, unsigned int flags, int netnsid)
> +{

[ ... ]

> +	nlmsg_end(skb, nlh);
> +	return 0;
> +}
> +
> +static int rtnl_dump_mcaddr_dev(struct net_device *dev, struct sk_buff *skb,
> +				struct netlink_callback *cb, int *s_addr_idx,
> +				unsigned int flags, int netnsid)
> +{
> +	struct netdev_hw_addr *ha;
> +	int addr_idx = 0;
> +	int err = 0;
> +
> +	netif_addr_lock_bh(dev);
> +	netdev_for_each_mc_addr(ha, dev) {
> +		if (addr_idx < *s_addr_idx) {
> +			addr_idx++;
> +			continue;
> +		}
> +		err = rtnl_fill_mcaddr(skb, dev, ha, NETLINK_CB(cb->skb).portid,
> +				       cb->nlh->nlmsg_seq, flags, netnsid);
> +		if (err < 0)
> +			break;
> +		addr_idx++;
> +	}
> +	netif_addr_unlock_bh(dev);
> +
> +	*s_addr_idx = err < 0 ? addr_idx : 0;
> +
> +	return err;
> +}

[Severity: Medium]

The only resume state for a multi-part dump is a bare positional index into
dev->mc, and both netif_addr_lock_bh(dev) here and the rcu_read_lock() in
rtnl_dump_mcaddr() are dropped between dump rounds.

Can this silently skip or repeat entries of dev->mc?

Round N fills the skb until rtnl_fill_mcaddr() returns -EMSGSIZE and stores
the position:

	*s_addr_idx = err < 0 ? addr_idx : 0;

Round N+1 then skips exactly *s_addr_idx entries from the head of the list
again:

	netdev_for_each_mc_addr(ha, dev) {
		if (addr_idx < *s_addr_idx) {
			addr_idx++;
			continue;
		}

If a __dev_mc_del() or __dev_mc_add() runs in between (an IGMP/MLD join or
leave, SIOCADDMULTI, "bridge fdb add ... self", or a lower device sync), the
list shifts under the cursor.  A removal before the cursor means the entry
that moved into that slot is never emitted; an insertion means an
already-emitted entry is emitted a second time.

> +
> +struct rtnl_mcaddr_dump_filter {

[ ... ]

> +static int rtnl_dump_mcaddr(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct rtnl_mcaddr_dump_filter filter = {
> +		.tgt_net = sock_net(skb->sk),
> +		.netnsid = -1,
> +	};
> +	unsigned int flags = NLM_F_MULTI;
> +	struct {
> +		unsigned long ifindex;
> +		int addr_idx;
> +	} *ctx = (void *)cb->ctx;

[Severity: Medium]

Related to the cursor question above: cb->seq is never set to a generation
counter for dev->mc, and rtnl_fill_mcaddr() does not call
nl_dump_check_consistent(), so NLM_F_DUMP_INTR can never appear on an
emitted message or on NLMSG_DONE.  Does that leave user space unable to tell
a torn listing from a consistent one?

The IPv4 RTM_GETMULTICAST dump that this mirrors does both, in
net/ipv4/devinet.c:

	cb->seq = inet_base_seq(tgt_net);
	...
	nl_dump_check_consistent(cb, nlmsg_hdr(skb));

and net/ipv6/addrconf.c does the same with inet6_base_seq().  Is there
something about dev->mc that makes the stamping unnecessary here, or should
this dump grow an equivalent counter?

> +	unsigned long s_ifindex;
> +	struct net_device *dev;
> +	int err;
> +

[ ... ]

> +	s_ifindex = ctx->ifindex;
> +	for_each_netdev_dump(filter.tgt_net, dev, ctx->ifindex) {
> +		/* The device the dump stopped at is gone, do not skip
> +		 * entries of the next one.
> +		 */
> +		if (dev->ifindex != s_ifindex)
> +			ctx->addr_idx = 0;
> +		err = rtnl_dump_mcaddr_dev(dev, skb, cb, &ctx->addr_idx, flags,
> +					   filter.netnsid);
> +		if (err < 0)
> +			break;
> +	}
> +out:
> +	rcu_read_unlock();
> +	if (filter.netnsid >= 0)
> +		put_net_track(filter.tgt_net, &filter.ns_tracker);
> +	return err;
> +}

One more note, on the first patch of the series rather than on this one:

[Severity: Low]

"netlink: specs: rt-addr: fix the type of target-netnsid" changes
addr-attrs.target-netnsid in Documentation/netlink/specs/rt-addr.yaml from

	type: binary

to s32, matching what the kernel actually parses in ifa_ipv4_policy
(net/ipv4/devinet.c) and ifa_ipv6_policy (net/ipv6/addrconf.c):

	[IFA_TARGET_NETNSID]	= { .type = NLA_S32 },

That is a fix to a machine-readable ABI description consumed by ynl and
generated bindings, but the patch carries no Fixes: tag.  git blame points
the "type: binary" line at dfb0f7d9d979 ("doc/netlink: Add spec for rt addr
messages"), and a prior spec fix, 0c8e30252d9fe ("netlink: specs: rt_addr:
pull the ifa- prefix out of the names"), tagged the same commit.  Should the
patch pick up:

	Fixes: dfb0f7d9d979 ("doc/netlink: Add spec for rt addr messages")

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260914014539.5015-1-sigefriedhyy%40gmail.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next v5 3/4] netlink: specs: rt-addr: document AF_PACKET multicast dumps
  2026-09-14  1:45 ` [PATCH net-next v5 3/4] netlink: specs: rt-addr: document " Yuyang Huang
@ 2026-09-15 16:47   ` netdev-bot+sashiko
  0 siblings, 0 replies; 13+ messages in thread
From: netdev-bot+sashiko @ 2026-09-15 16:47 UTC (permalink / raw)
  To: sigefriedhyy
  Cc: andrew+netdev, davem, dsahern, donald.hunter, edumazet, idosch,
	jacob.e.keller, kuba, kuniyu, nicolas.dichtel, nickgarlis,
	pabeni, sd, shuah, horms, sdf.kernel, linux-kernel,
	linux-kselftest, netdev

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 0 (1) · Low: 1 (1)

- [Low] The new `getmulticast` doc text (Documentation/netlink/specs/rt-
  addr.yaml:173-179) documents only the ifa-family selector.

Pre-existing issues:
- [Medium] Documentation/netlink/specs/rt-addr.yaml describes a `do`
  (single-message get) variant of `getmulticast` (lines 182-193), and…
- [Low] The patch adds `target-netnsid` to the shared `getmulticast`
  reply attribute set (&mcaddr-attrs, Documentation/netlink/specs/rt-…

--

netlink: specs: rt-addr: document AF_PACKET multicast dumps

This adds the global address flag to the rt-addr spec, extends the
getmulticast reply attribute list with flags and target-netnsid, and
rewrites the operation doc to explain how ifa-family selects IPv4, IPv6
or link-layer output.

> diff --git a/Documentation/netlink/specs/rt-addr.yaml b/Documentation/netlink/specs/rt-addr.yaml
> index 17ead22034515..1a17e55d1cca0 100644
> --- a/Documentation/netlink/specs/rt-addr.yaml
> +++ b/Documentation/netlink/specs/rt-addr.yaml

[ ... ]

> @@ -168,7 +170,13 @@ operations:
>            attributes: *ifaddr-all
>      -
>        name: getmulticast
> -      doc: Get / dump IPv4/IPv6 multicast addresses.
> +      doc: |
> +        Get / dump multicast addresses. ifa-family must select the address
> +        family: AF_INET or AF_INET6 for the IP multicast groups joined on
> +        a device, AF_PACKET for the link-layer multicast addresses in the
> +        device filter. Link-layer entries added explicitly, e.g. with
> +        SIOCADDMULTI or "bridge fdb add ... self", rather than by a
> +        protocol join are reported with the global flag set.

[Severity: Low]
This isn't a bug, but the new doc text describes only the ifa-family
selector, while the AF_PACKET dump path added by the sibling commit
"rtnetlink: add AF_PACKET multicast dumps" enforces two further
request-side rules in rtnl_valid_dump_mcaddr_req():

net/core/rtnetlink.c:rtnl_valid_dump_mcaddr_req() {
	if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) {
		NL_SET_ERR_MSG(extack,
			       "Invalid values in multicast dump header");
		return -EINVAL;
	}
	...
	filter->ifindex = ifm->ifa_index;
}

Should the doc mention that ifa_prefixlen, ifa_flags and ifa_scope must
be zero for AF_PACKET, which is stricter than the AF_INET/AF_INET6
behaviour of the same operation?

A caller reusing an ifaddrmsg from a getaddr reply, with a non-zero
ifa_scope still in it, gets -EINVAL with nothing in the spec explaining
why.

Should the doc also mention that ifa-index restricts the dump to a single
device, and that the reply then carries NLM_F_DUMP_FILTERED? Right now
that filter is not discoverable from the spec.

>        attribute-set: addr-attrs
>        fixed-header: ifaddrmsg
>        do:
> @@ -181,10 +189,13 @@ operations:
>              - multicast
>              - mc-users
>              - cacheinfo
> +            - flags
> +            - target-netnsid

[Severity: Medium]
This isn't a problem introduced by this patch, but since the patch
extends this block it may be worth resolving here: the spec advertises a
do (single-message get) variant of getmulticast, yet no family registers
a doit handler for RTM_GETMULTICAST.

net/ipv4/devinet.c:
	{.owner = THIS_MODULE, .protocol = PF_INET, .msgtype = RTM_GETMULTICAST,
	 .dumpit = inet_dump_ifmcaddr, .flags = RTNL_FLAG_DUMP_UNLOCKED},

net/ipv6/addrconf.c:
	{.owner = THIS_MODULE, .protocol = PF_INET6, .msgtype = RTM_GETMULTICAST,
	 .dumpit = inet6_dump_ifmcaddr,
	 .flags = RTNL_FLAG_DUMP_UNLOCKED},

net/core/rtnetlink.c (the new AF_PACKET registration):
	{.protocol = PF_PACKET, .msgtype = RTM_GETMULTICAST,
	 .dumpit = rtnl_dump_mcaddr, .flags = RTNL_FLAG_DUMP_UNLOCKED},

All three provide .dumpit only, and there is no PF_UNSPEC entry, so a
non-dump request ends up here:

net/core/rtnetlink.c:rtnetlink_rcv_msg() {
	link = rtnl_get_link(family, type);
	if (!link || !link->doit) {
		family = PF_UNSPEC;
		link = rtnl_get_link(PF_UNSPEC, type);
		if (!link || !link->doit)
			goto out_unlock;
	}
}

and returns -EOPNOTSUPP. Would it make sense to drop the do: block
instead of extending its reply list, so ynl-generated clients do not
emit a single-object get that can never succeed?

[Severity: Low]
This is a pre-existing kernel-side gap rather than something this patch
introduces, but target-netnsid is being added to the shared
&mcaddr-attrs anchor used by all three families. The AF_PACKET and
AF_INET6 emitters do put the attribute:

net/core/rtnetlink.c:rtnl_fill_mcaddr() {
	if ((netnsid >= 0 &&
	     nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) ||
}

net/ipv6/addrconf.c:inet6_fill_ifmcaddr() {
	if (args->netnsid >= 0 &&
	    nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) {
}

The AF_INET emitter does not, even though inet_valid_dump_ifaddr_req()
accepts IFA_TARGET_NETNSID and stores it in fillargs.netnsid:

net/ipv4/igmp.c:inet_fill_ifmcaddr() {
	if (nla_put_in_addr(skb, IFA_MULTICAST, im->multiaddr) < 0 ||
	    nla_put_u32(skb, IFA_MC_USERS, READ_ONCE(im->users)) < 0 ||
	    nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci) < 0) {
}

So an AF_INET multicast dump against another namespace never reports the
netnsid that its AF_INET6 and AF_PACKET peers report. Would a one-line
follow-up in inet_fill_ifmcaddr() be worth doing so the three families
agree with what the spec now lists?

>        dump:
>          request:
>            value: 58
> -          attributes: []
> +          attributes:
> +            - target-netnsid
>          reply:
>            value: 58
>            attributes: *mcaddr-attrs

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260914014539.5015-1-sigefriedhyy%40gmail.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next v5 4/4] selftests: net: test AF_PACKET multicast dumps
  2026-09-14  1:45 ` [PATCH net-next v5 4/4] selftests: net: test " Yuyang Huang
  2026-09-14 16:04   ` Nicolas Dichtel
@ 2026-09-15 16:47   ` netdev-bot+sashiko
  2026-09-16 11:40     ` Yuyang Huang
  2026-09-17  1:54   ` Jakub Kicinski
  2 siblings, 1 reply; 13+ messages in thread
From: netdev-bot+sashiko @ 2026-09-15 16:47 UTC (permalink / raw)
  To: sigefriedhyy
  Cc: andrew+netdev, davem, dsahern, donald.hunter, edumazet, idosch,
	jacob.e.keller, kuba, kuniyu, nicolas.dichtel, nickgarlis,
	pabeni, sd, shuah, horms, sdf.kernel, linux-kernel,
	linux-kselftest, netdev

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 1 · Low: 0

- [Medium] In `dump_mcaddr_l2_check()`
  (tools/testing/selftests/net/rtnetlink.py:161-173) the…

--

selftests: net: test AF_PACKET multicast dumps

This adds dump_mcaddr_l2_check() to tools/testing/selftests/net/rtnetlink.py,
dumping the link-layer multicast list of a dummy device and checking the
ifa-index filter, the global flag, mc-users, and a dump of another netns via
target-netnsid. The test skips when the kernel returns EOPNOTSUPP for the
AF_PACKET dump.

> diff --git a/tools/testing/selftests/net/rtnetlink.py b/tools/testing/selftests/net/rtnetlink.py
> index 5cc3ebdcf08de..d69d375a2deff 100755
> --- a/tools/testing/selftests/net/rtnetlink.py
> +++ b/tools/testing/selftests/net/rtnetlink.py

[ ... ]

> @@ -105,6 +109,70 @@ def dump_mcaddr6_check() -> None:
>                  s2.close()
>  
>  
> +def dump_mcaddr_l2_check() -> None:
> +    """
> +    Verify link-layer multicast addresses in an AF_PACKET RTM_GETMULTICAST
> +    dump: the ifa-index filter, mc-users, the global flag and
> +    target-netnsid.
> +    """
> +
> +    with NetNS() as ns, NetNSEnter(str(ns)):
> +        for ifname in ("dummy1", "dummy2"):
> +            ip(f"link add name {ifname} type dummy")
> +            ip(f"link set {ifname} up")
> +        dev_idx = socket.if_nametoindex("dummy1")
> +        ip(f"maddr add {ETH_TEST_MULTICAST_STR} dev dummy1")
> +

[ ... ]

> +        # target-netnsid dumps another netns, ifa-index is relative to it
> +        with NetNS() as peer:
> +            ip(f"netns set {peer} 5")
> +            ip("link add name dummy3 type dummy", ns=peer)
> +            ip("link set dummy3 up", ns=peer)
> +            peer_idx = ip("link show dummy3", json=True, ns=peer)[0]['ifindex']
> +
> +            addresses = rtnl.getmulticast(
> +                {"ifa-family": socket.AF_PACKET, "target-netnsid": 5,
> +                 "ifa-index": peer_idx}, dump=True)
> +            ksft_eq({(addr['ifa-index'], addr['target-netnsid'])
> +                     for addr in addresses}, {(peer_idx, 5)},
> +                    "target-netnsid did not dump the peer netns")

[Severity: Medium]
Can this final assertion actually distinguish a dump of the peer netns from
a dump of the socket's own netns?

The test body runs inside a fresh netns, so lo is 1, dummy1 is 2 and dummy2
is 3, making dev_idx equal to 2.  The peer netns is created by NetNS(), which
just does:

tools/testing/selftests/net/lib/py/netns.py:NetNS.__init__() {
    ...
    ip('netns add ' + self.name)
    ...
}

so the peer contains only lo (1) plus dummy3, and peer_idx ends up as 2 as
well - the same ifindex as dummy1 in the enclosing netns.

On the kernel side, rtnl_dump_mcaddr() starts with the socket's namespace:

net/core/rtnetlink.c:rtnl_dump_mcaddr() {
    ...
    struct rtnl_mcaddr_dump_filter filter = {
        .tgt_net = sock_net(skb->sk),
    ...
    dev = dev_get_by_index_rcu(filter.tgt_net, filter.ifindex);
    ...
}

If filter.tgt_net were left at sock_net(skb->sk) instead of the resolved peer
net, the lookup of ifindex 2 returns the local dummy1, and the entries are
emitted with ifa_index 2.  IFA_TARGET_NETNSID is then echoed straight back
from the request value:

net/core/rtnetlink.c:rtnl_fill_mcaddr() {
    ...
    if ((netnsid >= 0 &&
         nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) ||
    ...
}

so the reply set is {(2, 5)}, which is exactly what ksft_eq() expects here.
Would a kernel that parsed target-netnsid but iterated the wrong struct net
still pass this check?

The commit message says the test verifies "that IFA_TARGET_NETNSID dumps
another netns" - is that claim accurate given the above?

Would it help to make the peer namespace distinguishable, for example by
adding a unique address with ip maddr add ... dev dummy3 in the peer netns
and asserting that address shows up, and/or by creating extra devices so peer
ifindices cannot collide with the local ones?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260914014539.5015-1-sigefriedhyy%40gmail.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next v5 4/4] selftests: net: test AF_PACKET multicast dumps
  2026-09-15 16:47   ` netdev-bot+sashiko
@ 2026-09-16 11:40     ` Yuyang Huang
  0 siblings, 0 replies; 13+ messages in thread
From: Yuyang Huang @ 2026-09-16 11:40 UTC (permalink / raw)
  To: netdev-bot+sashiko
  Cc: andrew+netdev, davem, dsahern, donald.hunter, edumazet, idosch,
	jacob.e.keller, kuba, kuniyu, nicolas.dichtel, nickgarlis,
	pabeni, sd, shuah, horms, sdf.kernel, linux-kernel,
	linux-kselftest, netdev

> Can this final assertion actually distinguish a dump of the peer netns from
> a dump of the socket's own netns?

> Should the doc mention that ifa_prefixlen, ifa_flags and ifa_scope must
> be zero for AF_PACKET

I checked all the Sashiko comments on this patchset. The two above are
real, but they look like nits and are not worth a v6 on their own.

I will fix them in v6 if a v6 is needed for other reasons.

Thanks,
Yuyang

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses
  2026-09-14  1:45 [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
                   ` (3 preceding siblings ...)
  2026-09-14  1:45 ` [PATCH net-next v5 4/4] selftests: net: test " Yuyang Huang
@ 2026-09-17  1:47 ` Jakub Kicinski
  4 siblings, 0 replies; 13+ messages in thread
From: Jakub Kicinski @ 2026-09-17  1:47 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: Andrew Lunn, David S. Miller, David Ahern, Donald Hunter,
	Eric Dumazet, Ido Schimmel, Jacob Keller, Kuniyuki Iwashima,
	Nicolas Dichtel, Nikolaos Gkarlis, Paolo Abeni, Sabrina Dubroca,
	Shuah Khan, Simon Horman, Stanislav Fomichev, linux-kernel,
	linux-kselftest, netdev

On Mon, 14 Sep 2026 10:45:35 +0900 Yuyang Huang wrote:
> "ip maddr show" prints three kinds of entries: link-layer, IPv4 and
> IPv6. The IPv4 and IPv6 ones can be read over netlink today: IPv6 has
> had RTM_GETMULTICAST for a long time and IPv4 got it in eb4e17a1d915
> ("netlink: support dumping IPv4 multicast addresses"), with IFA_MC_USERS
> added later so the user count no longer has to come from procfs.

You compare the situation to IP but for L2 the UC addresses
are not exposed via RTM_GETADDR. Are you going to add it?

> The link-layer list is the missing piece. dev->mc, the addresses
> programmed into the device filter, is only exported via
> /proc/net/dev_mcast, so iproute2 still carries a procfs parser just for
> that. This series closes the gap so that "ip maddr show" can be served
> from rtnetlink alone.

Is that the only justification? To avoid reading proc?
Are you planning to extend this interface with new features?

> Patch 1 fixes the type of target-netnsid in the rt-addr spec. Patch 2
> handles RTM_GETMULTICAST dumps with ifa_family set to AF_PACKET and
> walks dev->mc under netif_addr_lock_bh(), no RTNL. The reply reuses
> the ifaddrmsg format of the IPv4 and IPv6 dumps: IFA_MULTICAST carries
> the raw link-layer address, IFA_MC_USERS the reference count, and a new
> IFA_F_GLOBAL flag in IFA_FLAGS marks entries added explicitly, which is
> the "static" column /proc/net/dev_mcast has and "ip maddr" prints. A
> non-zero ifa_index limits the dump to one device and IFA_TARGET_NETNSID
> selects another netns, like the IPv4 and IPv6 dumps.
> 
> Patch 3 updates the rt-addr spec and patch 4 adds a selftest that
> checks the filter, the user count, the global flag and target-netnsid.
> 
> Nothing changes for other families. AF_PACKET dumps returned
> -EOPNOTSUPP before, so iproute2 can keep the procfs fallback for older
> kernels. I have the iproute2 side ready and will post it once this is
> in; with it, "ip maddr show" does not open /proc/net at all.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next v5 2/4] rtnetlink: add AF_PACKET multicast dumps
  2026-09-14  1:45 ` [PATCH net-next v5 2/4] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
  2026-09-15 16:47   ` netdev-bot+sashiko
@ 2026-09-17  1:49   ` Jakub Kicinski
  1 sibling, 0 replies; 13+ messages in thread
From: Jakub Kicinski @ 2026-09-17  1:49 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: Andrew Lunn, David S. Miller, David Ahern, Donald Hunter,
	Eric Dumazet, Ido Schimmel, Jacob Keller, Kuniyuki Iwashima,
	Nicolas Dichtel, Nikolaos Gkarlis, Paolo Abeni, Sabrina Dubroca,
	Shuah Khan, Simon Horman, Stanislav Fomichev, linux-kernel,
	linux-kselftest, netdev

On Mon, 14 Sep 2026 10:45:37 +0900 Yuyang Huang wrote:
>  net/core/rtnetlink.c         | 174 +++++++++++++++++++++++++++++++++++
>  2 files changed, 175 insertions(+)

I don't think we need another 200 LoC in rtnetlink.c ?
Especially if we make a precedent for AF_PACKET and someone decides 
to even add more code later.
The AI report about consistency check is probably good to act on as
well?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next v5 4/4] selftests: net: test AF_PACKET multicast dumps
  2026-09-14  1:45 ` [PATCH net-next v5 4/4] selftests: net: test " Yuyang Huang
  2026-09-14 16:04   ` Nicolas Dichtel
  2026-09-15 16:47   ` netdev-bot+sashiko
@ 2026-09-17  1:54   ` Jakub Kicinski
  2 siblings, 0 replies; 13+ messages in thread
From: Jakub Kicinski @ 2026-09-17  1:54 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: Andrew Lunn, David S. Miller, David Ahern, Donald Hunter,
	Eric Dumazet, Ido Schimmel, Jacob Keller, Kuniyuki Iwashima,
	Nicolas Dichtel, Nikolaos Gkarlis, Paolo Abeni, Sabrina Dubroca,
	Shuah Khan, Simon Horman, Stanislav Fomichev, linux-kernel,
	linux-kselftest, netdev

On Mon, 14 Sep 2026 10:45:39 +0900 Yuyang Huang wrote:
> +        try:
> +            addresses = rtnl.getmulticast(
> +                {"ifa-family": socket.AF_PACKET, "ifa-index": dev_idx},
> +                dump=True)
> +        except NlError as e:
> +            if e.error == errno.EOPNOTSUPP:
> +                raise KsftSkipEx(
> +                    "kernel does not support AF_PACKET multicast dump")

What's the point of catching this exception?
The error for ENOPNOTSUPP will be both very rare (not sure I understand
where you expect it to come from TBH), and also about as meaningful as 
the skip. Just let the exception propagate, it's fine.

Otherwise Pylint complains:
W0707: Consider explicitly re-raising using 'raise KsftSkipEx('kernel does not support AF_PACKET multicast dump') from e' (raise-missing-from)


> +            raise

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-09-17  1:54 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-14  1:45 [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
2026-09-14  1:45 ` [PATCH net-next v5 1/4] netlink: specs: rt-addr: fix the type of target-netnsid Yuyang Huang
2026-09-14  1:45 ` [PATCH net-next v5 2/4] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
2026-09-15 16:47   ` netdev-bot+sashiko
2026-09-17  1:49   ` Jakub Kicinski
2026-09-14  1:45 ` [PATCH net-next v5 3/4] netlink: specs: rt-addr: document " Yuyang Huang
2026-09-15 16:47   ` netdev-bot+sashiko
2026-09-14  1:45 ` [PATCH net-next v5 4/4] selftests: net: test " Yuyang Huang
2026-09-14 16:04   ` Nicolas Dichtel
2026-09-15 16:47   ` netdev-bot+sashiko
2026-09-16 11:40     ` Yuyang Huang
2026-09-17  1:54   ` Jakub Kicinski
2026-09-17  1:47 ` [PATCH net-next v5 0/4] rtnetlink: dump link-layer multicast addresses Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®