aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 }