diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 367 |
1 files changed, 242 insertions, 125 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a998db6e7895..de2b1decd786 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -89,14 +89,44 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); | |||
89 | 89 | ||
90 | #ifdef CONFIG_IPV6_ROUTE_INFO | 90 | #ifdef CONFIG_IPV6_ROUTE_INFO |
91 | static struct rt6_info *rt6_add_route_info(struct net *net, | 91 | static struct rt6_info *rt6_add_route_info(struct net *net, |
92 | struct in6_addr *prefix, int prefixlen, | 92 | const struct in6_addr *prefix, int prefixlen, |
93 | struct in6_addr *gwaddr, int ifindex, | 93 | const struct in6_addr *gwaddr, int ifindex, |
94 | unsigned pref); | 94 | unsigned pref); |
95 | static struct rt6_info *rt6_get_route_info(struct net *net, | 95 | static struct rt6_info *rt6_get_route_info(struct net *net, |
96 | struct in6_addr *prefix, int prefixlen, | 96 | const struct in6_addr *prefix, int prefixlen, |
97 | struct in6_addr *gwaddr, int ifindex); | 97 | const struct in6_addr *gwaddr, int ifindex); |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) | ||
101 | { | ||
102 | struct rt6_info *rt = (struct rt6_info *) dst; | ||
103 | struct inet_peer *peer; | ||
104 | u32 *p = NULL; | ||
105 | |||
106 | if (!rt->rt6i_peer) | ||
107 | rt6_bind_peer(rt, 1); | ||
108 | |||
109 | peer = rt->rt6i_peer; | ||
110 | if (peer) { | ||
111 | u32 *old_p = __DST_METRICS_PTR(old); | ||
112 | unsigned long prev, new; | ||
113 | |||
114 | p = peer->metrics; | ||
115 | if (inet_metrics_new(peer)) | ||
116 | memcpy(p, old_p, sizeof(u32) * RTAX_MAX); | ||
117 | |||
118 | new = (unsigned long) p; | ||
119 | prev = cmpxchg(&dst->_metrics, old, new); | ||
120 | |||
121 | if (prev != old) { | ||
122 | p = __DST_METRICS_PTR(prev); | ||
123 | if (prev & DST_METRICS_READ_ONLY) | ||
124 | p = NULL; | ||
125 | } | ||
126 | } | ||
127 | return p; | ||
128 | } | ||
129 | |||
100 | static struct dst_ops ip6_dst_ops_template = { | 130 | static struct dst_ops ip6_dst_ops_template = { |
101 | .family = AF_INET6, | 131 | .family = AF_INET6, |
102 | .protocol = cpu_to_be16(ETH_P_IPV6), | 132 | .protocol = cpu_to_be16(ETH_P_IPV6), |
@@ -105,6 +135,7 @@ static struct dst_ops ip6_dst_ops_template = { | |||
105 | .check = ip6_dst_check, | 135 | .check = ip6_dst_check, |
106 | .default_advmss = ip6_default_advmss, | 136 | .default_advmss = ip6_default_advmss, |
107 | .default_mtu = ip6_default_mtu, | 137 | .default_mtu = ip6_default_mtu, |
138 | .cow_metrics = ipv6_cow_metrics, | ||
108 | .destroy = ip6_dst_destroy, | 139 | .destroy = ip6_dst_destroy, |
109 | .ifdown = ip6_dst_ifdown, | 140 | .ifdown = ip6_dst_ifdown, |
110 | .negative_advice = ip6_negative_advice, | 141 | .negative_advice = ip6_negative_advice, |
@@ -122,6 +153,12 @@ static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
122 | { | 153 | { |
123 | } | 154 | } |
124 | 155 | ||
156 | static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst, | ||
157 | unsigned long old) | ||
158 | { | ||
159 | return NULL; | ||
160 | } | ||
161 | |||
125 | static struct dst_ops ip6_dst_blackhole_ops = { | 162 | static struct dst_ops ip6_dst_blackhole_ops = { |
126 | .family = AF_INET6, | 163 | .family = AF_INET6, |
127 | .protocol = cpu_to_be16(ETH_P_IPV6), | 164 | .protocol = cpu_to_be16(ETH_P_IPV6), |
@@ -130,6 +167,11 @@ static struct dst_ops ip6_dst_blackhole_ops = { | |||
130 | .default_mtu = ip6_blackhole_default_mtu, | 167 | .default_mtu = ip6_blackhole_default_mtu, |
131 | .default_advmss = ip6_default_advmss, | 168 | .default_advmss = ip6_default_advmss, |
132 | .update_pmtu = ip6_rt_blackhole_update_pmtu, | 169 | .update_pmtu = ip6_rt_blackhole_update_pmtu, |
170 | .cow_metrics = ip6_rt_blackhole_cow_metrics, | ||
171 | }; | ||
172 | |||
173 | static const u32 ip6_template_metrics[RTAX_MAX] = { | ||
174 | [RTAX_HOPLIMIT - 1] = 255, | ||
133 | }; | 175 | }; |
134 | 176 | ||
135 | static struct rt6_info ip6_null_entry_template = { | 177 | static struct rt6_info ip6_null_entry_template = { |
@@ -185,9 +227,14 @@ static struct rt6_info ip6_blk_hole_entry_template = { | |||
185 | #endif | 227 | #endif |
186 | 228 | ||
187 | /* allocate dst with ip6_dst_ops */ | 229 | /* allocate dst with ip6_dst_ops */ |
188 | static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops) | 230 | static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops, |
231 | struct net_device *dev) | ||
189 | { | 232 | { |
190 | return (struct rt6_info *)dst_alloc(ops); | 233 | struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, 0); |
234 | |||
235 | memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry)); | ||
236 | |||
237 | return rt; | ||
191 | } | 238 | } |
192 | 239 | ||
193 | static void ip6_dst_destroy(struct dst_entry *dst) | 240 | static void ip6_dst_destroy(struct dst_entry *dst) |
@@ -206,6 +253,13 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
206 | } | 253 | } |
207 | } | 254 | } |
208 | 255 | ||
256 | static atomic_t __rt6_peer_genid = ATOMIC_INIT(0); | ||
257 | |||
258 | static u32 rt6_peer_genid(void) | ||
259 | { | ||
260 | return atomic_read(&__rt6_peer_genid); | ||
261 | } | ||
262 | |||
209 | void rt6_bind_peer(struct rt6_info *rt, int create) | 263 | void rt6_bind_peer(struct rt6_info *rt, int create) |
210 | { | 264 | { |
211 | struct inet_peer *peer; | 265 | struct inet_peer *peer; |
@@ -213,6 +267,8 @@ void rt6_bind_peer(struct rt6_info *rt, int create) | |||
213 | peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); | 267 | peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); |
214 | if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) | 268 | if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) |
215 | inet_putpeer(peer); | 269 | inet_putpeer(peer); |
270 | else | ||
271 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
216 | } | 272 | } |
217 | 273 | ||
218 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 274 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
@@ -239,7 +295,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt) | |||
239 | time_after(jiffies, rt->rt6i_expires); | 295 | time_after(jiffies, rt->rt6i_expires); |
240 | } | 296 | } |
241 | 297 | ||
242 | static inline int rt6_need_strict(struct in6_addr *daddr) | 298 | static inline int rt6_need_strict(const struct in6_addr *daddr) |
243 | { | 299 | { |
244 | return ipv6_addr_type(daddr) & | 300 | return ipv6_addr_type(daddr) & |
245 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); | 301 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); |
@@ -251,7 +307,7 @@ static inline int rt6_need_strict(struct in6_addr *daddr) | |||
251 | 307 | ||
252 | static inline struct rt6_info *rt6_device_match(struct net *net, | 308 | static inline struct rt6_info *rt6_device_match(struct net *net, |
253 | struct rt6_info *rt, | 309 | struct rt6_info *rt, |
254 | struct in6_addr *saddr, | 310 | const struct in6_addr *saddr, |
255 | int oif, | 311 | int oif, |
256 | int flags) | 312 | int flags) |
257 | { | 313 | { |
@@ -463,7 +519,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) | |||
463 | 519 | ||
464 | #ifdef CONFIG_IPV6_ROUTE_INFO | 520 | #ifdef CONFIG_IPV6_ROUTE_INFO |
465 | int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | 521 | int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, |
466 | struct in6_addr *gwaddr) | 522 | const struct in6_addr *gwaddr) |
467 | { | 523 | { |
468 | struct net *net = dev_net(dev); | 524 | struct net *net = dev_net(dev); |
469 | struct route_info *rinfo = (struct route_info *) opt; | 525 | struct route_info *rinfo = (struct route_info *) opt; |
@@ -555,17 +611,17 @@ do { \ | |||
555 | 611 | ||
556 | static struct rt6_info *ip6_pol_route_lookup(struct net *net, | 612 | static struct rt6_info *ip6_pol_route_lookup(struct net *net, |
557 | struct fib6_table *table, | 613 | struct fib6_table *table, |
558 | struct flowi *fl, int flags) | 614 | struct flowi6 *fl6, int flags) |
559 | { | 615 | { |
560 | struct fib6_node *fn; | 616 | struct fib6_node *fn; |
561 | struct rt6_info *rt; | 617 | struct rt6_info *rt; |
562 | 618 | ||
563 | read_lock_bh(&table->tb6_lock); | 619 | read_lock_bh(&table->tb6_lock); |
564 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 620 | fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); |
565 | restart: | 621 | restart: |
566 | rt = fn->leaf; | 622 | rt = fn->leaf; |
567 | rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags); | 623 | rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags); |
568 | BACKTRACK(net, &fl->fl6_src); | 624 | BACKTRACK(net, &fl6->saddr); |
569 | out: | 625 | out: |
570 | dst_use(&rt->dst, jiffies); | 626 | dst_use(&rt->dst, jiffies); |
571 | read_unlock_bh(&table->tb6_lock); | 627 | read_unlock_bh(&table->tb6_lock); |
@@ -576,19 +632,19 @@ out: | |||
576 | struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, | 632 | struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, |
577 | const struct in6_addr *saddr, int oif, int strict) | 633 | const struct in6_addr *saddr, int oif, int strict) |
578 | { | 634 | { |
579 | struct flowi fl = { | 635 | struct flowi6 fl6 = { |
580 | .oif = oif, | 636 | .flowi6_oif = oif, |
581 | .fl6_dst = *daddr, | 637 | .daddr = *daddr, |
582 | }; | 638 | }; |
583 | struct dst_entry *dst; | 639 | struct dst_entry *dst; |
584 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; | 640 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; |
585 | 641 | ||
586 | if (saddr) { | 642 | if (saddr) { |
587 | memcpy(&fl.fl6_src, saddr, sizeof(*saddr)); | 643 | memcpy(&fl6.saddr, saddr, sizeof(*saddr)); |
588 | flags |= RT6_LOOKUP_F_HAS_SADDR; | 644 | flags |= RT6_LOOKUP_F_HAS_SADDR; |
589 | } | 645 | } |
590 | 646 | ||
591 | dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_lookup); | 647 | dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup); |
592 | if (dst->error == 0) | 648 | if (dst->error == 0) |
593 | return (struct rt6_info *) dst; | 649 | return (struct rt6_info *) dst; |
594 | 650 | ||
@@ -626,8 +682,8 @@ int ip6_ins_rt(struct rt6_info *rt) | |||
626 | return __ip6_ins_rt(rt, &info); | 682 | return __ip6_ins_rt(rt, &info); |
627 | } | 683 | } |
628 | 684 | ||
629 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, | 685 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_addr *daddr, |
630 | struct in6_addr *saddr) | 686 | const struct in6_addr *saddr) |
631 | { | 687 | { |
632 | struct rt6_info *rt; | 688 | struct rt6_info *rt; |
633 | 689 | ||
@@ -695,7 +751,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad | |||
695 | return rt; | 751 | return rt; |
696 | } | 752 | } |
697 | 753 | ||
698 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr) | 754 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_addr *daddr) |
699 | { | 755 | { |
700 | struct rt6_info *rt = ip6_rt_copy(ort); | 756 | struct rt6_info *rt = ip6_rt_copy(ort); |
701 | if (rt) { | 757 | if (rt) { |
@@ -709,7 +765,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d | |||
709 | } | 765 | } |
710 | 766 | ||
711 | static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, | 767 | static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, |
712 | struct flowi *fl, int flags) | 768 | struct flowi6 *fl6, int flags) |
713 | { | 769 | { |
714 | struct fib6_node *fn; | 770 | struct fib6_node *fn; |
715 | struct rt6_info *rt, *nrt; | 771 | struct rt6_info *rt, *nrt; |
@@ -724,12 +780,12 @@ relookup: | |||
724 | read_lock_bh(&table->tb6_lock); | 780 | read_lock_bh(&table->tb6_lock); |
725 | 781 | ||
726 | restart_2: | 782 | restart_2: |
727 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 783 | fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); |
728 | 784 | ||
729 | restart: | 785 | restart: |
730 | rt = rt6_select(fn, oif, strict | reachable); | 786 | rt = rt6_select(fn, oif, strict | reachable); |
731 | 787 | ||
732 | BACKTRACK(net, &fl->fl6_src); | 788 | BACKTRACK(net, &fl6->saddr); |
733 | if (rt == net->ipv6.ip6_null_entry || | 789 | if (rt == net->ipv6.ip6_null_entry || |
734 | rt->rt6i_flags & RTF_CACHE) | 790 | rt->rt6i_flags & RTF_CACHE) |
735 | goto out; | 791 | goto out; |
@@ -738,9 +794,11 @@ restart: | |||
738 | read_unlock_bh(&table->tb6_lock); | 794 | read_unlock_bh(&table->tb6_lock); |
739 | 795 | ||
740 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 796 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
741 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); | 797 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); |
798 | else if (!(rt->dst.flags & DST_HOST)) | ||
799 | nrt = rt6_alloc_clone(rt, &fl6->daddr); | ||
742 | else | 800 | else |
743 | nrt = rt6_alloc_clone(rt, &fl->fl6_dst); | 801 | goto out2; |
744 | 802 | ||
745 | dst_release(&rt->dst); | 803 | dst_release(&rt->dst); |
746 | rt = nrt ? : net->ipv6.ip6_null_entry; | 804 | rt = nrt ? : net->ipv6.ip6_null_entry; |
@@ -777,74 +835,71 @@ out2: | |||
777 | } | 835 | } |
778 | 836 | ||
779 | static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, | 837 | static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, |
780 | struct flowi *fl, int flags) | 838 | struct flowi6 *fl6, int flags) |
781 | { | 839 | { |
782 | return ip6_pol_route(net, table, fl->iif, fl, flags); | 840 | return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags); |
783 | } | 841 | } |
784 | 842 | ||
785 | void ip6_route_input(struct sk_buff *skb) | 843 | void ip6_route_input(struct sk_buff *skb) |
786 | { | 844 | { |
787 | struct ipv6hdr *iph = ipv6_hdr(skb); | 845 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
788 | struct net *net = dev_net(skb->dev); | 846 | struct net *net = dev_net(skb->dev); |
789 | int flags = RT6_LOOKUP_F_HAS_SADDR; | 847 | int flags = RT6_LOOKUP_F_HAS_SADDR; |
790 | struct flowi fl = { | 848 | struct flowi6 fl6 = { |
791 | .iif = skb->dev->ifindex, | 849 | .flowi6_iif = skb->dev->ifindex, |
792 | .fl6_dst = iph->daddr, | 850 | .daddr = iph->daddr, |
793 | .fl6_src = iph->saddr, | 851 | .saddr = iph->saddr, |
794 | .fl6_flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, | 852 | .flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, |
795 | .mark = skb->mark, | 853 | .flowi6_mark = skb->mark, |
796 | .proto = iph->nexthdr, | 854 | .flowi6_proto = iph->nexthdr, |
797 | }; | 855 | }; |
798 | 856 | ||
799 | if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG) | 857 | if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG) |
800 | flags |= RT6_LOOKUP_F_IFACE; | 858 | flags |= RT6_LOOKUP_F_IFACE; |
801 | 859 | ||
802 | skb_dst_set(skb, fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input)); | 860 | skb_dst_set(skb, fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_input)); |
803 | } | 861 | } |
804 | 862 | ||
805 | static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, | 863 | static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, |
806 | struct flowi *fl, int flags) | 864 | struct flowi6 *fl6, int flags) |
807 | { | 865 | { |
808 | return ip6_pol_route(net, table, fl->oif, fl, flags); | 866 | return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); |
809 | } | 867 | } |
810 | 868 | ||
811 | struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, | 869 | struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk, |
812 | struct flowi *fl) | 870 | struct flowi6 *fl6) |
813 | { | 871 | { |
814 | int flags = 0; | 872 | int flags = 0; |
815 | 873 | ||
816 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl->fl6_dst)) | 874 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr)) |
817 | flags |= RT6_LOOKUP_F_IFACE; | 875 | flags |= RT6_LOOKUP_F_IFACE; |
818 | 876 | ||
819 | if (!ipv6_addr_any(&fl->fl6_src)) | 877 | if (!ipv6_addr_any(&fl6->saddr)) |
820 | flags |= RT6_LOOKUP_F_HAS_SADDR; | 878 | flags |= RT6_LOOKUP_F_HAS_SADDR; |
821 | else if (sk) | 879 | else if (sk) |
822 | flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); | 880 | flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); |
823 | 881 | ||
824 | return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); | 882 | return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output); |
825 | } | 883 | } |
826 | 884 | ||
827 | EXPORT_SYMBOL(ip6_route_output); | 885 | EXPORT_SYMBOL(ip6_route_output); |
828 | 886 | ||
829 | int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl) | 887 | struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) |
830 | { | 888 | { |
831 | struct rt6_info *ort = (struct rt6_info *) *dstp; | 889 | struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig; |
832 | struct rt6_info *rt = (struct rt6_info *) | ||
833 | dst_alloc(&ip6_dst_blackhole_ops); | ||
834 | struct dst_entry *new = NULL; | 890 | struct dst_entry *new = NULL; |
835 | 891 | ||
892 | rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0); | ||
836 | if (rt) { | 893 | if (rt) { |
894 | memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry)); | ||
895 | |||
837 | new = &rt->dst; | 896 | new = &rt->dst; |
838 | 897 | ||
839 | atomic_set(&new->__refcnt, 1); | ||
840 | new->__use = 1; | 898 | new->__use = 1; |
841 | new->input = dst_discard; | 899 | new->input = dst_discard; |
842 | new->output = dst_discard; | 900 | new->output = dst_discard; |
843 | 901 | ||
844 | dst_copy_metrics(new, &ort->dst); | 902 | dst_copy_metrics(new, &ort->dst); |
845 | new->dev = ort->dst.dev; | ||
846 | if (new->dev) | ||
847 | dev_hold(new->dev); | ||
848 | rt->rt6i_idev = ort->rt6i_idev; | 903 | rt->rt6i_idev = ort->rt6i_idev; |
849 | if (rt->rt6i_idev) | 904 | if (rt->rt6i_idev) |
850 | in6_dev_hold(rt->rt6i_idev); | 905 | in6_dev_hold(rt->rt6i_idev); |
@@ -862,11 +917,9 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl | |||
862 | dst_free(new); | 917 | dst_free(new); |
863 | } | 918 | } |
864 | 919 | ||
865 | dst_release(*dstp); | 920 | dst_release(dst_orig); |
866 | *dstp = new; | 921 | return new ? new : ERR_PTR(-ENOMEM); |
867 | return new ? 0 : -ENOMEM; | ||
868 | } | 922 | } |
869 | EXPORT_SYMBOL_GPL(ip6_dst_blackhole); | ||
870 | 923 | ||
871 | /* | 924 | /* |
872 | * Destination cache support functions | 925 | * Destination cache support functions |
@@ -878,9 +931,14 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) | |||
878 | 931 | ||
879 | rt = (struct rt6_info *) dst; | 932 | rt = (struct rt6_info *) dst; |
880 | 933 | ||
881 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) | 934 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) { |
935 | if (rt->rt6i_peer_genid != rt6_peer_genid()) { | ||
936 | if (!rt->rt6i_peer) | ||
937 | rt6_bind_peer(rt, 0); | ||
938 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
939 | } | ||
882 | return dst; | 940 | return dst; |
883 | 941 | } | |
884 | return NULL; | 942 | return NULL; |
885 | } | 943 | } |
886 | 944 | ||
@@ -931,7 +989,6 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
931 | dst_metric_set(dst, RTAX_FEATURES, features); | 989 | dst_metric_set(dst, RTAX_FEATURES, features); |
932 | } | 990 | } |
933 | dst_metric_set(dst, RTAX_MTU, mtu); | 991 | dst_metric_set(dst, RTAX_MTU, mtu); |
934 | call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst); | ||
935 | } | 992 | } |
936 | } | 993 | } |
937 | 994 | ||
@@ -985,13 +1042,12 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
985 | if (unlikely(idev == NULL)) | 1042 | if (unlikely(idev == NULL)) |
986 | return NULL; | 1043 | return NULL; |
987 | 1044 | ||
988 | rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 1045 | rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev); |
989 | if (unlikely(rt == NULL)) { | 1046 | if (unlikely(rt == NULL)) { |
990 | in6_dev_put(idev); | 1047 | in6_dev_put(idev); |
991 | goto out; | 1048 | goto out; |
992 | } | 1049 | } |
993 | 1050 | ||
994 | dev_hold(dev); | ||
995 | if (neigh) | 1051 | if (neigh) |
996 | neigh_hold(neigh); | 1052 | neigh_hold(neigh); |
997 | else { | 1053 | else { |
@@ -1000,7 +1056,6 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
1000 | neigh = NULL; | 1056 | neigh = NULL; |
1001 | } | 1057 | } |
1002 | 1058 | ||
1003 | rt->rt6i_dev = dev; | ||
1004 | rt->rt6i_idev = idev; | 1059 | rt->rt6i_idev = idev; |
1005 | rt->rt6i_nexthop = neigh; | 1060 | rt->rt6i_nexthop = neigh; |
1006 | atomic_set(&rt->dst.__refcnt, 1); | 1061 | atomic_set(&rt->dst.__refcnt, 1); |
@@ -1028,11 +1083,9 @@ out: | |||
1028 | 1083 | ||
1029 | int icmp6_dst_gc(void) | 1084 | int icmp6_dst_gc(void) |
1030 | { | 1085 | { |
1031 | struct dst_entry *dst, *next, **pprev; | 1086 | struct dst_entry *dst, **pprev; |
1032 | int more = 0; | 1087 | int more = 0; |
1033 | 1088 | ||
1034 | next = NULL; | ||
1035 | |||
1036 | spin_lock_bh(&icmp6_dst_lock); | 1089 | spin_lock_bh(&icmp6_dst_lock); |
1037 | pprev = &icmp6_dst_gc_list; | 1090 | pprev = &icmp6_dst_gc_list; |
1038 | 1091 | ||
@@ -1161,7 +1214,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1161 | goto out; | 1214 | goto out; |
1162 | } | 1215 | } |
1163 | 1216 | ||
1164 | rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 1217 | rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL); |
1165 | 1218 | ||
1166 | if (rt == NULL) { | 1219 | if (rt == NULL) { |
1167 | err = -ENOMEM; | 1220 | err = -ENOMEM; |
@@ -1228,7 +1281,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1228 | } | 1281 | } |
1229 | 1282 | ||
1230 | if (cfg->fc_flags & RTF_GATEWAY) { | 1283 | if (cfg->fc_flags & RTF_GATEWAY) { |
1231 | struct in6_addr *gw_addr; | 1284 | const struct in6_addr *gw_addr; |
1232 | int gwa_type; | 1285 | int gwa_type; |
1233 | 1286 | ||
1234 | gw_addr = &cfg->fc_gateway; | 1287 | gw_addr = &cfg->fc_gateway; |
@@ -1281,6 +1334,16 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1281 | if (dev == NULL) | 1334 | if (dev == NULL) |
1282 | goto out; | 1335 | goto out; |
1283 | 1336 | ||
1337 | if (!ipv6_addr_any(&cfg->fc_prefsrc)) { | ||
1338 | if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) { | ||
1339 | err = -EINVAL; | ||
1340 | goto out; | ||
1341 | } | ||
1342 | ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc); | ||
1343 | rt->rt6i_prefsrc.plen = 128; | ||
1344 | } else | ||
1345 | rt->rt6i_prefsrc.plen = 0; | ||
1346 | |||
1284 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { | 1347 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { |
1285 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); | 1348 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); |
1286 | if (IS_ERR(rt->rt6i_nexthop)) { | 1349 | if (IS_ERR(rt->rt6i_nexthop)) { |
@@ -1400,16 +1463,16 @@ static int ip6_route_del(struct fib6_config *cfg) | |||
1400 | * Handle redirects | 1463 | * Handle redirects |
1401 | */ | 1464 | */ |
1402 | struct ip6rd_flowi { | 1465 | struct ip6rd_flowi { |
1403 | struct flowi fl; | 1466 | struct flowi6 fl6; |
1404 | struct in6_addr gateway; | 1467 | struct in6_addr gateway; |
1405 | }; | 1468 | }; |
1406 | 1469 | ||
1407 | static struct rt6_info *__ip6_route_redirect(struct net *net, | 1470 | static struct rt6_info *__ip6_route_redirect(struct net *net, |
1408 | struct fib6_table *table, | 1471 | struct fib6_table *table, |
1409 | struct flowi *fl, | 1472 | struct flowi6 *fl6, |
1410 | int flags) | 1473 | int flags) |
1411 | { | 1474 | { |
1412 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl; | 1475 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6; |
1413 | struct rt6_info *rt; | 1476 | struct rt6_info *rt; |
1414 | struct fib6_node *fn; | 1477 | struct fib6_node *fn; |
1415 | 1478 | ||
@@ -1425,7 +1488,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, | |||
1425 | */ | 1488 | */ |
1426 | 1489 | ||
1427 | read_lock_bh(&table->tb6_lock); | 1490 | read_lock_bh(&table->tb6_lock); |
1428 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 1491 | fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); |
1429 | restart: | 1492 | restart: |
1430 | for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { | 1493 | for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { |
1431 | /* | 1494 | /* |
@@ -1440,7 +1503,7 @@ restart: | |||
1440 | continue; | 1503 | continue; |
1441 | if (!(rt->rt6i_flags & RTF_GATEWAY)) | 1504 | if (!(rt->rt6i_flags & RTF_GATEWAY)) |
1442 | continue; | 1505 | continue; |
1443 | if (fl->oif != rt->rt6i_dev->ifindex) | 1506 | if (fl6->flowi6_oif != rt->rt6i_dev->ifindex) |
1444 | continue; | 1507 | continue; |
1445 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) | 1508 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) |
1446 | continue; | 1509 | continue; |
@@ -1449,7 +1512,7 @@ restart: | |||
1449 | 1512 | ||
1450 | if (!rt) | 1513 | if (!rt) |
1451 | rt = net->ipv6.ip6_null_entry; | 1514 | rt = net->ipv6.ip6_null_entry; |
1452 | BACKTRACK(net, &fl->fl6_src); | 1515 | BACKTRACK(net, &fl6->saddr); |
1453 | out: | 1516 | out: |
1454 | dst_hold(&rt->dst); | 1517 | dst_hold(&rt->dst); |
1455 | 1518 | ||
@@ -1458,18 +1521,18 @@ out: | |||
1458 | return rt; | 1521 | return rt; |
1459 | }; | 1522 | }; |
1460 | 1523 | ||
1461 | static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | 1524 | static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest, |
1462 | struct in6_addr *src, | 1525 | const struct in6_addr *src, |
1463 | struct in6_addr *gateway, | 1526 | const struct in6_addr *gateway, |
1464 | struct net_device *dev) | 1527 | struct net_device *dev) |
1465 | { | 1528 | { |
1466 | int flags = RT6_LOOKUP_F_HAS_SADDR; | 1529 | int flags = RT6_LOOKUP_F_HAS_SADDR; |
1467 | struct net *net = dev_net(dev); | 1530 | struct net *net = dev_net(dev); |
1468 | struct ip6rd_flowi rdfl = { | 1531 | struct ip6rd_flowi rdfl = { |
1469 | .fl = { | 1532 | .fl6 = { |
1470 | .oif = dev->ifindex, | 1533 | .flowi6_oif = dev->ifindex, |
1471 | .fl6_dst = *dest, | 1534 | .daddr = *dest, |
1472 | .fl6_src = *src, | 1535 | .saddr = *src, |
1473 | }, | 1536 | }, |
1474 | }; | 1537 | }; |
1475 | 1538 | ||
@@ -1478,12 +1541,12 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | |||
1478 | if (rt6_need_strict(dest)) | 1541 | if (rt6_need_strict(dest)) |
1479 | flags |= RT6_LOOKUP_F_IFACE; | 1542 | flags |= RT6_LOOKUP_F_IFACE; |
1480 | 1543 | ||
1481 | return (struct rt6_info *)fib6_rule_lookup(net, (struct flowi *)&rdfl, | 1544 | return (struct rt6_info *)fib6_rule_lookup(net, &rdfl.fl6, |
1482 | flags, __ip6_route_redirect); | 1545 | flags, __ip6_route_redirect); |
1483 | } | 1546 | } |
1484 | 1547 | ||
1485 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | 1548 | void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, |
1486 | struct in6_addr *saddr, | 1549 | const struct in6_addr *saddr, |
1487 | struct neighbour *neigh, u8 *lladdr, int on_link) | 1550 | struct neighbour *neigh, u8 *lladdr, int on_link) |
1488 | { | 1551 | { |
1489 | struct rt6_info *rt, *nrt = NULL; | 1552 | struct rt6_info *rt, *nrt = NULL; |
@@ -1557,7 +1620,7 @@ out: | |||
1557 | * i.e. Path MTU discovery | 1620 | * i.e. Path MTU discovery |
1558 | */ | 1621 | */ |
1559 | 1622 | ||
1560 | static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr, | 1623 | static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr *saddr, |
1561 | struct net *net, u32 pmtu, int ifindex) | 1624 | struct net *net, u32 pmtu, int ifindex) |
1562 | { | 1625 | { |
1563 | struct rt6_info *rt, *nrt; | 1626 | struct rt6_info *rt, *nrt; |
@@ -1642,7 +1705,7 @@ out: | |||
1642 | dst_release(&rt->dst); | 1705 | dst_release(&rt->dst); |
1643 | } | 1706 | } |
1644 | 1707 | ||
1645 | void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | 1708 | void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *saddr, |
1646 | struct net_device *dev, u32 pmtu) | 1709 | struct net_device *dev, u32 pmtu) |
1647 | { | 1710 | { |
1648 | struct net *net = dev_net(dev); | 1711 | struct net *net = dev_net(dev); |
@@ -1670,7 +1733,8 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
1670 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | 1733 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) |
1671 | { | 1734 | { |
1672 | struct net *net = dev_net(ort->rt6i_dev); | 1735 | struct net *net = dev_net(ort->rt6i_dev); |
1673 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 1736 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, |
1737 | ort->dst.dev); | ||
1674 | 1738 | ||
1675 | if (rt) { | 1739 | if (rt) { |
1676 | rt->dst.input = ort->dst.input; | 1740 | rt->dst.input = ort->dst.input; |
@@ -1678,9 +1742,6 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1678 | 1742 | ||
1679 | dst_copy_metrics(&rt->dst, &ort->dst); | 1743 | dst_copy_metrics(&rt->dst, &ort->dst); |
1680 | rt->dst.error = ort->dst.error; | 1744 | rt->dst.error = ort->dst.error; |
1681 | rt->dst.dev = ort->dst.dev; | ||
1682 | if (rt->dst.dev) | ||
1683 | dev_hold(rt->dst.dev); | ||
1684 | rt->rt6i_idev = ort->rt6i_idev; | 1745 | rt->rt6i_idev = ort->rt6i_idev; |
1685 | if (rt->rt6i_idev) | 1746 | if (rt->rt6i_idev) |
1686 | in6_dev_hold(rt->rt6i_idev); | 1747 | in6_dev_hold(rt->rt6i_idev); |
@@ -1695,6 +1756,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1695 | #ifdef CONFIG_IPV6_SUBTREES | 1756 | #ifdef CONFIG_IPV6_SUBTREES |
1696 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); | 1757 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); |
1697 | #endif | 1758 | #endif |
1759 | memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key)); | ||
1698 | rt->rt6i_table = ort->rt6i_table; | 1760 | rt->rt6i_table = ort->rt6i_table; |
1699 | } | 1761 | } |
1700 | return rt; | 1762 | return rt; |
@@ -1702,8 +1764,8 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1702 | 1764 | ||
1703 | #ifdef CONFIG_IPV6_ROUTE_INFO | 1765 | #ifdef CONFIG_IPV6_ROUTE_INFO |
1704 | static struct rt6_info *rt6_get_route_info(struct net *net, | 1766 | static struct rt6_info *rt6_get_route_info(struct net *net, |
1705 | struct in6_addr *prefix, int prefixlen, | 1767 | const struct in6_addr *prefix, int prefixlen, |
1706 | struct in6_addr *gwaddr, int ifindex) | 1768 | const struct in6_addr *gwaddr, int ifindex) |
1707 | { | 1769 | { |
1708 | struct fib6_node *fn; | 1770 | struct fib6_node *fn; |
1709 | struct rt6_info *rt = NULL; | 1771 | struct rt6_info *rt = NULL; |
@@ -1734,8 +1796,8 @@ out: | |||
1734 | } | 1796 | } |
1735 | 1797 | ||
1736 | static struct rt6_info *rt6_add_route_info(struct net *net, | 1798 | static struct rt6_info *rt6_add_route_info(struct net *net, |
1737 | struct in6_addr *prefix, int prefixlen, | 1799 | const struct in6_addr *prefix, int prefixlen, |
1738 | struct in6_addr *gwaddr, int ifindex, | 1800 | const struct in6_addr *gwaddr, int ifindex, |
1739 | unsigned pref) | 1801 | unsigned pref) |
1740 | { | 1802 | { |
1741 | struct fib6_config cfg = { | 1803 | struct fib6_config cfg = { |
@@ -1763,7 +1825,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net, | |||
1763 | } | 1825 | } |
1764 | #endif | 1826 | #endif |
1765 | 1827 | ||
1766 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) | 1828 | struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev) |
1767 | { | 1829 | { |
1768 | struct rt6_info *rt; | 1830 | struct rt6_info *rt; |
1769 | struct fib6_table *table; | 1831 | struct fib6_table *table; |
@@ -1785,7 +1847,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
1785 | return rt; | 1847 | return rt; |
1786 | } | 1848 | } |
1787 | 1849 | ||
1788 | struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | 1850 | struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, |
1789 | struct net_device *dev, | 1851 | struct net_device *dev, |
1790 | unsigned int pref) | 1852 | unsigned int pref) |
1791 | { | 1853 | { |
@@ -1950,7 +2012,8 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1950 | int anycast) | 2012 | int anycast) |
1951 | { | 2013 | { |
1952 | struct net *net = dev_net(idev->dev); | 2014 | struct net *net = dev_net(idev->dev); |
1953 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 2015 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, |
2016 | net->loopback_dev); | ||
1954 | struct neighbour *neigh; | 2017 | struct neighbour *neigh; |
1955 | 2018 | ||
1956 | if (rt == NULL) { | 2019 | if (rt == NULL) { |
@@ -1960,15 +2023,12 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1960 | return ERR_PTR(-ENOMEM); | 2023 | return ERR_PTR(-ENOMEM); |
1961 | } | 2024 | } |
1962 | 2025 | ||
1963 | dev_hold(net->loopback_dev); | ||
1964 | in6_dev_hold(idev); | 2026 | in6_dev_hold(idev); |
1965 | 2027 | ||
1966 | rt->dst.flags = DST_HOST; | 2028 | rt->dst.flags = DST_HOST; |
1967 | rt->dst.input = ip6_input; | 2029 | rt->dst.input = ip6_input; |
1968 | rt->dst.output = ip6_output; | 2030 | rt->dst.output = ip6_output; |
1969 | rt->rt6i_dev = net->loopback_dev; | ||
1970 | rt->rt6i_idev = idev; | 2031 | rt->rt6i_idev = idev; |
1971 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1); | ||
1972 | rt->dst.obsolete = -1; | 2032 | rt->dst.obsolete = -1; |
1973 | 2033 | ||
1974 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; | 2034 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; |
@@ -1980,12 +2040,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1980 | if (IS_ERR(neigh)) { | 2040 | if (IS_ERR(neigh)) { |
1981 | dst_free(&rt->dst); | 2041 | dst_free(&rt->dst); |
1982 | 2042 | ||
1983 | /* We are casting this because that is the return | 2043 | return ERR_CAST(neigh); |
1984 | * value type. But an errno encoded pointer is the | ||
1985 | * same regardless of the underlying pointer type, | ||
1986 | * and that's what we are returning. So this is OK. | ||
1987 | */ | ||
1988 | return (struct rt6_info *) neigh; | ||
1989 | } | 2044 | } |
1990 | rt->rt6i_nexthop = neigh; | 2045 | rt->rt6i_nexthop = neigh; |
1991 | 2046 | ||
@@ -1998,6 +2053,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1998 | return rt; | 2053 | return rt; |
1999 | } | 2054 | } |
2000 | 2055 | ||
2056 | int ip6_route_get_saddr(struct net *net, | ||
2057 | struct rt6_info *rt, | ||
2058 | const struct in6_addr *daddr, | ||
2059 | unsigned int prefs, | ||
2060 | struct in6_addr *saddr) | ||
2061 | { | ||
2062 | struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt); | ||
2063 | int err = 0; | ||
2064 | if (rt->rt6i_prefsrc.plen) | ||
2065 | ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr); | ||
2066 | else | ||
2067 | err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, | ||
2068 | daddr, prefs, saddr); | ||
2069 | return err; | ||
2070 | } | ||
2071 | |||
2072 | /* remove deleted ip from prefsrc entries */ | ||
2073 | struct arg_dev_net_ip { | ||
2074 | struct net_device *dev; | ||
2075 | struct net *net; | ||
2076 | struct in6_addr *addr; | ||
2077 | }; | ||
2078 | |||
2079 | static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg) | ||
2080 | { | ||
2081 | struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev; | ||
2082 | struct net *net = ((struct arg_dev_net_ip *)arg)->net; | ||
2083 | struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; | ||
2084 | |||
2085 | if (((void *)rt->rt6i_dev == dev || dev == NULL) && | ||
2086 | rt != net->ipv6.ip6_null_entry && | ||
2087 | ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) { | ||
2088 | /* remove prefsrc entry */ | ||
2089 | rt->rt6i_prefsrc.plen = 0; | ||
2090 | } | ||
2091 | return 0; | ||
2092 | } | ||
2093 | |||
2094 | void rt6_remove_prefsrc(struct inet6_ifaddr *ifp) | ||
2095 | { | ||
2096 | struct net *net = dev_net(ifp->idev->dev); | ||
2097 | struct arg_dev_net_ip adni = { | ||
2098 | .dev = ifp->idev->dev, | ||
2099 | .net = net, | ||
2100 | .addr = &ifp->addr, | ||
2101 | }; | ||
2102 | fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni); | ||
2103 | } | ||
2104 | |||
2001 | struct arg_dev_net { | 2105 | struct arg_dev_net { |
2002 | struct net_device *dev; | 2106 | struct net_device *dev; |
2003 | struct net *net; | 2107 | struct net *net; |
@@ -2144,6 +2248,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2144 | nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); | 2248 | nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); |
2145 | } | 2249 | } |
2146 | 2250 | ||
2251 | if (tb[RTA_PREFSRC]) | ||
2252 | nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16); | ||
2253 | |||
2147 | if (tb[RTA_OIF]) | 2254 | if (tb[RTA_OIF]) |
2148 | cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); | 2255 | cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); |
2149 | 2256 | ||
@@ -2286,13 +2393,17 @@ static int rt6_fill_node(struct net *net, | |||
2286 | #endif | 2393 | #endif |
2287 | NLA_PUT_U32(skb, RTA_IIF, iif); | 2394 | NLA_PUT_U32(skb, RTA_IIF, iif); |
2288 | } else if (dst) { | 2395 | } else if (dst) { |
2289 | struct inet6_dev *idev = ip6_dst_idev(&rt->dst); | ||
2290 | struct in6_addr saddr_buf; | 2396 | struct in6_addr saddr_buf; |
2291 | if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, | 2397 | if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0) |
2292 | dst, 0, &saddr_buf) == 0) | ||
2293 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); | 2398 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); |
2294 | } | 2399 | } |
2295 | 2400 | ||
2401 | if (rt->rt6i_prefsrc.plen) { | ||
2402 | struct in6_addr saddr_buf; | ||
2403 | ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr); | ||
2404 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); | ||
2405 | } | ||
2406 | |||
2296 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) | 2407 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
2297 | goto nla_put_failure; | 2408 | goto nla_put_failure; |
2298 | 2409 | ||
@@ -2346,7 +2457,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2346 | struct rt6_info *rt; | 2457 | struct rt6_info *rt; |
2347 | struct sk_buff *skb; | 2458 | struct sk_buff *skb; |
2348 | struct rtmsg *rtm; | 2459 | struct rtmsg *rtm; |
2349 | struct flowi fl; | 2460 | struct flowi6 fl6; |
2350 | int err, iif = 0; | 2461 | int err, iif = 0; |
2351 | 2462 | ||
2352 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); | 2463 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
@@ -2354,27 +2465,27 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2354 | goto errout; | 2465 | goto errout; |
2355 | 2466 | ||
2356 | err = -EINVAL; | 2467 | err = -EINVAL; |
2357 | memset(&fl, 0, sizeof(fl)); | 2468 | memset(&fl6, 0, sizeof(fl6)); |
2358 | 2469 | ||
2359 | if (tb[RTA_SRC]) { | 2470 | if (tb[RTA_SRC]) { |
2360 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) | 2471 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) |
2361 | goto errout; | 2472 | goto errout; |
2362 | 2473 | ||
2363 | ipv6_addr_copy(&fl.fl6_src, nla_data(tb[RTA_SRC])); | 2474 | ipv6_addr_copy(&fl6.saddr, nla_data(tb[RTA_SRC])); |
2364 | } | 2475 | } |
2365 | 2476 | ||
2366 | if (tb[RTA_DST]) { | 2477 | if (tb[RTA_DST]) { |
2367 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) | 2478 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) |
2368 | goto errout; | 2479 | goto errout; |
2369 | 2480 | ||
2370 | ipv6_addr_copy(&fl.fl6_dst, nla_data(tb[RTA_DST])); | 2481 | ipv6_addr_copy(&fl6.daddr, nla_data(tb[RTA_DST])); |
2371 | } | 2482 | } |
2372 | 2483 | ||
2373 | if (tb[RTA_IIF]) | 2484 | if (tb[RTA_IIF]) |
2374 | iif = nla_get_u32(tb[RTA_IIF]); | 2485 | iif = nla_get_u32(tb[RTA_IIF]); |
2375 | 2486 | ||
2376 | if (tb[RTA_OIF]) | 2487 | if (tb[RTA_OIF]) |
2377 | fl.oif = nla_get_u32(tb[RTA_OIF]); | 2488 | fl6.flowi6_oif = nla_get_u32(tb[RTA_OIF]); |
2378 | 2489 | ||
2379 | if (iif) { | 2490 | if (iif) { |
2380 | struct net_device *dev; | 2491 | struct net_device *dev; |
@@ -2397,10 +2508,10 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2397 | skb_reset_mac_header(skb); | 2508 | skb_reset_mac_header(skb); |
2398 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | 2509 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); |
2399 | 2510 | ||
2400 | rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); | 2511 | rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl6); |
2401 | skb_dst_set(skb, &rt->dst); | 2512 | skb_dst_set(skb, &rt->dst); |
2402 | 2513 | ||
2403 | err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, | 2514 | err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, |
2404 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2515 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, |
2405 | nlh->nlmsg_seq, 0, 0, 0); | 2516 | nlh->nlmsg_seq, 0, 0, 0); |
2406 | if (err < 0) { | 2517 | if (err < 0) { |
@@ -2557,14 +2668,16 @@ static | |||
2557 | int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, | 2668 | int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, |
2558 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2669 | void __user *buffer, size_t *lenp, loff_t *ppos) |
2559 | { | 2670 | { |
2560 | struct net *net = current->nsproxy->net_ns; | 2671 | struct net *net; |
2561 | int delay = net->ipv6.sysctl.flush_delay; | 2672 | int delay; |
2562 | if (write) { | 2673 | if (!write) |
2563 | proc_dointvec(ctl, write, buffer, lenp, ppos); | ||
2564 | fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); | ||
2565 | return 0; | ||
2566 | } else | ||
2567 | return -EINVAL; | 2674 | return -EINVAL; |
2675 | |||
2676 | net = (struct net *)ctl->extra1; | ||
2677 | delay = net->ipv6.sysctl.flush_delay; | ||
2678 | proc_dointvec(ctl, write, buffer, lenp, ppos); | ||
2679 | fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); | ||
2680 | return 0; | ||
2568 | } | 2681 | } |
2569 | 2682 | ||
2570 | ctl_table ipv6_route_table_template[] = { | 2683 | ctl_table ipv6_route_table_template[] = { |
@@ -2651,6 +2764,7 @@ struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) | |||
2651 | 2764 | ||
2652 | if (table) { | 2765 | if (table) { |
2653 | table[0].data = &net->ipv6.sysctl.flush_delay; | 2766 | table[0].data = &net->ipv6.sysctl.flush_delay; |
2767 | table[0].extra1 = net; | ||
2654 | table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh; | 2768 | table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh; |
2655 | table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; | 2769 | table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; |
2656 | table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; | 2770 | table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; |
@@ -2684,7 +2798,8 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2684 | net->ipv6.ip6_null_entry->dst.path = | 2798 | net->ipv6.ip6_null_entry->dst.path = |
2685 | (struct dst_entry *)net->ipv6.ip6_null_entry; | 2799 | (struct dst_entry *)net->ipv6.ip6_null_entry; |
2686 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2800 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
2687 | dst_metric_set(&net->ipv6.ip6_null_entry->dst, RTAX_HOPLIMIT, 255); | 2801 | dst_init_metrics(&net->ipv6.ip6_null_entry->dst, |
2802 | ip6_template_metrics, true); | ||
2688 | 2803 | ||
2689 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 2804 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
2690 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, | 2805 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, |
@@ -2695,7 +2810,8 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2695 | net->ipv6.ip6_prohibit_entry->dst.path = | 2810 | net->ipv6.ip6_prohibit_entry->dst.path = |
2696 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; | 2811 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; |
2697 | net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2812 | net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
2698 | dst_metric_set(&net->ipv6.ip6_prohibit_entry->dst, RTAX_HOPLIMIT, 255); | 2813 | dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst, |
2814 | ip6_template_metrics, true); | ||
2699 | 2815 | ||
2700 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, | 2816 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, |
2701 | sizeof(*net->ipv6.ip6_blk_hole_entry), | 2817 | sizeof(*net->ipv6.ip6_blk_hole_entry), |
@@ -2705,7 +2821,8 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2705 | net->ipv6.ip6_blk_hole_entry->dst.path = | 2821 | net->ipv6.ip6_blk_hole_entry->dst.path = |
2706 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; | 2822 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; |
2707 | net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2823 | net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
2708 | dst_metric_set(&net->ipv6.ip6_blk_hole_entry->dst, RTAX_HOPLIMIT, 255); | 2824 | dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, |
2825 | ip6_template_metrics, true); | ||
2709 | #endif | 2826 | #endif |
2710 | 2827 | ||
2711 | net->ipv6.sysctl.flush_delay = 0; | 2828 | net->ipv6.sysctl.flush_delay = 0; |