diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 96 |
1 files changed, 56 insertions, 40 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 854e4018d205..d1ddbc6ddac5 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -222,7 +222,7 @@ static const u32 ip6_template_metrics[RTAX_MAX] = { | |||
222 | [RTAX_HOPLIMIT - 1] = 255, | 222 | [RTAX_HOPLIMIT - 1] = 255, |
223 | }; | 223 | }; |
224 | 224 | ||
225 | static struct rt6_info ip6_null_entry_template = { | 225 | static const struct rt6_info ip6_null_entry_template = { |
226 | .dst = { | 226 | .dst = { |
227 | .__refcnt = ATOMIC_INIT(1), | 227 | .__refcnt = ATOMIC_INIT(1), |
228 | .__use = 1, | 228 | .__use = 1, |
@@ -242,7 +242,7 @@ static struct rt6_info ip6_null_entry_template = { | |||
242 | static int ip6_pkt_prohibit(struct sk_buff *skb); | 242 | static int ip6_pkt_prohibit(struct sk_buff *skb); |
243 | static int ip6_pkt_prohibit_out(struct sk_buff *skb); | 243 | static int ip6_pkt_prohibit_out(struct sk_buff *skb); |
244 | 244 | ||
245 | static struct rt6_info ip6_prohibit_entry_template = { | 245 | static const struct rt6_info ip6_prohibit_entry_template = { |
246 | .dst = { | 246 | .dst = { |
247 | .__refcnt = ATOMIC_INIT(1), | 247 | .__refcnt = ATOMIC_INIT(1), |
248 | .__use = 1, | 248 | .__use = 1, |
@@ -257,7 +257,7 @@ static struct rt6_info ip6_prohibit_entry_template = { | |||
257 | .rt6i_ref = ATOMIC_INIT(1), | 257 | .rt6i_ref = ATOMIC_INIT(1), |
258 | }; | 258 | }; |
259 | 259 | ||
260 | static struct rt6_info ip6_blk_hole_entry_template = { | 260 | static const struct rt6_info ip6_blk_hole_entry_template = { |
261 | .dst = { | 261 | .dst = { |
262 | .__refcnt = ATOMIC_INIT(1), | 262 | .__refcnt = ATOMIC_INIT(1), |
263 | .__use = 1, | 263 | .__use = 1, |
@@ -370,15 +370,11 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | |||
370 | 370 | ||
371 | static bool rt6_check_expired(const struct rt6_info *rt) | 371 | static bool rt6_check_expired(const struct rt6_info *rt) |
372 | { | 372 | { |
373 | struct rt6_info *ort = NULL; | ||
374 | |||
375 | if (rt->rt6i_flags & RTF_EXPIRES) { | 373 | if (rt->rt6i_flags & RTF_EXPIRES) { |
376 | if (time_after(jiffies, rt->dst.expires)) | 374 | if (time_after(jiffies, rt->dst.expires)) |
377 | return true; | 375 | return true; |
378 | } else if (rt->dst.from) { | 376 | } else if (rt->dst.from) { |
379 | ort = (struct rt6_info *) rt->dst.from; | 377 | return rt6_check_expired((struct rt6_info *) rt->dst.from); |
380 | return (ort->rt6i_flags & RTF_EXPIRES) && | ||
381 | time_after(jiffies, ort->dst.expires); | ||
382 | } | 378 | } |
383 | return false; | 379 | return false; |
384 | } | 380 | } |
@@ -452,10 +448,9 @@ static void rt6_probe(struct rt6_info *rt) | |||
452 | * Router Reachability Probe MUST be rate-limited | 448 | * Router Reachability Probe MUST be rate-limited |
453 | * to no more than one per minute. | 449 | * to no more than one per minute. |
454 | */ | 450 | */ |
455 | rcu_read_lock(); | ||
456 | neigh = rt ? rt->n : NULL; | 451 | neigh = rt ? rt->n : NULL; |
457 | if (!neigh || (neigh->nud_state & NUD_VALID)) | 452 | if (!neigh || (neigh->nud_state & NUD_VALID)) |
458 | goto out; | 453 | return; |
459 | read_lock_bh(&neigh->lock); | 454 | read_lock_bh(&neigh->lock); |
460 | if (!(neigh->nud_state & NUD_VALID) && | 455 | if (!(neigh->nud_state & NUD_VALID) && |
461 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | 456 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { |
@@ -471,8 +466,6 @@ static void rt6_probe(struct rt6_info *rt) | |||
471 | } else { | 466 | } else { |
472 | read_unlock_bh(&neigh->lock); | 467 | read_unlock_bh(&neigh->lock); |
473 | } | 468 | } |
474 | out: | ||
475 | rcu_read_unlock(); | ||
476 | } | 469 | } |
477 | #else | 470 | #else |
478 | static inline void rt6_probe(struct rt6_info *rt) | 471 | static inline void rt6_probe(struct rt6_info *rt) |
@@ -499,7 +492,6 @@ static inline int rt6_check_neigh(struct rt6_info *rt) | |||
499 | struct neighbour *neigh; | 492 | struct neighbour *neigh; |
500 | int m; | 493 | int m; |
501 | 494 | ||
502 | rcu_read_lock(); | ||
503 | neigh = rt->n; | 495 | neigh = rt->n; |
504 | if (rt->rt6i_flags & RTF_NONEXTHOP || | 496 | if (rt->rt6i_flags & RTF_NONEXTHOP || |
505 | !(rt->rt6i_flags & RTF_GATEWAY)) | 497 | !(rt->rt6i_flags & RTF_GATEWAY)) |
@@ -517,7 +509,6 @@ static inline int rt6_check_neigh(struct rt6_info *rt) | |||
517 | read_unlock_bh(&neigh->lock); | 509 | read_unlock_bh(&neigh->lock); |
518 | } else | 510 | } else |
519 | m = 0; | 511 | m = 0; |
520 | rcu_read_unlock(); | ||
521 | return m; | 512 | return m; |
522 | } | 513 | } |
523 | 514 | ||
@@ -966,7 +957,7 @@ struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk, | |||
966 | { | 957 | { |
967 | int flags = 0; | 958 | int flags = 0; |
968 | 959 | ||
969 | fl6->flowi6_iif = net->loopback_dev->ifindex; | 960 | fl6->flowi6_iif = LOOPBACK_IFINDEX; |
970 | 961 | ||
971 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr)) | 962 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr)) |
972 | flags |= RT6_LOOKUP_F_IFACE; | 963 | flags |= RT6_LOOKUP_F_IFACE; |
@@ -1469,8 +1460,21 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1469 | } | 1460 | } |
1470 | rt->dst.output = ip6_pkt_discard_out; | 1461 | rt->dst.output = ip6_pkt_discard_out; |
1471 | rt->dst.input = ip6_pkt_discard; | 1462 | rt->dst.input = ip6_pkt_discard; |
1472 | rt->dst.error = -ENETUNREACH; | ||
1473 | rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; | 1463 | rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; |
1464 | switch (cfg->fc_type) { | ||
1465 | case RTN_BLACKHOLE: | ||
1466 | rt->dst.error = -EINVAL; | ||
1467 | break; | ||
1468 | case RTN_PROHIBIT: | ||
1469 | rt->dst.error = -EACCES; | ||
1470 | break; | ||
1471 | case RTN_THROW: | ||
1472 | rt->dst.error = -EAGAIN; | ||
1473 | break; | ||
1474 | default: | ||
1475 | rt->dst.error = -ENETUNREACH; | ||
1476 | break; | ||
1477 | } | ||
1474 | goto install_route; | 1478 | goto install_route; |
1475 | } | 1479 | } |
1476 | 1480 | ||
@@ -1835,7 +1839,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
1835 | if (!table) | 1839 | if (!table) |
1836 | return NULL; | 1840 | return NULL; |
1837 | 1841 | ||
1838 | write_lock_bh(&table->tb6_lock); | 1842 | read_lock_bh(&table->tb6_lock); |
1839 | fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0); | 1843 | fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0); |
1840 | if (!fn) | 1844 | if (!fn) |
1841 | goto out; | 1845 | goto out; |
@@ -1851,7 +1855,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
1851 | break; | 1855 | break; |
1852 | } | 1856 | } |
1853 | out: | 1857 | out: |
1854 | write_unlock_bh(&table->tb6_lock); | 1858 | read_unlock_bh(&table->tb6_lock); |
1855 | return rt; | 1859 | return rt; |
1856 | } | 1860 | } |
1857 | 1861 | ||
@@ -1867,7 +1871,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net, | |||
1867 | .fc_dst_len = prefixlen, | 1871 | .fc_dst_len = prefixlen, |
1868 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | | 1872 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | |
1869 | RTF_UP | RTF_PREF(pref), | 1873 | RTF_UP | RTF_PREF(pref), |
1870 | .fc_nlinfo.pid = 0, | 1874 | .fc_nlinfo.portid = 0, |
1871 | .fc_nlinfo.nlh = NULL, | 1875 | .fc_nlinfo.nlh = NULL, |
1872 | .fc_nlinfo.nl_net = net, | 1876 | .fc_nlinfo.nl_net = net, |
1873 | }; | 1877 | }; |
@@ -1894,7 +1898,7 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev | |||
1894 | if (!table) | 1898 | if (!table) |
1895 | return NULL; | 1899 | return NULL; |
1896 | 1900 | ||
1897 | write_lock_bh(&table->tb6_lock); | 1901 | read_lock_bh(&table->tb6_lock); |
1898 | for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) { | 1902 | for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) { |
1899 | if (dev == rt->dst.dev && | 1903 | if (dev == rt->dst.dev && |
1900 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && | 1904 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && |
@@ -1903,7 +1907,7 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev | |||
1903 | } | 1907 | } |
1904 | if (rt) | 1908 | if (rt) |
1905 | dst_hold(&rt->dst); | 1909 | dst_hold(&rt->dst); |
1906 | write_unlock_bh(&table->tb6_lock); | 1910 | read_unlock_bh(&table->tb6_lock); |
1907 | return rt; | 1911 | return rt; |
1908 | } | 1912 | } |
1909 | 1913 | ||
@@ -1917,7 +1921,7 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, | |||
1917 | .fc_ifindex = dev->ifindex, | 1921 | .fc_ifindex = dev->ifindex, |
1918 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | | 1922 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | |
1919 | RTF_UP | RTF_EXPIRES | RTF_PREF(pref), | 1923 | RTF_UP | RTF_EXPIRES | RTF_PREF(pref), |
1920 | .fc_nlinfo.pid = 0, | 1924 | .fc_nlinfo.portid = 0, |
1921 | .fc_nlinfo.nlh = NULL, | 1925 | .fc_nlinfo.nlh = NULL, |
1922 | .fc_nlinfo.nl_net = dev_net(dev), | 1926 | .fc_nlinfo.nl_net = dev_net(dev), |
1923 | }; | 1927 | }; |
@@ -2266,14 +2270,18 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2266 | cfg->fc_src_len = rtm->rtm_src_len; | 2270 | cfg->fc_src_len = rtm->rtm_src_len; |
2267 | cfg->fc_flags = RTF_UP; | 2271 | cfg->fc_flags = RTF_UP; |
2268 | cfg->fc_protocol = rtm->rtm_protocol; | 2272 | cfg->fc_protocol = rtm->rtm_protocol; |
2273 | cfg->fc_type = rtm->rtm_type; | ||
2269 | 2274 | ||
2270 | if (rtm->rtm_type == RTN_UNREACHABLE) | 2275 | if (rtm->rtm_type == RTN_UNREACHABLE || |
2276 | rtm->rtm_type == RTN_BLACKHOLE || | ||
2277 | rtm->rtm_type == RTN_PROHIBIT || | ||
2278 | rtm->rtm_type == RTN_THROW) | ||
2271 | cfg->fc_flags |= RTF_REJECT; | 2279 | cfg->fc_flags |= RTF_REJECT; |
2272 | 2280 | ||
2273 | if (rtm->rtm_type == RTN_LOCAL) | 2281 | if (rtm->rtm_type == RTN_LOCAL) |
2274 | cfg->fc_flags |= RTF_LOCAL; | 2282 | cfg->fc_flags |= RTF_LOCAL; |
2275 | 2283 | ||
2276 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; | 2284 | cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; |
2277 | cfg->fc_nlinfo.nlh = nlh; | 2285 | cfg->fc_nlinfo.nlh = nlh; |
2278 | cfg->fc_nlinfo.nl_net = sock_net(skb->sk); | 2286 | cfg->fc_nlinfo.nl_net = sock_net(skb->sk); |
2279 | 2287 | ||
@@ -2364,7 +2372,7 @@ static inline size_t rt6_nlmsg_size(void) | |||
2364 | static int rt6_fill_node(struct net *net, | 2372 | static int rt6_fill_node(struct net *net, |
2365 | struct sk_buff *skb, struct rt6_info *rt, | 2373 | struct sk_buff *skb, struct rt6_info *rt, |
2366 | struct in6_addr *dst, struct in6_addr *src, | 2374 | struct in6_addr *dst, struct in6_addr *src, |
2367 | int iif, int type, u32 pid, u32 seq, | 2375 | int iif, int type, u32 portid, u32 seq, |
2368 | int prefix, int nowait, unsigned int flags) | 2376 | int prefix, int nowait, unsigned int flags) |
2369 | { | 2377 | { |
2370 | struct rtmsg *rtm; | 2378 | struct rtmsg *rtm; |
@@ -2380,7 +2388,7 @@ static int rt6_fill_node(struct net *net, | |||
2380 | } | 2388 | } |
2381 | } | 2389 | } |
2382 | 2390 | ||
2383 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags); | 2391 | nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags); |
2384 | if (!nlh) | 2392 | if (!nlh) |
2385 | return -EMSGSIZE; | 2393 | return -EMSGSIZE; |
2386 | 2394 | ||
@@ -2396,8 +2404,22 @@ static int rt6_fill_node(struct net *net, | |||
2396 | rtm->rtm_table = table; | 2404 | rtm->rtm_table = table; |
2397 | if (nla_put_u32(skb, RTA_TABLE, table)) | 2405 | if (nla_put_u32(skb, RTA_TABLE, table)) |
2398 | goto nla_put_failure; | 2406 | goto nla_put_failure; |
2399 | if (rt->rt6i_flags & RTF_REJECT) | 2407 | if (rt->rt6i_flags & RTF_REJECT) { |
2400 | rtm->rtm_type = RTN_UNREACHABLE; | 2408 | switch (rt->dst.error) { |
2409 | case -EINVAL: | ||
2410 | rtm->rtm_type = RTN_BLACKHOLE; | ||
2411 | break; | ||
2412 | case -EACCES: | ||
2413 | rtm->rtm_type = RTN_PROHIBIT; | ||
2414 | break; | ||
2415 | case -EAGAIN: | ||
2416 | rtm->rtm_type = RTN_THROW; | ||
2417 | break; | ||
2418 | default: | ||
2419 | rtm->rtm_type = RTN_UNREACHABLE; | ||
2420 | break; | ||
2421 | } | ||
2422 | } | ||
2401 | else if (rt->rt6i_flags & RTF_LOCAL) | 2423 | else if (rt->rt6i_flags & RTF_LOCAL) |
2402 | rtm->rtm_type = RTN_LOCAL; | 2424 | rtm->rtm_type = RTN_LOCAL; |
2403 | else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK)) | 2425 | else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK)) |
@@ -2470,15 +2492,11 @@ static int rt6_fill_node(struct net *net, | |||
2470 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) | 2492 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
2471 | goto nla_put_failure; | 2493 | goto nla_put_failure; |
2472 | 2494 | ||
2473 | rcu_read_lock(); | ||
2474 | n = rt->n; | 2495 | n = rt->n; |
2475 | if (n) { | 2496 | if (n) { |
2476 | if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) { | 2497 | if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) |
2477 | rcu_read_unlock(); | ||
2478 | goto nla_put_failure; | 2498 | goto nla_put_failure; |
2479 | } | ||
2480 | } | 2499 | } |
2481 | rcu_read_unlock(); | ||
2482 | 2500 | ||
2483 | if (rt->dst.dev && | 2501 | if (rt->dst.dev && |
2484 | nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) | 2502 | nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) |
@@ -2511,7 +2529,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) | |||
2511 | 2529 | ||
2512 | return rt6_fill_node(arg->net, | 2530 | return rt6_fill_node(arg->net, |
2513 | arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, | 2531 | arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, |
2514 | NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq, | 2532 | NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq, |
2515 | prefix, 0, NLM_F_MULTI); | 2533 | prefix, 0, NLM_F_MULTI); |
2516 | } | 2534 | } |
2517 | 2535 | ||
@@ -2591,14 +2609,14 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2591 | skb_dst_set(skb, &rt->dst); | 2609 | skb_dst_set(skb, &rt->dst); |
2592 | 2610 | ||
2593 | err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, | 2611 | err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, |
2594 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2612 | RTM_NEWROUTE, NETLINK_CB(in_skb).portid, |
2595 | nlh->nlmsg_seq, 0, 0, 0); | 2613 | nlh->nlmsg_seq, 0, 0, 0); |
2596 | if (err < 0) { | 2614 | if (err < 0) { |
2597 | kfree_skb(skb); | 2615 | kfree_skb(skb); |
2598 | goto errout; | 2616 | goto errout; |
2599 | } | 2617 | } |
2600 | 2618 | ||
2601 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); | 2619 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); |
2602 | errout: | 2620 | errout: |
2603 | return err; | 2621 | return err; |
2604 | } | 2622 | } |
@@ -2618,14 +2636,14 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) | |||
2618 | goto errout; | 2636 | goto errout; |
2619 | 2637 | ||
2620 | err = rt6_fill_node(net, skb, rt, NULL, NULL, 0, | 2638 | err = rt6_fill_node(net, skb, rt, NULL, NULL, 0, |
2621 | event, info->pid, seq, 0, 0, 0); | 2639 | event, info->portid, seq, 0, 0, 0); |
2622 | if (err < 0) { | 2640 | if (err < 0) { |
2623 | /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ | 2641 | /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ |
2624 | WARN_ON(err == -EMSGSIZE); | 2642 | WARN_ON(err == -EMSGSIZE); |
2625 | kfree_skb(skb); | 2643 | kfree_skb(skb); |
2626 | goto errout; | 2644 | goto errout; |
2627 | } | 2645 | } |
2628 | rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE, | 2646 | rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE, |
2629 | info->nlh, gfp_any()); | 2647 | info->nlh, gfp_any()); |
2630 | return; | 2648 | return; |
2631 | errout: | 2649 | errout: |
@@ -2680,14 +2698,12 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2680 | #else | 2698 | #else |
2681 | seq_puts(m, "00000000000000000000000000000000 00 "); | 2699 | seq_puts(m, "00000000000000000000000000000000 00 "); |
2682 | #endif | 2700 | #endif |
2683 | rcu_read_lock(); | ||
2684 | n = rt->n; | 2701 | n = rt->n; |
2685 | if (n) { | 2702 | if (n) { |
2686 | seq_printf(m, "%pi6", n->primary_key); | 2703 | seq_printf(m, "%pi6", n->primary_key); |
2687 | } else { | 2704 | } else { |
2688 | seq_puts(m, "00000000000000000000000000000000"); | 2705 | seq_puts(m, "00000000000000000000000000000000"); |
2689 | } | 2706 | } |
2690 | rcu_read_unlock(); | ||
2691 | seq_printf(m, " %08x %08x %08x %08x %8s\n", | 2707 | seq_printf(m, " %08x %08x %08x %08x %8s\n", |
2692 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), | 2708 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), |
2693 | rt->dst.__use, rt->rt6i_flags, | 2709 | rt->dst.__use, rt->rt6i_flags, |