* [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses
@ 2026-09-09 13:32 Yuyang Huang
2026-09-09 13:32 ` [PATCH net-next v3 1/4] netlink: specs: rt-addr: fix the type of target-netnsid Yuyang Huang
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Yuyang Huang @ 2026-09-09 13:32 UTC (permalink / raw)
To: Yuyang Huang
Cc: David S. Miller, David Ahern, Donald Hunter, Eric Dumazet,
Ido Schimmel, 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 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 | 165 +++++++++++++++++++++++
tools/testing/selftests/net/rtnetlink.py | 71 +++++++++-
4 files changed, 248 insertions(+), 6 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH net-next v3 1/4] netlink: specs: rt-addr: fix the type of target-netnsid
2026-09-09 13:32 [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
@ 2026-09-09 13:32 ` Yuyang Huang
2026-09-09 16:09 ` Nicolas Dichtel
2026-09-09 13:32 ` [PATCH net-next v3 2/4] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Yuyang Huang @ 2026-09-09 13:32 UTC (permalink / raw)
To: Yuyang Huang
Cc: David S. Miller, David Ahern, Donald Hunter, Eric Dumazet,
Ido Schimmel, 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.
Fixes: dfb0f7d9d979 ("doc/netlink: Add spec for rt addr messages")
Signed-off-by: Yuyang Huang <sigefriedhyy@gmail.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] 12+ messages in thread
* [PATCH net-next v3 2/4] rtnetlink: add AF_PACKET multicast dumps
2026-09-09 13:32 [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
2026-09-09 13:32 ` [PATCH net-next v3 1/4] netlink: specs: rt-addr: fix the type of target-netnsid Yuyang Huang
@ 2026-09-09 13:32 ` Yuyang Huang
2026-09-10 13:50 ` netdev-bot+sashiko
2026-09-09 13:32 ` [PATCH net-next v3 3/4] netlink: specs: rt-addr: document " Yuyang Huang
` (2 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Yuyang Huang @ 2026-09-09 13:32 UTC (permalink / raw)
To: Yuyang Huang
Cc: David S. Miller, David Ahern, Donald Hunter, Eric Dumazet,
Ido Schimmel, 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"), and
AF_UNSPEC keeps its "all families" meaning from RTM_GETADDR.
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>
---
include/uapi/linux/if_addr.h | 1 +
net/core/rtnetlink.c | 165 +++++++++++++++++++++++++++++++++++
2 files changed, 166 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 81c5a6104dea..f54e9cb3bf30 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -4566,6 +4566,169 @@ 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;
+ 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);
+ }
+ 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;
+ 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;
+ }
+
+ for_each_netdev_dump(filter.tgt_net, dev, ctx->ifindex) {
+ 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(filter.tgt_net);
+ 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,
@@ -7251,6 +7414,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] 12+ messages in thread
* [PATCH net-next v3 3/4] netlink: specs: rt-addr: document AF_PACKET multicast dumps
2026-09-09 13:32 [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
2026-09-09 13:32 ` [PATCH net-next v3 1/4] netlink: specs: rt-addr: fix the type of target-netnsid Yuyang Huang
2026-09-09 13:32 ` [PATCH net-next v3 2/4] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
@ 2026-09-09 13:32 ` Yuyang Huang
2026-09-09 13:32 ` [PATCH net-next v3 4/4] selftests: net: test " Yuyang Huang
2026-09-09 14:22 ` [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Nicolas Dichtel
4 siblings, 0 replies; 12+ messages in thread
From: Yuyang Huang @ 2026-09-09 13:32 UTC (permalink / raw)
To: Yuyang Huang
Cc: David S. Miller, David Ahern, Donald Hunter, Eric Dumazet,
Ido Schimmel, 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>
---
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..adf82b69ade7 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 selects 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] 12+ messages in thread
* [PATCH net-next v3 4/4] selftests: net: test AF_PACKET multicast dumps
2026-09-09 13:32 [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
` (2 preceding siblings ...)
2026-09-09 13:32 ` [PATCH net-next v3 3/4] netlink: specs: rt-addr: document " Yuyang Huang
@ 2026-09-09 13:32 ` Yuyang Huang
2026-09-10 13:50 ` netdev-bot+sashiko
2026-09-09 14:22 ` [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Nicolas Dichtel
4 siblings, 1 reply; 12+ messages in thread
From: Yuyang Huang @ 2026-09-09 13:32 UTC (permalink / raw)
To: Yuyang Huang
Cc: David S. Miller, David Ahern, Donald Hunter, Eric Dumazet,
Ido Schimmel, 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 | 71 +++++++++++++++++++++++-
1 file changed, 68 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/net/rtnetlink.py b/tools/testing/selftests/net/rtnetlink.py
index 5cc3ebdcf08d..41da259c3a09 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,66 @@ 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()
+ 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.
+ ksft_in(ETH_ALL_HOSTS_MULTICAST, entries,
+ "dummy1 does not have the all-hosts link-layer address")
+ ksft_not_in('global', entries[ETH_ALL_HOSTS_MULTICAST]['flags'],
+ "protocol entry is global")
+
+ ksft_in(ETH_TEST_MULTICAST, entries,
+ "dummy1 does not have the SIOCADDMULTI address")
+ ksft_eq(entries[ETH_TEST_MULTICAST]['mc-users'], 1,
+ "unexpected mc-users for the SIOCADDMULTI address")
+ ksft_in('global', entries[ETH_TEST_MULTICAST]['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},
+ 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 +379,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] 12+ messages in thread
* Re: [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses
2026-09-09 13:32 [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
` (3 preceding siblings ...)
2026-09-09 13:32 ` [PATCH net-next v3 4/4] selftests: net: test " Yuyang Huang
@ 2026-09-09 14:22 ` Nicolas Dichtel
2026-09-09 14:32 ` Yuyang Huang
4 siblings, 1 reply; 12+ messages in thread
From: Nicolas Dichtel @ 2026-09-09 14:22 UTC (permalink / raw)
To: Yuyang Huang
Cc: David S. Miller, David Ahern, Donald Hunter, Eric Dumazet,
Ido Schimmel, Jakub Kicinski, Kuniyuki Iwashima,
Nikolaos Gkarlis, Paolo Abeni, Sabrina Dubroca, Shuah Khan,
Simon Horman, Stanislav Fomichev, linux-kernel, linux-kselftest,
netdev
Le 09/09/2026 à 15:32, Yuyang Huang a écrit :
> "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 v3:
Please, wait 24 hours before sending a new version:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/maintainer-netdev.rst#n15
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses
2026-09-09 14:22 ` [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Nicolas Dichtel
@ 2026-09-09 14:32 ` Yuyang Huang
0 siblings, 0 replies; 12+ messages in thread
From: Yuyang Huang @ 2026-09-09 14:32 UTC (permalink / raw)
To: nicolas.dichtel
Cc: David S. Miller, David Ahern, Donald Hunter, Eric Dumazet,
Ido Schimmel, Jakub Kicinski, Kuniyuki Iwashima,
Nikolaos Gkarlis, Paolo Abeni, Sabrina Dubroca, Shuah Khan,
Simon Horman, Stanislav Fomichev, linux-kernel, linux-kselftest,
netdev
> Please, wait 24 hours before sending a new version:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/maintainer-netdev.rst#n15
Acked, will be more careful next time.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net-next v3 1/4] netlink: specs: rt-addr: fix the type of target-netnsid
2026-09-09 13:32 ` [PATCH net-next v3 1/4] netlink: specs: rt-addr: fix the type of target-netnsid Yuyang Huang
@ 2026-09-09 16:09 ` Nicolas Dichtel
2026-09-09 18:32 ` Jakub Kicinski
0 siblings, 1 reply; 12+ messages in thread
From: Nicolas Dichtel @ 2026-09-09 16:09 UTC (permalink / raw)
To: Yuyang Huang
Cc: David S. Miller, David Ahern, Donald Hunter, Eric Dumazet,
Ido Schimmel, Jakub Kicinski, Kuniyuki Iwashima,
Nikolaos Gkarlis, Paolo Abeni, Sabrina Dubroca, Shuah Khan,
Simon Horman, Stanislav Fomichev, linux-kernel, linux-kselftest,
netdev
Le 09/09/2026 à 15:32, Yuyang Huang a écrit :
> 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.
>
> Fixes: dfb0f7d9d979 ("doc/netlink: Add spec for rt addr messages")
> Signed-off-by: Yuyang Huang <sigefriedhyy@gmail.com>
This is a fix, so the target is net.
Could you submit it separately?
Regards,
Nicolas
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net-next v3 1/4] netlink: specs: rt-addr: fix the type of target-netnsid
2026-09-09 16:09 ` Nicolas Dichtel
@ 2026-09-09 18:32 ` Jakub Kicinski
2026-09-10 1:11 ` Yuyang Huang
0 siblings, 1 reply; 12+ messages in thread
From: Jakub Kicinski @ 2026-09-09 18:32 UTC (permalink / raw)
To: Nicolas Dichtel
Cc: Yuyang Huang, David S. Miller, David Ahern, Donald Hunter,
Eric Dumazet, Ido Schimmel, Kuniyuki Iwashima, Nikolaos Gkarlis,
Paolo Abeni, Sabrina Dubroca, Shuah Khan, Simon Horman,
Stanislav Fomichev, linux-kernel, linux-kselftest, netdev
On Wed, 9 Sep 2026 18:09:17 +0200 Nicolas Dichtel wrote:
> Le 09/09/2026 à 15:32, Yuyang Huang a écrit :
> > 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.
> >
> > Fixes: dfb0f7d9d979 ("doc/netlink: Add spec for rt addr messages")
> > Signed-off-by: Yuyang Huang <sigefriedhyy@gmail.com>
> This is a fix, so the target is net.
> Could you submit it separately?
We should just drop the Fixes tag instead
It never worked, and if someone cares they can use the latest YAML file
AI makes people slap Fixes tags on everything these days :/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net-next v3 1/4] netlink: specs: rt-addr: fix the type of target-netnsid
2026-09-09 18:32 ` Jakub Kicinski
@ 2026-09-10 1:11 ` Yuyang Huang
0 siblings, 0 replies; 12+ messages in thread
From: Yuyang Huang @ 2026-09-10 1:11 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Nicolas Dichtel, David S. Miller, David Ahern, Donald Hunter,
Eric Dumazet, Ido Schimmel, Kuniyuki Iwashima, Nikolaos Gkarlis,
Paolo Abeni, Sabrina Dubroca, Shuah Khan, Simon Horman,
Stanislav Fomichev, linux-kernel, linux-kselftest, netdev
>This is a fix, so the target is net.
>Could you submit it separately?
>We should just drop the Fixes tag instead
>It never worked, and if someone cares they can use the latest YAML file
>AI makes people slap Fixes tags on everything these days :/
Thanks for the advice, I will drop the Fixes tag in the next revision.
Though I think it will make sashiko unhappy....
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net-next v3 2/4] rtnetlink: add AF_PACKET multicast dumps
2026-09-09 13:32 ` [PATCH net-next v3 2/4] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
@ 2026-09-10 13:50 ` netdev-bot+sashiko
0 siblings, 0 replies; 12+ messages in thread
From: netdev-bot+sashiko @ 2026-09-10 13:50 UTC (permalink / raw)
To: sigefriedhyy
Cc: davem, dsahern, donald.hunter, edumazet, idosch, 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 4 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 2 · Low: 2
- [Medium] rtnl_dump_mcaddr()/rtnl_dump_mcaddr_dev()
(net/core/rtnetlink.c:4603-4728) resume a multi-part…
- [Medium] The commit message claims "AF_UNSPEC keeps its 'all families'
meaning from RTM_GETADDR".
- [Low] Incomplete submission claim: the new IFA_F_GLOBAL uAPI flag is
added only to include/uapi/linux/if_addr.h while the in-tree mirror…
- [Low] Claim that Documentation/netlink/specs/rt-addr.yaml is not
updated for the new AF_PACKET producer: the ifa-flags enum lacks a…
--
rtnetlink: add AF_PACKET multicast dumps
This adds an RTM_GETMULTICAST dump handler for ifa_family AF_PACKET which
walks dev->mc and reports each entry as an ifaddrmsg with IFA_MULTICAST,
IFA_MC_USERS and the new IFA_F_GLOBAL flag in IFA_FLAGS. The handler is
registered under PF_PACKET with RTNL_FLAG_DUMP_UNLOCKED and runs under RCU
plus netif_addr_lock_bh().
A note on the commit message first:
> This covers every column of /proc/net/dev_mcast. AF_PACKET is the
> family iproute2 already uses for link-layer addresses ("ip -0"), and
> AF_UNSPEC keeps its "all families" meaning from RTM_GETADDR.
[Severity: Medium]
Is the AF_UNSPEC part of this sentence accurate for RTM_GETMULTICAST?
RTM_GETMULTICAST only has PF_INET (net/ipv4/devinet.c), PF_INET6
(net/ipv6/addrconf.c) and the new PF_PACKET registration; rtnl_dump_all is
wired to RTM_GETADDR, RTM_GETROUTE and RTM_GETNETCONF only. In
rtnetlink_rcv_msg() the dump lookup falls back to PF_UNSPEC and then errors
out:
link = rtnl_get_link(family, type);
if (!link || !link->dumpit) {
family = PF_UNSPEC;
link = rtnl_get_link(family, type);
if (!link || !link->dumpit)
goto err_unlock;
}
so wouldn't an ifa_family == AF_UNSPEC RTM_GETMULTICAST dump return
-EOPNOTSUPP rather than dumping all families?
And even with a PF_UNSPEC handler wired to rtnl_dump_all(), that loop skips
PF_PACKET:
if (idx < s_idx || idx == PF_PACKET)
continue;
which would keep the new link-layer entries out of a combined dump. Could
this sentence be reworded to say userspace has to issue an explicit
AF_PACKET request?
> 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
[Severity: Low]
This isn't a bug, but the in-tree mirror tools/include/uapi/linux/if_addr.h
is listed in tools/perf/check-headers.sh and does not get the new define, so
a perf build will report the two copies as differing. The mirror already
lags at the baseline commit (it is missing IFA_MC_USERS), so this changes
nothing observable, and tools/ resyncs are usually separate commits. Was a
resync intended here?
The selftest side of the same concern is already handled later in the
series: "selftests: net: test AF_PACKET multicast dumps" adds
dump_mcaddr_l2_check() to tools/testing/selftests/net/rtnetlink.py covering
the ifa-index filter, mc-users, the global flag and target-netnsid.
>
> struct ifa_cacheinfo {
> __u32 ifa_prefered;
> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> index 81c5a6104dea..f54e9cb3bf30 100644
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -4566,6 +4566,169 @@ 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;
[ ... ]
> + 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)) {
[Severity: Low]
This isn't a bug in the code, but at this commit
Documentation/netlink/specs/rt-addr.yaml has no "global" entry in the
ifa-flags enum for bit 0x1000, and the getmulticast operation still lists a
reply of {multicast, mc-users, cacheinfo} with an empty dump request
attribute list, while this function emits IFA_FLAGS and IFA_TARGET_NETNSID
and rtnl_valid_dump_mcaddr_req() accepts IFA_TARGET_NETNSID.
The following commit in the series, "netlink: specs: rt-addr: document
AF_PACKET multicast dumps", adds "- name: global" as the 13th ifa-flags
entry, adds flags and target-netnsid to the reply attributes and
target-netnsid to the dump request, and updates the op doc, so this only
matters for bisectability of the generated bindings.
> + 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;
> +}
[Severity: Medium]
Can this skip or duplicate dev->mc entries across a multi-part dump without
telling userspace?
rtnl_dump_mcaddr_dev() resumes with a bare positional index and drops the
lock protecting dev->mc when it returns:
netif_addr_lock_bh(dev);
netdev_for_each_mc_addr(ha, dev) {
if (addr_idx < *s_addr_idx) {
...
netif_addr_unlock_bh(dev);
*s_addr_idx = err < 0 ? addr_idx : 0;
Between two netlink_dump() invocations dev->mc can be mutated by
__dev_mc_add()/__dev_mc_del()/dev_mc_flush() in net/core/dev_addr_lists.c,
which only take netif_addr_lock_bh(dev):
netif_addr_lock_bh(dev);
err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len, ...
and the handler is registered with RTNL_FLAG_DUMP_UNLOCKED, so RTNL does
not serialize this either. If an entry before *s_addr_idx is removed the
next entry is silently skipped; if one is inserted an entry is emitted
twice.
The sibling RTM_GETMULTICAST producers mark that case. in_dev_dump_ifmcaddr()
calls, per message:
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
with cb->seq initialised from inet_base_seq(tgt_net) by the caller, so
userspace gets NLM_F_DUMP_INTR. rtnl_dump_ifinfo() and inet6_dump_addr() do
the same.
> +
[ ... ]
> +static int rtnl_dump_mcaddr(struct sk_buff *skb, struct netlink_callback *cb)
> +{
[ ... ]
> + err = rtnl_valid_dump_mcaddr_req(cb->nlh, skb->sk, &filter,
> + cb->extack);
> + if (err < 0)
> + return err;
> +
> + rcu_read_lock();
> +
> + if (filter.ifindex) {
[Severity: Medium]
This is the spot where the sibling dumps set cb->seq from a generation
counter before iterating, for example inet6_dump_addr() and
inet_dump_addr(). Should rtnl_dump_mcaddr() do the same so that
nl_dump_check_consistent() in rtnl_dump_mcaddr_dev() can raise
NLM_F_DUMP_INTR?
struct netdev_hw_addr_list has no generation field today:
struct netdev_hw_addr_list {
struct list_head list;
int count;
...
};
so would this need a new counter bumped by __hw_addr_add_ex()/
__hw_addr_del_entry(), or would reusing something like dev_base_seq or a
dev_addr_genid style value be enough here?
> + cb->answer_flags |= NLM_F_DUMP_FILTERED;
> + flags |= NLM_F_DUMP_FILTERED;
> + dev = dev_get_by_index_rcu(filter.tgt_net, filter.ifindex);
[ ... ]
> + for_each_netdev_dump(filter.tgt_net, dev, ctx->ifindex) {
> + 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(filter.tgt_net);
> + return err;
> +}
> +
[ ... ]
> @@ -7251,6 +7414,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},
[Severity: Medium]
This registration is PF_PACKET only, which is the basis of the commit
message question above about AF_UNSPEC keeping its "all families" meaning
for RTM_GETMULTICAST.
> {.protocol = PF_BRIDGE, .msgtype = RTM_GETLINK,
> .dumpit = rtnl_bridge_getlink},
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260909133247.113923-1-sigefriedhyy%40gmail.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net-next v3 4/4] selftests: net: test AF_PACKET multicast dumps
2026-09-09 13:32 ` [PATCH net-next v3 4/4] selftests: net: test " Yuyang Huang
@ 2026-09-10 13:50 ` netdev-bot+sashiko
0 siblings, 0 replies; 12+ messages in thread
From: netdev-bot+sashiko @ 2026-09-10 13:50 UTC (permalink / raw)
To: sigefriedhyy
Cc: davem, dsahern, donald.hunter, edumazet, idosch, 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 2 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 0 · Low: 2 (1)
- [Low] In dump_mcaddr_l2_check() the ksft_in() membership checks are
non-fatal, but the immediately following statements index the same…
- [Low] Reported concern: dump_mcaddr_l2_check() creates a netlink socket
(rtnl = RtnlAddrFamily(),…
Pre-existing issues:
- [Low] Documentation/netlink/specs/rt-addr.yaml declares a `do` form for
the getmulticast operation (request value 58, reply value 58 carrying…
--
selftests: net: test AF_PACKET multicast dumps
This adds dump_mcaddr_l2_check() to tools/testing/selftests/net/rtnetlink.py,
which dumps the link-layer multicast addresses of a dummy device over
AF_PACKET RTM_GETMULTICAST and checks the ifa-index filter, the mc-users
count, the global flag and target-netnsid. The test skips when the kernel
answers with -EOPNOTSUPP.
> diff --git a/tools/testing/selftests/net/rtnetlink.py b/tools/testing/selftests/net/rtnetlink.py
> index 5cc3ebdcf08d..41da259c3a09 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,66 @@ 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()
[Severity: Low]
This isn't a bug, but the netlink socket created here in
dump_mcaddr_l2_check() is never closed and no defer(rtnl.close) is
registered, so the fd stays open until CPython collects the object,
including on the KsftSkipEx path below where the traceback keeps the frame
alive.
Note that dump_mcaddr_check() and dump_mcaddr6_check() in the same file
create rtnl = RtnlAddrFamily() inside NetNSEnter the same way and also
never close it, so this matches the existing convention in this file; only
_rtnl_route_subscribe() uses defer(rtnl.close), and that one keeps a
notification subscription alive after leaving the netns. Would it be worth
adding defer(rtnl.close) here anyway for symmetry with the netns teardown?
> + 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
[Severity: Low]
This isn't a bug introduced by this patch, but while the test only ever
uses dump=True here, the getmulticast operation in
Documentation/netlink/specs/rt-addr.yaml also declares a do form (request
and reply value 58, reply carrying multicast, mc-users, cacheinfo and, after
the AF_PACKET documentation change, flags and target-netnsid).
No family registers a .doit handler for RTM_GETMULTICAST: the PF_PACKET
entry in rtnetlink_rtnl_msg_handlers(), the PF_INET entry in
devinet_rtnl_msg_handlers() and the PF_INET6 entry in
addrconf_rtnl_msg_handlers() all set .dumpit only. rtnetlink_rcv_msg()
then takes the out_unlock path:
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;
}
so ynl --do getmulticast, and anything generated from the do half of the
spec, can only return -EOPNOTSUPP. Should the do form be dropped from the
spec, or is a .doit handler planned?
> +
> + # 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.
> + ksft_in(ETH_ALL_HOSTS_MULTICAST, entries,
> + "dummy1 does not have the all-hosts link-layer address")
> + ksft_not_in('global', entries[ETH_ALL_HOSTS_MULTICAST]['flags'],
> + "protocol entry is global")
> +
> + ksft_in(ETH_TEST_MULTICAST, entries,
> + "dummy1 does not have the SIOCADDMULTI address")
> + ksft_eq(entries[ETH_TEST_MULTICAST]['mc-users'], 1,
> + "unexpected mc-users for the SIOCADDMULTI address")
[Severity: Low]
Can this raise KeyError instead of reporting the individual checks?
ksft_in() in tools/testing/selftests/net/lib/py/ksft.py is non-fatal:
def _fail(*args):
global KSFT_RESULT
KSFT_RESULT = False
...
def ksft_in(a, b, comment=""):
if a not in b:
_fail("Check failed", a, "not in", b, comment)
So when the all-hosts entry is missing from the dump, ksft_in() records the
failure and the next statement still evaluates
entries[ETH_ALL_HOSTS_MULTICAST]['flags'], and likewise
entries[ETH_TEST_MULTICAST]['mc-users'] after the second ksft_in().
The preceding ksft_eq() on the ifa-index set is non-fatal too, so an empty
or unexpected dump flows straight into the indexing. ksft_run() catches the
exception and marks the case failed, but the mc-users check, the global flag
check and the whole target-netnsid sub-test below are then skipped rather
than reported.
Would it be better to bail out before dereferencing, the way
dump_mcaddr_check() and dump_mcaddr6_check() do with
if before is None:
raise KsftSkipEx(...)
or to guard the dict lookups with an explicit early return?
> + ksft_in('global', entries[ETH_TEST_MULTICAST]['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},
> + 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")
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260909133247.113923-1-sigefriedhyy%40gmail.com
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-09-10 13:50 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-09 13:32 [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Yuyang Huang
2026-09-09 13:32 ` [PATCH net-next v3 1/4] netlink: specs: rt-addr: fix the type of target-netnsid Yuyang Huang
2026-09-09 16:09 ` Nicolas Dichtel
2026-09-09 18:32 ` Jakub Kicinski
2026-09-10 1:11 ` Yuyang Huang
2026-09-09 13:32 ` [PATCH net-next v3 2/4] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
2026-09-10 13:50 ` netdev-bot+sashiko
2026-09-09 13:32 ` [PATCH net-next v3 3/4] netlink: specs: rt-addr: document " Yuyang Huang
2026-09-09 13:32 ` [PATCH net-next v3 4/4] selftests: net: test " Yuyang Huang
2026-09-10 13:50 ` netdev-bot+sashiko
2026-09-09 14:22 ` [PATCH net-next v3 0/4] rtnetlink: dump link-layer multicast addresses Nicolas Dichtel
2026-09-09 14:32 ` Yuyang Huang
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®