From mboxrd@z Thu Jan 1 00:00:00 1970 From: Roopa Prabhu Subject: Re: [PATCH net-next v3 1/2] netlink: ipv4 igmp join notifications Date: Thu, 6 Sep 2018 20:40:39 -0700 Message-ID: References: <20180830093545.29465-2-pruddy@vyatta.att-mail.com> <20180906091056.21109-1-pruddy@vyatta.att-mail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Cc: netdev , =?UTF-8?B?SmnFmcOtIFDDrXJrbw==?= , Stephen Hemminger To: Patrick Ruddy Return-path: Received: from mail-ed1-f65.google.com ([209.85.208.65]:42959 "EHLO mail-ed1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726689AbeIGITc (ORCPT ); Fri, 7 Sep 2018 04:19:32 -0400 Received: by mail-ed1-f65.google.com with SMTP id l5so10504449edw.9 for ; Thu, 06 Sep 2018 20:40:40 -0700 (PDT) In-Reply-To: <20180906091056.21109-1-pruddy@vyatta.att-mail.com> Sender: netdev-owner@vger.kernel.org List-ID: On Thu, Sep 6, 2018 at 2:10 AM, Patrick Ruddy wrote: > Some userspace applications need to know about IGMP joins from the > kernel for 2 reasons: > 1. To allow the programming of multicast MAC filters in hardware > 2. To form a multicast FORUS list for non link-local multicast > groups to be sent to the kernel and from there to the interested > party. > (1) can be fulfilled but simply sending the hardware multicast MAC > address to be programmed but (2) requires the L3 address to be sent > since this cannot be constructed from the MAC address whereas the > reverse translation is a standard library function. > > This commit provides addition and deletion of multicast addresses > using the RTM_NEWMDB and RTM_DELMDB messages with AF_INET. It also > provides the RTM_GETMDB extension to allow multicast join state to > be read from the kernel. > > Signed-off-by: Patrick Ruddy > --- > v3 rework to use RTM_***MDB messages as per review comments. Patrick, this version seems to be using RTM_***MDB msgs with the RTM_*ADDR format. We cant do that...because existing RTM_MDB users will be confused. My request was to evaluate RTM_***MDB msg format. see nlmsg_populate_mdb_fill for details. If you can wait a day or two I can share some experimental code that moves high level RTM_*MDB msg handling into net/core/rtnetlink.c similar to RTM_*FDB > > net/ipv4/igmp.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 139 insertions(+) > > diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c > index 4da39446da2d..aed819e2ea93 100644 > --- a/net/ipv4/igmp.c > +++ b/net/ipv4/igmp.c > @@ -86,6 +86,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -1385,6 +1386,91 @@ static void ip_mc_hash_remove(struct in_device *in_dev, > } > > > +static int fill_addr(struct sk_buff *skb, struct net_device *dev, __be32 addr, > + int type, unsigned int flags) > +{ > + struct nlmsghdr *nlh; > + struct ifaddrmsg *ifm; > + > + nlh = nlmsg_put(skb, 0, 0, type, sizeof(*ifm), flags); > + if (!nlh) > + return -EMSGSIZE; > + > + ifm = nlmsg_data(nlh); > + ifm->ifa_family = AF_INET; > + ifm->ifa_prefixlen = 32; > + ifm->ifa_flags = IFA_F_PERMANENT; > + ifm->ifa_scope = RT_SCOPE_LINK; > + ifm->ifa_index = dev->ifindex; > + > + if (nla_put_in_addr(skb, IFA_ADDRESS, addr)) > + goto nla_put_failure; > + nlmsg_end(skb, nlh); > + return 0; > + > +nla_put_failure: > + nlmsg_cancel(skb, nlh); > + return -EMSGSIZE; > +} > + > +static inline size_t addr_nlmsg_size(void) > +{ > + return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) > + + nla_total_size(sizeof(__be32)); > +} > + > +static void ip_mc_addr_notify(struct net_device *dev, __be32 addr, int type) > +{ > + struct net *net = dev_net(dev); > + struct sk_buff *skb; > + int err = -ENOBUFS; > + > + skb = nlmsg_new(addr_nlmsg_size(), GFP_ATOMIC); > + if (!skb) > + goto errout; > + > + err = fill_addr(skb, dev, addr, type, 0); > + if (err < 0) { > + WARN_ON(err == -EMSGSIZE); > + kfree_skb(skb); > + goto errout; > + } > + rtnl_notify(skb, net, 0, RTNLGRP_MDB, NULL, GFP_ATOMIC); > + return; > +errout: > + if (err < 0) > + rtnl_set_sk_err(net, RTNLGRP_MDB, err); > +} > + > +int ip_mc_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb, > + struct net_device *dev) > +{ > + int s_idx; > + int idx = 0; > + struct ip_mc_list *im; > + struct in_device *in_dev; > + > + ASSERT_RTNL(); > + > + s_idx = cb->args[2]; > + in_dev = __in_dev_get_rtnl(dev); > + > + for_each_pmc_rtnl(in_dev, im) { > + if (idx < s_idx) > + continue; > + if (fill_addr(skb, dev, im->multiaddr, RTM_NEWMDB, > + NLM_F_MULTI) < 0) > + goto done; > + nl_dump_check_consistent(cb, nlmsg_hdr(skb)); > + idx++; > + } > + > + done: > + cb->args[2] = idx; > + > + return skb->len; > +} > + > /* > * A socket has joined a multicast group on device dev. > */ > @@ -1430,6 +1516,8 @@ static void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr, > igmpv3_del_delrec(in_dev, im); > #endif > igmp_group_added(im); > + > + ip_mc_addr_notify(in_dev->dev, addr, RTM_NEWMDB); > if (!in_dev->dead) > ip_rt_multicast_event(in_dev); > out: > @@ -1661,6 +1749,8 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) > in_dev->mc_count--; > igmp_group_dropped(i); > ip_mc_clear_src(i); > + ip_mc_addr_notify(in_dev->dev, addr, > + RTM_DELMDB); > > if (!in_dev->dead) > ip_rt_multicast_event(in_dev); > @@ -3051,6 +3141,53 @@ static struct notifier_block igmp_notifier = { > .notifier_call = igmp_netdev_event, > }; > > +static int igmp_mc_dump_ifaddrs(struct sk_buff *skb, > + struct netlink_callback *cb) > +{ > + struct net *net = sock_net(skb->sk); > + int h, s_h; > + int idx, s_idx; > + struct net_device *dev; > + struct in_device *in_dev; > + struct hlist_head *head; > + > + s_h = cb->args[0]; > + idx = cb->args[1]; > + s_idx = idx; > + > + for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { > + idx = 0; > + head = &net->dev_index_head[h]; > + rcu_read_lock(); > + cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^ > + net->dev_base_seq; > + hlist_for_each_entry_rcu(dev, head, index_hlist) { > + if (idx < s_idx) > + goto cont; > + if (h > s_h || idx > s_idx) > + cb->args[2] = 0; > + in_dev = __in_dev_get_rcu(dev); > + if (!in_dev) > + goto cont; > + > + /* loop over multicast addresses */ > + if (ip_mc_dump_ifaddr(skb, cb, dev) < 0) { > + rcu_read_unlock(); > + goto done; > + } > +cont: > + idx++; > + } > + rcu_read_unlock(); > + } > + > +done: > + cb->args[0] = h; > + cb->args[1] = idx; > + > + return skb->len; > +} > + > int __init igmp_mc_init(void) > { > #if defined(CONFIG_PROC_FS) > @@ -3064,6 +3201,8 @@ int __init igmp_mc_init(void) > goto reg_notif_fail; > return 0; > > + rtnl_register(PF_INET, RTM_GETMDB, NULL, igmp_mc_dump_ifaddrs, 0); > + > reg_notif_fail: > unregister_pernet_subsys(&igmp_net_ops); > return err; > -- > 2.17.1 >