Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipmr: add netlink notifications on igmpmsg cache reports

Add Netlink notifications on cache reports in ipmr, in addition to the
existing igmpmsg sent to mroute_sk.
Send RTM_NEWCACHEREPORT notifications to RTNLGRP_IPV4_MROUTE_R.

MSGTYPE, VIF_ID, SRC_ADDR and DST_ADDR Netlink attributes contain the
same data as their equivalent fields in the igmpmsg header.
PKT attribute is the packet sent to mroute_sk, without the added igmpmsg
header.

Suggested-by: Ryan Halbrook <halbrook@arista.com>
Signed-off-by: Julien Gomes <julien@arista.com>
Reviewed-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Julien Gomes and committed by
David S. Miller
5a645dd8 5f729eaa

+79 -2
+12
include/uapi/linux/mroute.h
··· 152 152 }; 153 153 #define IPMRA_VIFA_MAX (__IPMRA_VIFA_MAX - 1) 154 154 155 + /* ipmr netlink cache report attributes */ 156 + enum { 157 + IPMRA_CREPORT_UNSPEC, 158 + IPMRA_CREPORT_MSGTYPE, 159 + IPMRA_CREPORT_VIF_ID, 160 + IPMRA_CREPORT_SRC_ADDR, 161 + IPMRA_CREPORT_DST_ADDR, 162 + IPMRA_CREPORT_PKT, 163 + __IPMRA_CREPORT_MAX 164 + }; 165 + #define IPMRA_CREPORT_MAX (__IPMRA_CREPORT_MAX - 1) 166 + 155 167 /* That's all usermode folks */ 156 168 157 169 #define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */
+67 -2
net/ipv4/ipmr.c
··· 109 109 struct mfc_cache *c, struct rtmsg *rtm); 110 110 static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, 111 111 int cmd); 112 + static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt); 112 113 static void mroute_clean_tables(struct mr_table *mrt, bool all); 113 114 static void ipmr_expire_process(unsigned long arg); 114 115 ··· 996 995 } 997 996 } 998 997 999 - /* Bounce a cache query up to mrouted. We could use netlink for this but mrouted 1000 - * expects the following bizarre scheme. 998 + /* Bounce a cache query up to mrouted and netlink. 1001 999 * 1002 1000 * Called under mrt_lock. 1003 1001 */ ··· 1061 1061 kfree_skb(skb); 1062 1062 return -EINVAL; 1063 1063 } 1064 + 1065 + igmpmsg_netlink_event(mrt, skb); 1064 1066 1065 1067 /* Deliver to mrouted */ 1066 1068 ret = sock_queue_rcv_skb(mroute_sk, skb); ··· 2341 2339 kfree_skb(skb); 2342 2340 if (err < 0) 2343 2341 rtnl_set_sk_err(net, RTNLGRP_IPV4_MROUTE, err); 2342 + } 2343 + 2344 + static size_t igmpmsg_netlink_msgsize(size_t payloadlen) 2345 + { 2346 + size_t len = 2347 + NLMSG_ALIGN(sizeof(struct rtgenmsg)) 2348 + + nla_total_size(1) /* IPMRA_CREPORT_MSGTYPE */ 2349 + + nla_total_size(4) /* IPMRA_CREPORT_VIF_ID */ 2350 + + nla_total_size(4) /* IPMRA_CREPORT_SRC_ADDR */ 2351 + + nla_total_size(4) /* IPMRA_CREPORT_DST_ADDR */ 2352 + /* IPMRA_CREPORT_PKT */ 2353 + + nla_total_size(payloadlen) 2354 + ; 2355 + 2356 + return len; 2357 + } 2358 + 2359 + static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt) 2360 + { 2361 + struct net *net = read_pnet(&mrt->net); 2362 + struct nlmsghdr *nlh; 2363 + struct rtgenmsg *rtgenm; 2364 + struct igmpmsg *msg; 2365 + struct sk_buff *skb; 2366 + struct nlattr *nla; 2367 + int payloadlen; 2368 + 2369 + payloadlen = pkt->len - sizeof(struct igmpmsg); 2370 + msg = (struct igmpmsg *)skb_network_header(pkt); 2371 + 2372 + skb = nlmsg_new(igmpmsg_netlink_msgsize(payloadlen), GFP_ATOMIC); 2373 + if (!skb) 2374 + goto errout; 2375 + 2376 + nlh = nlmsg_put(skb, 0, 0, RTM_NEWCACHEREPORT, 2377 + sizeof(struct rtgenmsg), 0); 2378 + if (!nlh) 2379 + goto errout; 2380 + rtgenm = nlmsg_data(nlh); 2381 + rtgenm->rtgen_family = RTNL_FAMILY_IPMR; 2382 + if (nla_put_u8(skb, IPMRA_CREPORT_MSGTYPE, msg->im_msgtype) || 2383 + nla_put_u32(skb, IPMRA_CREPORT_VIF_ID, msg->im_vif) || 2384 + nla_put_in_addr(skb, IPMRA_CREPORT_SRC_ADDR, 2385 + msg->im_src.s_addr) || 2386 + nla_put_in_addr(skb, IPMRA_CREPORT_DST_ADDR, 2387 + msg->im_dst.s_addr)) 2388 + goto nla_put_failure; 2389 + 2390 + nla = nla_reserve(skb, IPMRA_CREPORT_PKT, payloadlen); 2391 + if (!nla || skb_copy_bits(pkt, sizeof(struct igmpmsg), 2392 + nla_data(nla), payloadlen)) 2393 + goto nla_put_failure; 2394 + 2395 + nlmsg_end(skb, nlh); 2396 + 2397 + rtnl_notify(skb, net, 0, RTNLGRP_IPV4_MROUTE_R, NULL, GFP_ATOMIC); 2398 + return; 2399 + 2400 + nla_put_failure: 2401 + nlmsg_cancel(skb, nlh); 2402 + errout: 2403 + kfree_skb(skb); 2404 + rtnl_set_sk_err(net, RTNLGRP_IPV4_MROUTE_R, -ENOBUFS); 2344 2405 } 2345 2406 2346 2407 static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)