diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 138 |
1 files changed, 90 insertions, 48 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0ef1f086feb..f02fe523bd3 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -72,7 +72,8 @@ | |||
72 | #define RT6_TRACE(x...) do { ; } while (0) | 72 | #define RT6_TRACE(x...) do { ; } while (0) |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); | 75 | static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort, |
76 | const struct in6_addr *dest); | ||
76 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); | 77 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); |
77 | static unsigned int ip6_default_advmss(const struct dst_entry *dst); | 78 | static unsigned int ip6_default_advmss(const struct dst_entry *dst); |
78 | static unsigned int ip6_default_mtu(const struct dst_entry *dst); | 79 | static unsigned int ip6_default_mtu(const struct dst_entry *dst); |
@@ -103,6 +104,9 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) | |||
103 | struct inet_peer *peer; | 104 | struct inet_peer *peer; |
104 | u32 *p = NULL; | 105 | u32 *p = NULL; |
105 | 106 | ||
107 | if (!(rt->dst.flags & DST_HOST)) | ||
108 | return NULL; | ||
109 | |||
106 | if (!rt->rt6i_peer) | 110 | if (!rt->rt6i_peer) |
107 | rt6_bind_peer(rt, 1); | 111 | rt6_bind_peer(rt, 1); |
108 | 112 | ||
@@ -127,6 +131,11 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) | |||
127 | return p; | 131 | return p; |
128 | } | 132 | } |
129 | 133 | ||
134 | static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst, const void *daddr) | ||
135 | { | ||
136 | return __neigh_lookup_errno(&nd_tbl, daddr, dst->dev); | ||
137 | } | ||
138 | |||
130 | static struct dst_ops ip6_dst_ops_template = { | 139 | static struct dst_ops ip6_dst_ops_template = { |
131 | .family = AF_INET6, | 140 | .family = AF_INET6, |
132 | .protocol = cpu_to_be16(ETH_P_IPV6), | 141 | .protocol = cpu_to_be16(ETH_P_IPV6), |
@@ -142,6 +151,7 @@ static struct dst_ops ip6_dst_ops_template = { | |||
142 | .link_failure = ip6_link_failure, | 151 | .link_failure = ip6_link_failure, |
143 | .update_pmtu = ip6_rt_update_pmtu, | 152 | .update_pmtu = ip6_rt_update_pmtu, |
144 | .local_out = __ip6_local_out, | 153 | .local_out = __ip6_local_out, |
154 | .neigh_lookup = ip6_neigh_lookup, | ||
145 | }; | 155 | }; |
146 | 156 | ||
147 | static unsigned int ip6_blackhole_default_mtu(const struct dst_entry *dst) | 157 | static unsigned int ip6_blackhole_default_mtu(const struct dst_entry *dst) |
@@ -168,6 +178,7 @@ static struct dst_ops ip6_dst_blackhole_ops = { | |||
168 | .default_advmss = ip6_default_advmss, | 178 | .default_advmss = ip6_default_advmss, |
169 | .update_pmtu = ip6_rt_blackhole_update_pmtu, | 179 | .update_pmtu = ip6_rt_blackhole_update_pmtu, |
170 | .cow_metrics = ip6_rt_blackhole_cow_metrics, | 180 | .cow_metrics = ip6_rt_blackhole_cow_metrics, |
181 | .neigh_lookup = ip6_neigh_lookup, | ||
171 | }; | 182 | }; |
172 | 183 | ||
173 | static const u32 ip6_template_metrics[RTAX_MAX] = { | 184 | static const u32 ip6_template_metrics[RTAX_MAX] = { |
@@ -233,7 +244,9 @@ static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops, | |||
233 | { | 244 | { |
234 | struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, flags); | 245 | struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, flags); |
235 | 246 | ||
236 | memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry)); | 247 | if (rt != NULL) |
248 | memset(&rt->rt6i_table, 0, | ||
249 | sizeof(*rt) - sizeof(struct dst_entry)); | ||
237 | 250 | ||
238 | return rt; | 251 | return rt; |
239 | } | 252 | } |
@@ -244,6 +257,9 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
244 | struct inet6_dev *idev = rt->rt6i_idev; | 257 | struct inet6_dev *idev = rt->rt6i_idev; |
245 | struct inet_peer *peer = rt->rt6i_peer; | 258 | struct inet_peer *peer = rt->rt6i_peer; |
246 | 259 | ||
260 | if (!(rt->dst.flags & DST_HOST)) | ||
261 | dst_destroy_metrics_generic(dst); | ||
262 | |||
247 | if (idev != NULL) { | 263 | if (idev != NULL) { |
248 | rt->rt6i_idev = NULL; | 264 | rt->rt6i_idev = NULL; |
249 | in6_dev_put(idev); | 265 | in6_dev_put(idev); |
@@ -356,7 +372,7 @@ out: | |||
356 | #ifdef CONFIG_IPV6_ROUTER_PREF | 372 | #ifdef CONFIG_IPV6_ROUTER_PREF |
357 | static void rt6_probe(struct rt6_info *rt) | 373 | static void rt6_probe(struct rt6_info *rt) |
358 | { | 374 | { |
359 | struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL; | 375 | struct neighbour *neigh; |
360 | /* | 376 | /* |
361 | * Okay, this does not seem to be appropriate | 377 | * Okay, this does not seem to be appropriate |
362 | * for now, however, we need to check if it | 378 | * for now, however, we need to check if it |
@@ -365,8 +381,10 @@ static void rt6_probe(struct rt6_info *rt) | |||
365 | * Router Reachability Probe MUST be rate-limited | 381 | * Router Reachability Probe MUST be rate-limited |
366 | * to no more than one per minute. | 382 | * to no more than one per minute. |
367 | */ | 383 | */ |
384 | rcu_read_lock(); | ||
385 | neigh = rt ? dst_get_neighbour(&rt->dst) : NULL; | ||
368 | if (!neigh || (neigh->nud_state & NUD_VALID)) | 386 | if (!neigh || (neigh->nud_state & NUD_VALID)) |
369 | return; | 387 | goto out; |
370 | read_lock_bh(&neigh->lock); | 388 | read_lock_bh(&neigh->lock); |
371 | if (!(neigh->nud_state & NUD_VALID) && | 389 | if (!(neigh->nud_state & NUD_VALID) && |
372 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | 390 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { |
@@ -379,8 +397,11 @@ static void rt6_probe(struct rt6_info *rt) | |||
379 | target = (struct in6_addr *)&neigh->primary_key; | 397 | target = (struct in6_addr *)&neigh->primary_key; |
380 | addrconf_addr_solict_mult(target, &mcaddr); | 398 | addrconf_addr_solict_mult(target, &mcaddr); |
381 | ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); | 399 | ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); |
382 | } else | 400 | } else { |
383 | read_unlock_bh(&neigh->lock); | 401 | read_unlock_bh(&neigh->lock); |
402 | } | ||
403 | out: | ||
404 | rcu_read_unlock(); | ||
384 | } | 405 | } |
385 | #else | 406 | #else |
386 | static inline void rt6_probe(struct rt6_info *rt) | 407 | static inline void rt6_probe(struct rt6_info *rt) |
@@ -404,8 +425,11 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) | |||
404 | 425 | ||
405 | static inline int rt6_check_neigh(struct rt6_info *rt) | 426 | static inline int rt6_check_neigh(struct rt6_info *rt) |
406 | { | 427 | { |
407 | struct neighbour *neigh = rt->rt6i_nexthop; | 428 | struct neighbour *neigh; |
408 | int m; | 429 | int m; |
430 | |||
431 | rcu_read_lock(); | ||
432 | neigh = dst_get_neighbour(&rt->dst); | ||
409 | if (rt->rt6i_flags & RTF_NONEXTHOP || | 433 | if (rt->rt6i_flags & RTF_NONEXTHOP || |
410 | !(rt->rt6i_flags & RTF_GATEWAY)) | 434 | !(rt->rt6i_flags & RTF_GATEWAY)) |
411 | m = 1; | 435 | m = 1; |
@@ -422,6 +446,7 @@ static inline int rt6_check_neigh(struct rt6_info *rt) | |||
422 | read_unlock_bh(&neigh->lock); | 446 | read_unlock_bh(&neigh->lock); |
423 | } else | 447 | } else |
424 | m = 0; | 448 | m = 0; |
449 | rcu_read_unlock(); | ||
425 | return m; | 450 | return m; |
426 | } | 451 | } |
427 | 452 | ||
@@ -683,7 +708,8 @@ int ip6_ins_rt(struct rt6_info *rt) | |||
683 | return __ip6_ins_rt(rt, &info); | 708 | return __ip6_ins_rt(rt, &info); |
684 | } | 709 | } |
685 | 710 | ||
686 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_addr *daddr, | 711 | static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort, |
712 | const struct in6_addr *daddr, | ||
687 | const struct in6_addr *saddr) | 713 | const struct in6_addr *saddr) |
688 | { | 714 | { |
689 | struct rt6_info *rt; | 715 | struct rt6_info *rt; |
@@ -692,23 +718,20 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_add | |||
692 | * Clone the route. | 718 | * Clone the route. |
693 | */ | 719 | */ |
694 | 720 | ||
695 | rt = ip6_rt_copy(ort); | 721 | rt = ip6_rt_copy(ort, daddr); |
696 | 722 | ||
697 | if (rt) { | 723 | if (rt) { |
698 | struct neighbour *neigh; | 724 | struct neighbour *neigh; |
699 | int attempts = !in_softirq(); | 725 | int attempts = !in_softirq(); |
700 | 726 | ||
701 | if (!(rt->rt6i_flags&RTF_GATEWAY)) { | 727 | if (!(rt->rt6i_flags&RTF_GATEWAY)) { |
702 | if (rt->rt6i_dst.plen != 128 && | 728 | if (ort->rt6i_dst.plen != 128 && |
703 | ipv6_addr_equal(&rt->rt6i_dst.addr, daddr)) | 729 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) |
704 | rt->rt6i_flags |= RTF_ANYCAST; | 730 | rt->rt6i_flags |= RTF_ANYCAST; |
705 | ipv6_addr_copy(&rt->rt6i_gateway, daddr); | 731 | ipv6_addr_copy(&rt->rt6i_gateway, daddr); |
706 | } | 732 | } |
707 | 733 | ||
708 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); | ||
709 | rt->rt6i_dst.plen = 128; | ||
710 | rt->rt6i_flags |= RTF_CACHE; | 734 | rt->rt6i_flags |= RTF_CACHE; |
711 | rt->dst.flags |= DST_HOST; | ||
712 | 735 | ||
713 | #ifdef CONFIG_IPV6_SUBTREES | 736 | #ifdef CONFIG_IPV6_SUBTREES |
714 | if (rt->rt6i_src.plen && saddr) { | 737 | if (rt->rt6i_src.plen && saddr) { |
@@ -745,22 +768,21 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_add | |||
745 | dst_free(&rt->dst); | 768 | dst_free(&rt->dst); |
746 | return NULL; | 769 | return NULL; |
747 | } | 770 | } |
748 | rt->rt6i_nexthop = neigh; | 771 | dst_set_neighbour(&rt->dst, neigh); |
749 | 772 | ||
750 | } | 773 | } |
751 | 774 | ||
752 | return rt; | 775 | return rt; |
753 | } | 776 | } |
754 | 777 | ||
755 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_addr *daddr) | 778 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, |
779 | const struct in6_addr *daddr) | ||
756 | { | 780 | { |
757 | struct rt6_info *rt = ip6_rt_copy(ort); | 781 | struct rt6_info *rt = ip6_rt_copy(ort, daddr); |
782 | |||
758 | if (rt) { | 783 | if (rt) { |
759 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); | ||
760 | rt->rt6i_dst.plen = 128; | ||
761 | rt->rt6i_flags |= RTF_CACHE; | 784 | rt->rt6i_flags |= RTF_CACHE; |
762 | rt->dst.flags |= DST_HOST; | 785 | dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst))); |
763 | rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop); | ||
764 | } | 786 | } |
765 | return rt; | 787 | return rt; |
766 | } | 788 | } |
@@ -794,7 +816,7 @@ restart: | |||
794 | dst_hold(&rt->dst); | 816 | dst_hold(&rt->dst); |
795 | read_unlock_bh(&table->tb6_lock); | 817 | read_unlock_bh(&table->tb6_lock); |
796 | 818 | ||
797 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 819 | if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
798 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); | 820 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); |
799 | else if (!(rt->dst.flags & DST_HOST)) | 821 | else if (!(rt->dst.flags & DST_HOST)) |
800 | nrt = rt6_alloc_clone(rt, &fl6->daddr); | 822 | nrt = rt6_alloc_clone(rt, &fl6->daddr); |
@@ -900,7 +922,10 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori | |||
900 | new->input = dst_discard; | 922 | new->input = dst_discard; |
901 | new->output = dst_discard; | 923 | new->output = dst_discard; |
902 | 924 | ||
903 | dst_copy_metrics(new, &ort->dst); | 925 | if (dst_metrics_read_only(&ort->dst)) |
926 | new->_metrics = ort->dst._metrics; | ||
927 | else | ||
928 | dst_copy_metrics(new, &ort->dst); | ||
904 | rt->rt6i_idev = ort->rt6i_idev; | 929 | rt->rt6i_idev = ort->rt6i_idev; |
905 | if (rt->rt6i_idev) | 930 | if (rt->rt6i_idev) |
906 | in6_dev_hold(rt->rt6i_idev); | 931 | in6_dev_hold(rt->rt6i_idev); |
@@ -1057,11 +1082,14 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
1057 | neigh = NULL; | 1082 | neigh = NULL; |
1058 | } | 1083 | } |
1059 | 1084 | ||
1060 | rt->rt6i_idev = idev; | 1085 | rt->dst.flags |= DST_HOST; |
1061 | rt->rt6i_nexthop = neigh; | 1086 | rt->dst.output = ip6_output; |
1087 | dst_set_neighbour(&rt->dst, neigh); | ||
1062 | atomic_set(&rt->dst.__refcnt, 1); | 1088 | atomic_set(&rt->dst.__refcnt, 1); |
1089 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); | ||
1090 | rt->rt6i_dst.plen = 128; | ||
1091 | rt->rt6i_idev = idev; | ||
1063 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); | 1092 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); |
1064 | rt->dst.output = ip6_output; | ||
1065 | 1093 | ||
1066 | spin_lock_bh(&icmp6_dst_lock); | 1094 | spin_lock_bh(&icmp6_dst_lock); |
1067 | rt->dst.next = icmp6_dst_gc_list; | 1095 | rt->dst.next = icmp6_dst_gc_list; |
@@ -1239,6 +1267,14 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1239 | if (rt->rt6i_dst.plen == 128) | 1267 | if (rt->rt6i_dst.plen == 128) |
1240 | rt->dst.flags |= DST_HOST; | 1268 | rt->dst.flags |= DST_HOST; |
1241 | 1269 | ||
1270 | if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) { | ||
1271 | u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL); | ||
1272 | if (!metrics) { | ||
1273 | err = -ENOMEM; | ||
1274 | goto out; | ||
1275 | } | ||
1276 | dst_init_metrics(&rt->dst, metrics, 0); | ||
1277 | } | ||
1242 | #ifdef CONFIG_IPV6_SUBTREES | 1278 | #ifdef CONFIG_IPV6_SUBTREES |
1243 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); | 1279 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); |
1244 | rt->rt6i_src.plen = cfg->fc_src_len; | 1280 | rt->rt6i_src.plen = cfg->fc_src_len; |
@@ -1338,12 +1374,12 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1338 | rt->rt6i_prefsrc.plen = 0; | 1374 | rt->rt6i_prefsrc.plen = 0; |
1339 | 1375 | ||
1340 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { | 1376 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { |
1341 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); | 1377 | struct neighbour *n = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); |
1342 | if (IS_ERR(rt->rt6i_nexthop)) { | 1378 | if (IS_ERR(n)) { |
1343 | err = PTR_ERR(rt->rt6i_nexthop); | 1379 | err = PTR_ERR(n); |
1344 | rt->rt6i_nexthop = NULL; | ||
1345 | goto out; | 1380 | goto out; |
1346 | } | 1381 | } |
1382 | dst_set_neighbour(&rt->dst, n); | ||
1347 | } | 1383 | } |
1348 | 1384 | ||
1349 | rt->rt6i_flags = cfg->fc_flags; | 1385 | rt->rt6i_flags = cfg->fc_flags; |
@@ -1574,10 +1610,10 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, | |||
1574 | dst_confirm(&rt->dst); | 1610 | dst_confirm(&rt->dst); |
1575 | 1611 | ||
1576 | /* Duplicate redirect: silently ignore. */ | 1612 | /* Duplicate redirect: silently ignore. */ |
1577 | if (neigh == rt->dst.neighbour) | 1613 | if (neigh == dst_get_neighbour_raw(&rt->dst)) |
1578 | goto out; | 1614 | goto out; |
1579 | 1615 | ||
1580 | nrt = ip6_rt_copy(rt); | 1616 | nrt = ip6_rt_copy(rt, dest); |
1581 | if (nrt == NULL) | 1617 | if (nrt == NULL) |
1582 | goto out; | 1618 | goto out; |
1583 | 1619 | ||
@@ -1585,12 +1621,8 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, | |||
1585 | if (on_link) | 1621 | if (on_link) |
1586 | nrt->rt6i_flags &= ~RTF_GATEWAY; | 1622 | nrt->rt6i_flags &= ~RTF_GATEWAY; |
1587 | 1623 | ||
1588 | ipv6_addr_copy(&nrt->rt6i_dst.addr, dest); | ||
1589 | nrt->rt6i_dst.plen = 128; | ||
1590 | nrt->dst.flags |= DST_HOST; | ||
1591 | |||
1592 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); | 1624 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); |
1593 | nrt->rt6i_nexthop = neigh_clone(neigh); | 1625 | dst_set_neighbour(&nrt->dst, neigh_clone(neigh)); |
1594 | 1626 | ||
1595 | if (ip6_ins_rt(nrt)) | 1627 | if (ip6_ins_rt(nrt)) |
1596 | goto out; | 1628 | goto out; |
@@ -1670,7 +1702,7 @@ again: | |||
1670 | 1. It is connected route. Action: COW | 1702 | 1. It is connected route. Action: COW |
1671 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. | 1703 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. |
1672 | */ | 1704 | */ |
1673 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 1705 | if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
1674 | nrt = rt6_alloc_cow(rt, daddr, saddr); | 1706 | nrt = rt6_alloc_cow(rt, daddr, saddr); |
1675 | else | 1707 | else |
1676 | nrt = rt6_alloc_clone(rt, daddr); | 1708 | nrt = rt6_alloc_clone(rt, daddr); |
@@ -1723,7 +1755,8 @@ void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *sad | |||
1723 | * Misc support functions | 1755 | * Misc support functions |
1724 | */ | 1756 | */ |
1725 | 1757 | ||
1726 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | 1758 | static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort, |
1759 | const struct in6_addr *dest) | ||
1727 | { | 1760 | { |
1728 | struct net *net = dev_net(ort->rt6i_dev); | 1761 | struct net *net = dev_net(ort->rt6i_dev); |
1729 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, | 1762 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, |
@@ -1732,7 +1765,10 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1732 | if (rt) { | 1765 | if (rt) { |
1733 | rt->dst.input = ort->dst.input; | 1766 | rt->dst.input = ort->dst.input; |
1734 | rt->dst.output = ort->dst.output; | 1767 | rt->dst.output = ort->dst.output; |
1768 | rt->dst.flags |= DST_HOST; | ||
1735 | 1769 | ||
1770 | ipv6_addr_copy(&rt->rt6i_dst.addr, dest); | ||
1771 | rt->rt6i_dst.plen = 128; | ||
1736 | dst_copy_metrics(&rt->dst, &ort->dst); | 1772 | dst_copy_metrics(&rt->dst, &ort->dst); |
1737 | rt->dst.error = ort->dst.error; | 1773 | rt->dst.error = ort->dst.error; |
1738 | rt->rt6i_idev = ort->rt6i_idev; | 1774 | rt->rt6i_idev = ort->rt6i_idev; |
@@ -1745,7 +1781,6 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1745 | rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES; | 1781 | rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES; |
1746 | rt->rt6i_metric = 0; | 1782 | rt->rt6i_metric = 0; |
1747 | 1783 | ||
1748 | memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); | ||
1749 | #ifdef CONFIG_IPV6_SUBTREES | 1784 | #ifdef CONFIG_IPV6_SUBTREES |
1750 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); | 1785 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); |
1751 | #endif | 1786 | #endif |
@@ -2035,7 +2070,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
2035 | 2070 | ||
2036 | return ERR_CAST(neigh); | 2071 | return ERR_CAST(neigh); |
2037 | } | 2072 | } |
2038 | rt->rt6i_nexthop = neigh; | 2073 | dst_set_neighbour(&rt->dst, neigh); |
2039 | 2074 | ||
2040 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); | 2075 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); |
2041 | rt->rt6i_dst.plen = 128; | 2076 | rt->rt6i_dst.plen = 128; |
@@ -2312,6 +2347,7 @@ static int rt6_fill_node(struct net *net, | |||
2312 | struct nlmsghdr *nlh; | 2347 | struct nlmsghdr *nlh; |
2313 | long expires; | 2348 | long expires; |
2314 | u32 table; | 2349 | u32 table; |
2350 | struct neighbour *n; | ||
2315 | 2351 | ||
2316 | if (prefix) { /* user wants prefix routes only */ | 2352 | if (prefix) { /* user wants prefix routes only */ |
2317 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { | 2353 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { |
@@ -2400,8 +2436,11 @@ static int rt6_fill_node(struct net *net, | |||
2400 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) | 2436 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
2401 | goto nla_put_failure; | 2437 | goto nla_put_failure; |
2402 | 2438 | ||
2403 | if (rt->dst.neighbour) | 2439 | rcu_read_lock(); |
2404 | NLA_PUT(skb, RTA_GATEWAY, 16, &rt->dst.neighbour->primary_key); | 2440 | n = dst_get_neighbour(&rt->dst); |
2441 | if (n) | ||
2442 | NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key); | ||
2443 | rcu_read_unlock(); | ||
2405 | 2444 | ||
2406 | if (rt->dst.dev) | 2445 | if (rt->dst.dev) |
2407 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); | 2446 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); |
@@ -2585,6 +2624,7 @@ struct rt6_proc_arg | |||
2585 | static int rt6_info_route(struct rt6_info *rt, void *p_arg) | 2624 | static int rt6_info_route(struct rt6_info *rt, void *p_arg) |
2586 | { | 2625 | { |
2587 | struct seq_file *m = p_arg; | 2626 | struct seq_file *m = p_arg; |
2627 | struct neighbour *n; | ||
2588 | 2628 | ||
2589 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); | 2629 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); |
2590 | 2630 | ||
@@ -2593,12 +2633,14 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2593 | #else | 2633 | #else |
2594 | seq_puts(m, "00000000000000000000000000000000 00 "); | 2634 | seq_puts(m, "00000000000000000000000000000000 00 "); |
2595 | #endif | 2635 | #endif |
2596 | 2636 | rcu_read_lock(); | |
2597 | if (rt->rt6i_nexthop) { | 2637 | n = dst_get_neighbour(&rt->dst); |
2598 | seq_printf(m, "%pi6", rt->rt6i_nexthop->primary_key); | 2638 | if (n) { |
2639 | seq_printf(m, "%pi6", n->primary_key); | ||
2599 | } else { | 2640 | } else { |
2600 | seq_puts(m, "00000000000000000000000000000000"); | 2641 | seq_puts(m, "00000000000000000000000000000000"); |
2601 | } | 2642 | } |
2643 | rcu_read_unlock(); | ||
2602 | seq_printf(m, " %08x %08x %08x %08x %8s\n", | 2644 | seq_printf(m, " %08x %08x %08x %08x %8s\n", |
2603 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), | 2645 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), |
2604 | rt->dst.__use, rt->rt6i_flags, | 2646 | rt->dst.__use, rt->rt6i_flags, |
@@ -2918,9 +2960,9 @@ int __init ip6_route_init(void) | |||
2918 | goto xfrm6_init; | 2960 | goto xfrm6_init; |
2919 | 2961 | ||
2920 | ret = -ENOBUFS; | 2962 | ret = -ENOBUFS; |
2921 | if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL) || | 2963 | if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) || |
2922 | __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL) || | 2964 | __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) || |
2923 | __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL)) | 2965 | __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL)) |
2924 | goto fib6_rules_init; | 2966 | goto fib6_rules_init; |
2925 | 2967 | ||
2926 | ret = register_netdevice_notifier(&ip6_route_dev_notifier); | 2968 | ret = register_netdevice_notifier(&ip6_route_dev_notifier); |