Le 22/09/2026 à 01:59, Yuyang Huang a écrit :
> 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 next to
> the dev->mc helpers in dev_addr_lists.c 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.
> 
> Requests are always validated, there are no legacy users: prefixlen,
> flags and scope must be zero, ifa_index selects one device and
> IFA_TARGET_NETNSID is the only attribute accepted. The dump runs under
> RCU and netif_addr_lock_bh() without RTNL, and stamps cb->seq from
> dev_base_seq so a device added or removed between dump rounds sets
> NLM_F_DUMP_INTR.
> 
> Signed-off-by: Yuyang Huang <[email protected]>
> Reviewed-by: Nicolas Dichtel <[email protected]>
> ---
[snip]

> +static int dev_mc_dump_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 = dev_mc_fill_addr(skb, dev, ha, NETLINK_CB(cb->skb).portid,
> +                                    cb->nlh->nlmsg_seq, flags, netnsid);
> +             if (err < 0)
> +                     break;
> +             nl_dump_check_consistent(cb, nlmsg_hdr(skb));
> +             addr_idx++;
> +     }
> +     netif_addr_unlock_bh(dev);
> +
> +     *s_addr_idx = err < 0 ? addr_idx : 0;
> +
> +     return err;
> +}
[snip]

> +int dev_mc_dump(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +     struct dev_mc_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 = dev_mc_valid_dump_req(cb->nlh, skb->sk, &filter, cb->extack);
> +     if (err < 0)
> +             return err;
> +
> +     cb->seq = READ_ONCE(filter.tgt_net->dev_base_seq);
dev_base_seq only indicates whether the netdevice list has changed, not whether
the addr list has changed. It's only a partial consistency check.
See inet_base_seq()/inet6_base_seq().

I don't see an equivalent of dev_addr_genid for the L2 mcaddr list; it should
probably be added.

Reply via email to