Skip to content

Commit eb4e17a

Browse files
Yuyang HuangPaolo Abeni
authored andcommitted
netlink: support dumping IPv4 multicast addresses
Extended RTM_GETMULTICAST to support dumping joined IPv4 multicast addresses, in addition to the existing IPv6 functionality. This allows userspace applications to retrieve both IPv4 and IPv6 multicast addresses through similar netlink command and then monitor future changes by registering to RTNLGRP_IPV4_MCADDR and RTNLGRP_IPV6_MCADDR. Cc: Maciej Żenczykowski <maze@google.com> Cc: Lorenzo Colitti <lorenzo@google.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Yuyang Huang <yuyanghuang@google.com> Link: https://patch.msgid.link/20250207110836.2407224-1-yuyanghuang@google.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 67800d2 commit eb4e17a

File tree

3 files changed

+90
-18
lines changed

3 files changed

+90
-18
lines changed

net/ipv4/devinet.c

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include <linux/notifier.h>
4747
#include <linux/inetdevice.h>
4848
#include <linux/igmp.h>
49+
#include "igmp_internal.h"
4950
#include <linux/slab.h>
5051
#include <linux/hash.h>
5152
#ifdef CONFIG_SYSCTL
@@ -107,15 +108,6 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
107108
[IFA_PROTO] = { .type = NLA_U8 },
108109
};
109110

110-
struct inet_fill_args {
111-
u32 portid;
112-
u32 seq;
113-
int event;
114-
unsigned int flags;
115-
int netnsid;
116-
int ifindex;
117-
};
118-
119111
#define IN4_ADDR_HSIZE_SHIFT 8
120112
#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
121113

@@ -1846,9 +1838,38 @@ static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,
18461838
return 0;
18471839
}
18481840

1849-
static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
1850-
struct netlink_callback *cb, int *s_ip_idx,
1851-
struct inet_fill_args *fillargs)
1841+
static int in_dev_dump_ifmcaddr(struct in_device *in_dev, struct sk_buff *skb,
1842+
struct netlink_callback *cb, int *s_ip_idx,
1843+
struct inet_fill_args *fillargs)
1844+
{
1845+
struct ip_mc_list *im;
1846+
int ip_idx = 0;
1847+
int err;
1848+
1849+
for (im = rcu_dereference(in_dev->mc_list);
1850+
im;
1851+
im = rcu_dereference(im->next_rcu)) {
1852+
if (ip_idx < *s_ip_idx) {
1853+
ip_idx++;
1854+
continue;
1855+
}
1856+
err = inet_fill_ifmcaddr(skb, in_dev->dev, im, fillargs);
1857+
if (err < 0)
1858+
goto done;
1859+
1860+
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1861+
ip_idx++;
1862+
}
1863+
err = 0;
1864+
ip_idx = 0;
1865+
done:
1866+
*s_ip_idx = ip_idx;
1867+
return err;
1868+
}
1869+
1870+
static int in_dev_dump_ifaddr(struct in_device *in_dev, struct sk_buff *skb,
1871+
struct netlink_callback *cb, int *s_ip_idx,
1872+
struct inet_fill_args *fillargs)
18521873
{
18531874
struct in_ifaddr *ifa;
18541875
int ip_idx = 0;
@@ -1874,6 +1895,21 @@ static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
18741895
return err;
18751896
}
18761897

1898+
static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
1899+
struct netlink_callback *cb, int *s_ip_idx,
1900+
struct inet_fill_args *fillargs)
1901+
{
1902+
switch (fillargs->event) {
1903+
case RTM_NEWADDR:
1904+
return in_dev_dump_ifaddr(in_dev, skb, cb, s_ip_idx, fillargs);
1905+
case RTM_GETMULTICAST:
1906+
return in_dev_dump_ifmcaddr(in_dev, skb, cb, s_ip_idx,
1907+
fillargs);
1908+
default:
1909+
return -EINVAL;
1910+
}
1911+
}
1912+
18771913
/* Combine dev_addr_genid and dev_base_seq to detect changes.
18781914
*/
18791915
static u32 inet_base_seq(const struct net *net)
@@ -1889,13 +1925,14 @@ static u32 inet_base_seq(const struct net *net)
18891925
return res;
18901926
}
18911927

1892-
static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1928+
static int inet_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
1929+
int event)
18931930
{
18941931
const struct nlmsghdr *nlh = cb->nlh;
18951932
struct inet_fill_args fillargs = {
18961933
.portid = NETLINK_CB(cb->skb).portid,
18971934
.seq = nlh->nlmsg_seq,
1898-
.event = RTM_NEWADDR,
1935+
.event = event,
18991936
.flags = NLM_F_MULTI,
19001937
.netnsid = -1,
19011938
};
@@ -1949,6 +1986,16 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
19491986
return err;
19501987
}
19511988

1989+
static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1990+
{
1991+
return inet_dump_addr(skb, cb, RTM_NEWADDR);
1992+
}
1993+
1994+
static int inet_dump_ifmcaddr(struct sk_buff *skb, struct netlink_callback *cb)
1995+
{
1996+
return inet_dump_addr(skb, cb, RTM_GETMULTICAST);
1997+
}
1998+
19521999
static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
19532000
u32 portid)
19542001
{
@@ -2845,6 +2892,8 @@ static const struct rtnl_msg_handler devinet_rtnl_msg_handlers[] __initconst = {
28452892
{.protocol = PF_INET, .msgtype = RTM_GETNETCONF,
28462893
.doit = inet_netconf_get_devconf, .dumpit = inet_netconf_dump_devconf,
28472894
.flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},
2895+
{.owner = THIS_MODULE, .protocol = PF_INET, .msgtype = RTM_GETMULTICAST,
2896+
.dumpit = inet_dump_ifmcaddr, .flags = RTNL_FLAG_DUMP_UNLOCKED},
28482897
};
28492898

28502899
void __init devinet_init(void)

net/ipv4/igmp.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#include <linux/skbuff.h>
8282
#include <linux/inetdevice.h>
8383
#include <linux/igmp.h>
84+
#include "igmp_internal.h"
8485
#include <linux/if_arp.h>
8586
#include <linux/rtnetlink.h>
8687
#include <linux/times.h>
@@ -1432,14 +1433,16 @@ static void ip_mc_hash_remove(struct in_device *in_dev,
14321433
*mc_hash = im->next_hash;
14331434
}
14341435

1435-
static int inet_fill_ifmcaddr(struct sk_buff *skb, struct net_device *dev,
1436-
const struct ip_mc_list *im, int event)
1436+
int inet_fill_ifmcaddr(struct sk_buff *skb, struct net_device *dev,
1437+
const struct ip_mc_list *im,
1438+
struct inet_fill_args *args)
14371439
{
14381440
struct ifa_cacheinfo ci;
14391441
struct ifaddrmsg *ifm;
14401442
struct nlmsghdr *nlh;
14411443

1442-
nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct ifaddrmsg), 0);
1444+
nlh = nlmsg_put(skb, args->portid, args->seq, args->event,
1445+
sizeof(struct ifaddrmsg), args->flags);
14431446
if (!nlh)
14441447
return -EMSGSIZE;
14451448

@@ -1468,6 +1471,9 @@ static int inet_fill_ifmcaddr(struct sk_buff *skb, struct net_device *dev,
14681471
static void inet_ifmcaddr_notify(struct net_device *dev,
14691472
const struct ip_mc_list *im, int event)
14701473
{
1474+
struct inet_fill_args fillargs = {
1475+
.event = event,
1476+
};
14711477
struct net *net = dev_net(dev);
14721478
struct sk_buff *skb;
14731479
int err = -ENOMEM;
@@ -1479,7 +1485,7 @@ static void inet_ifmcaddr_notify(struct net_device *dev,
14791485
if (!skb)
14801486
goto error;
14811487

1482-
err = inet_fill_ifmcaddr(skb, dev, im, event);
1488+
err = inet_fill_ifmcaddr(skb, dev, im, &fillargs);
14831489
if (err < 0) {
14841490
WARN_ON_ONCE(err == -EMSGSIZE);
14851491
nlmsg_free(skb);

net/ipv4/igmp_internal.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
#ifndef _LINUX_IGMP_INTERNAL_H
3+
#define _LINUX_IGMP_INTERNAL_H
4+
5+
struct inet_fill_args {
6+
u32 portid;
7+
u32 seq;
8+
int event;
9+
unsigned int flags;
10+
int netnsid;
11+
int ifindex;
12+
};
13+
14+
int inet_fill_ifmcaddr(struct sk_buff *skb, struct net_device *dev,
15+
const struct ip_mc_list *im,
16+
struct inet_fill_args *args);
17+
#endif

0 commit comments

Comments
 (0)