aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2012-12-03 20:13:41 -0500
committerDavid S. Miller <davem@davemloft.net>2012-12-04 13:08:11 -0500
commit812e44dd1829488096929ff362f749ae04dc71a0 (patch)
tree9b2e5b2609648e5ac26675e336c269875bf30161
parent8cd3ac9f9b7bd921d0a28fd3273160ee8891e698 (diff)
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>
-rw-r--r--net/ipv6/ip6mr.c63
1 files changed, 59 insertions, 4 deletions
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 93a769891b72..580e5e084962 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -116,6 +116,8 @@ static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
116 mifi_t mifi, int assert); 116 mifi_t mifi, int assert);
117static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, 117static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
118 struct mfc6_cache *c, struct rtmsg *rtm); 118 struct mfc6_cache *c, struct rtmsg *rtm);
119static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
120 int cmd);
119static int ip6mr_rtm_dumproute(struct sk_buff *skb, 121static int ip6mr_rtm_dumproute(struct sk_buff *skb,
120 struct netlink_callback *cb); 122 struct netlink_callback *cb);
121static void mroute_clean_tables(struct mr6_table *mrt); 123static void mroute_clean_tables(struct mr6_table *mrt);
@@ -870,6 +872,7 @@ static void ipmr_do_expire_process(struct mr6_table *mrt)
870 } 872 }
871 873
872 list_del(&c->list); 874 list_del(&c->list);
875 mr6_netlink_event(mrt, c, RTM_DELROUTE);
873 ip6mr_destroy_unres(mrt, c); 876 ip6mr_destroy_unres(mrt, c);
874 } 877 }
875 878
@@ -1220,6 +1223,7 @@ ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb)
1220 1223
1221 atomic_inc(&mrt->cache_resolve_queue_len); 1224 atomic_inc(&mrt->cache_resolve_queue_len);
1222 list_add(&c->list, &mrt->mfc6_unres_queue); 1225 list_add(&c->list, &mrt->mfc6_unres_queue);
1226 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
1223 1227
1224 ipmr_do_expire_process(mrt); 1228 ipmr_do_expire_process(mrt);
1225 } 1229 }
@@ -1257,6 +1261,7 @@ static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc)
1257 list_del(&c->list); 1261 list_del(&c->list);
1258 write_unlock_bh(&mrt_lock); 1262 write_unlock_bh(&mrt_lock);
1259 1263
1264 mr6_netlink_event(mrt, c, RTM_DELROUTE);
1260 ip6mr_cache_free(c); 1265 ip6mr_cache_free(c);
1261 return 0; 1266 return 0;
1262 } 1267 }
@@ -1421,6 +1426,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
1421 if (!mrtsock) 1426 if (!mrtsock)
1422 c->mfc_flags |= MFC_STATIC; 1427 c->mfc_flags |= MFC_STATIC;
1423 write_unlock_bh(&mrt_lock); 1428 write_unlock_bh(&mrt_lock);
1429 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
1424 return 0; 1430 return 0;
1425 } 1431 }
1426 1432
@@ -1465,6 +1471,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
1465 ip6mr_cache_resolve(net, mrt, uc, c); 1471 ip6mr_cache_resolve(net, mrt, uc, c);
1466 ip6mr_cache_free(uc); 1472 ip6mr_cache_free(uc);
1467 } 1473 }
1474 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
1468 return 0; 1475 return 0;
1469} 1476}
1470 1477
@@ -1498,6 +1505,7 @@ static void mroute_clean_tables(struct mr6_table *mrt)
1498 list_del(&c->list); 1505 list_del(&c->list);
1499 write_unlock_bh(&mrt_lock); 1506 write_unlock_bh(&mrt_lock);
1500 1507
1508 mr6_netlink_event(mrt, c, RTM_DELROUTE);
1501 ip6mr_cache_free(c); 1509 ip6mr_cache_free(c);
1502 } 1510 }
1503 } 1511 }
@@ -1506,6 +1514,7 @@ static void mroute_clean_tables(struct mr6_table *mrt)
1506 spin_lock_bh(&mfc_unres_lock); 1514 spin_lock_bh(&mfc_unres_lock);
1507 list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) { 1515 list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
1508 list_del(&c->list); 1516 list_del(&c->list);
1517 mr6_netlink_event(mrt, c, RTM_DELROUTE);
1509 ip6mr_destroy_unres(mrt, c); 1518 ip6mr_destroy_unres(mrt, c);
1510 } 1519 }
1511 spin_unlock_bh(&mfc_unres_lock); 1520 spin_unlock_bh(&mfc_unres_lock);
@@ -2231,13 +2240,13 @@ int ip6mr_get_route(struct net *net,
2231} 2240}
2232 2241
2233static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, 2242static 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 struct nlmsghdr *nlh; 2245 struct nlmsghdr *nlh;
2237 struct rtmsg *rtm; 2246 struct rtmsg *rtm;
2238 int err; 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 if (nlh == NULL) 2250 if (nlh == NULL)
2242 return -EMSGSIZE; 2251 return -EMSGSIZE;
2243 2252
@@ -2272,6 +2281,52 @@ nla_put_failure:
2272 return -EMSGSIZE; 2281 return -EMSGSIZE;
2273} 2282}
2274 2283
2284static 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
2305static 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
2324errout:
2325 kfree_skb(skb);
2326 if (err < 0)
2327 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2328}
2329
2275static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) 2330static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2276{ 2331{
2277 struct net *net = sock_net(skb->sk); 2332 struct net *net = sock_net(skb->sk);
@@ -2298,7 +2353,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2298 if (ip6mr_fill_mroute(mrt, skb, 2353 if (ip6mr_fill_mroute(mrt, skb,
2299 NETLINK_CB(cb->skb).portid, 2354 NETLINK_CB(cb->skb).portid,
2300 cb->nlh->nlmsg_seq, 2355 cb->nlh->nlmsg_seq,
2301 mfc) < 0) 2356 mfc, RTM_NEWROUTE) < 0)
2302 goto done; 2357 goto done;
2303next_entry: 2358next_entry:
2304 e++; 2359 e++;
@@ -2312,7 +2367,7 @@ next_entry:
2312 if (ip6mr_fill_mroute(mrt, skb, 2367 if (ip6mr_fill_mroute(mrt, skb,
2313 NETLINK_CB(cb->skb).portid, 2368 NETLINK_CB(cb->skb).portid,
2314 cb->nlh->nlmsg_seq, 2369 cb->nlh->nlmsg_seq,
2315 mfc) < 0) { 2370 mfc, RTM_NEWROUTE) < 0) {
2316 spin_unlock_bh(&mfc_unres_lock); 2371 spin_unlock_bh(&mfc_unres_lock);
2317 goto done; 2372 goto done;
2318 } 2373 }