Commit 812e44dd1829488096929ff362f749ae04dc71a0

Authored by Nicolas Dichtel
Committed by David S. Miller
1 parent 8cd3ac9f9b

ip6mr: advertise new mfc entries via rtnl

This patch allows to monitor mf6c activities via rtnetlink.
To avoid parsing two times the mf6c oifs, we use maxvif to allocate the rtnl
msg, thus we may allocate some superfluous space.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 59 additions and 4 deletions Side-by-side Diff

... ... @@ -116,6 +116,8 @@
116 116 mifi_t mifi, int assert);
117 117 static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
118 118 struct mfc6_cache *c, struct rtmsg *rtm);
  119 +static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
  120 + int cmd);
119 121 static int ip6mr_rtm_dumproute(struct sk_buff *skb,
120 122 struct netlink_callback *cb);
121 123 static void mroute_clean_tables(struct mr6_table *mrt);
... ... @@ -870,6 +872,7 @@
870 872 }
871 873  
872 874 list_del(&c->list);
  875 + mr6_netlink_event(mrt, c, RTM_DELROUTE);
873 876 ip6mr_destroy_unres(mrt, c);
874 877 }
875 878  
... ... @@ -1220,6 +1223,7 @@
1220 1223  
1221 1224 atomic_inc(&mrt->cache_resolve_queue_len);
1222 1225 list_add(&c->list, &mrt->mfc6_unres_queue);
  1226 + mr6_netlink_event(mrt, c, RTM_NEWROUTE);
1223 1227  
1224 1228 ipmr_do_expire_process(mrt);
1225 1229 }
... ... @@ -1257,6 +1261,7 @@
1257 1261 list_del(&c->list);
1258 1262 write_unlock_bh(&mrt_lock);
1259 1263  
  1264 + mr6_netlink_event(mrt, c, RTM_DELROUTE);
1260 1265 ip6mr_cache_free(c);
1261 1266 return 0;
1262 1267 }
... ... @@ -1421,6 +1426,7 @@
1421 1426 if (!mrtsock)
1422 1427 c->mfc_flags |= MFC_STATIC;
1423 1428 write_unlock_bh(&mrt_lock);
  1429 + mr6_netlink_event(mrt, c, RTM_NEWROUTE);
1424 1430 return 0;
1425 1431 }
1426 1432  
... ... @@ -1465,6 +1471,7 @@
1465 1471 ip6mr_cache_resolve(net, mrt, uc, c);
1466 1472 ip6mr_cache_free(uc);
1467 1473 }
  1474 + mr6_netlink_event(mrt, c, RTM_NEWROUTE);
1468 1475 return 0;
1469 1476 }
1470 1477  
... ... @@ -1498,6 +1505,7 @@
1498 1505 list_del(&c->list);
1499 1506 write_unlock_bh(&mrt_lock);
1500 1507  
  1508 + mr6_netlink_event(mrt, c, RTM_DELROUTE);
1501 1509 ip6mr_cache_free(c);
1502 1510 }
1503 1511 }
... ... @@ -1506,6 +1514,7 @@
1506 1514 spin_lock_bh(&mfc_unres_lock);
1507 1515 list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
1508 1516 list_del(&c->list);
  1517 + mr6_netlink_event(mrt, c, RTM_DELROUTE);
1509 1518 ip6mr_destroy_unres(mrt, c);
1510 1519 }
1511 1520 spin_unlock_bh(&mfc_unres_lock);
1512 1521  
... ... @@ -2231,13 +2240,13 @@
2231 2240 }
2232 2241  
2233 2242 static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
2234   - u32 portid, u32 seq, struct mfc6_cache *c)
  2243 + u32 portid, u32 seq, struct mfc6_cache *c, int cmd)
2235 2244 {
2236 2245 struct nlmsghdr *nlh;
2237 2246 struct rtmsg *rtm;
2238 2247 int err;
2239 2248  
2240   - nlh = nlmsg_put(skb, portid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI);
  2249 + nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
2241 2250 if (nlh == NULL)
2242 2251 return -EMSGSIZE;
2243 2252  
... ... @@ -2272,6 +2281,52 @@
2272 2281 return -EMSGSIZE;
2273 2282 }
2274 2283  
  2284 +static int mr6_msgsize(bool unresolved, int maxvif)
  2285 +{
  2286 + size_t len =
  2287 + NLMSG_ALIGN(sizeof(struct rtmsg))
  2288 + + nla_total_size(4) /* RTA_TABLE */
  2289 + + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
  2290 + + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
  2291 + ;
  2292 +
  2293 + if (!unresolved)
  2294 + len = len
  2295 + + nla_total_size(4) /* RTA_IIF */
  2296 + + nla_total_size(0) /* RTA_MULTIPATH */
  2297 + + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
  2298 + /* RTA_MFC_STATS */
  2299 + + nla_total_size(sizeof(struct rta_mfc_stats))
  2300 + ;
  2301 +
  2302 + return len;
  2303 +}
  2304 +
  2305 +static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
  2306 + int cmd)
  2307 +{
  2308 + struct net *net = read_pnet(&mrt->net);
  2309 + struct sk_buff *skb;
  2310 + int err = -ENOBUFS;
  2311 +
  2312 + skb = nlmsg_new(mr6_msgsize(mfc->mf6c_parent >= MAXMIFS, mrt->maxvif),
  2313 + GFP_ATOMIC);
  2314 + if (skb == NULL)
  2315 + goto errout;
  2316 +
  2317 + err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
  2318 + if (err < 0)
  2319 + goto errout;
  2320 +
  2321 + rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
  2322 + return;
  2323 +
  2324 +errout:
  2325 + kfree_skb(skb);
  2326 + if (err < 0)
  2327 + rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
  2328 +}
  2329 +
2275 2330 static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2276 2331 {
2277 2332 struct net *net = sock_net(skb->sk);
... ... @@ -2298,7 +2353,7 @@
2298 2353 if (ip6mr_fill_mroute(mrt, skb,
2299 2354 NETLINK_CB(cb->skb).portid,
2300 2355 cb->nlh->nlmsg_seq,
2301   - mfc) < 0)
  2356 + mfc, RTM_NEWROUTE) < 0)
2302 2357 goto done;
2303 2358 next_entry:
2304 2359 e++;
... ... @@ -2312,7 +2367,7 @@
2312 2367 if (ip6mr_fill_mroute(mrt, skb,
2313 2368 NETLINK_CB(cb->skb).portid,
2314 2369 cb->nlh->nlmsg_seq,
2315   - mfc) < 0) {
  2370 + mfc, RTM_NEWROUTE) < 0) {
2316 2371 spin_unlock_bh(&mfc_unres_lock);
2317 2372 goto done;
2318 2373 }