diff options
-rw-r--r-- | net/ipv6/ip6mr.c | 63 |
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); |
117 | static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | 117 | static 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); |
119 | static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc, | ||
120 | int cmd); | ||
119 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, | 121 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, |
120 | struct netlink_callback *cb); | 122 | struct netlink_callback *cb); |
121 | static void mroute_clean_tables(struct mr6_table *mrt); | 123 | static 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 | ||
2233 | static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | 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 | 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 | ||
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 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) | 2330 | static 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; |
2303 | next_entry: | 2358 | next_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 | } |