diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 215 |
1 files changed, 133 insertions, 82 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a998db6e7895..fd0eec6f88c6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -97,6 +97,36 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
97 | struct in6_addr *gwaddr, int ifindex); | 97 | 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 = { |
@@ -187,7 +229,7 @@ static struct rt6_info ip6_blk_hole_entry_template = { | |||
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) |
189 | { | 231 | { |
190 | return (struct rt6_info *)dst_alloc(ops); | 232 | return (struct rt6_info *)dst_alloc(ops, 0); |
191 | } | 233 | } |
192 | 234 | ||
193 | static void ip6_dst_destroy(struct dst_entry *dst) | 235 | static void ip6_dst_destroy(struct dst_entry *dst) |
@@ -206,6 +248,13 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
206 | } | 248 | } |
207 | } | 249 | } |
208 | 250 | ||
251 | static atomic_t __rt6_peer_genid = ATOMIC_INIT(0); | ||
252 | |||
253 | static u32 rt6_peer_genid(void) | ||
254 | { | ||
255 | return atomic_read(&__rt6_peer_genid); | ||
256 | } | ||
257 | |||
209 | void rt6_bind_peer(struct rt6_info *rt, int create) | 258 | void rt6_bind_peer(struct rt6_info *rt, int create) |
210 | { | 259 | { |
211 | struct inet_peer *peer; | 260 | struct inet_peer *peer; |
@@ -213,6 +262,8 @@ void rt6_bind_peer(struct rt6_info *rt, int create) | |||
213 | peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); | 262 | peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); |
214 | if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) | 263 | if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) |
215 | inet_putpeer(peer); | 264 | inet_putpeer(peer); |
265 | else | ||
266 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
216 | } | 267 | } |
217 | 268 | ||
218 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 269 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
@@ -555,17 +606,17 @@ do { \ | |||
555 | 606 | ||
556 | static struct rt6_info *ip6_pol_route_lookup(struct net *net, | 607 | static struct rt6_info *ip6_pol_route_lookup(struct net *net, |
557 | struct fib6_table *table, | 608 | struct fib6_table *table, |
558 | struct flowi *fl, int flags) | 609 | struct flowi6 *fl6, int flags) |
559 | { | 610 | { |
560 | struct fib6_node *fn; | 611 | struct fib6_node *fn; |
561 | struct rt6_info *rt; | 612 | struct rt6_info *rt; |
562 | 613 | ||
563 | read_lock_bh(&table->tb6_lock); | 614 | read_lock_bh(&table->tb6_lock); |
564 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 615 | fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); |
565 | restart: | 616 | restart: |
566 | rt = fn->leaf; | 617 | rt = fn->leaf; |
567 | rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags); | 618 | rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags); |
568 | BACKTRACK(net, &fl->fl6_src); | 619 | BACKTRACK(net, &fl6->saddr); |
569 | out: | 620 | out: |
570 | dst_use(&rt->dst, jiffies); | 621 | dst_use(&rt->dst, jiffies); |
571 | read_unlock_bh(&table->tb6_lock); | 622 | read_unlock_bh(&table->tb6_lock); |
@@ -576,19 +627,19 @@ out: | |||
576 | struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, | 627 | struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, |
577 | const struct in6_addr *saddr, int oif, int strict) | 628 | const struct in6_addr *saddr, int oif, int strict) |
578 | { | 629 | { |
579 | struct flowi fl = { | 630 | struct flowi6 fl6 = { |
580 | .oif = oif, | 631 | .flowi6_oif = oif, |
581 | .fl6_dst = *daddr, | 632 | .daddr = *daddr, |
582 | }; | 633 | }; |
583 | struct dst_entry *dst; | 634 | struct dst_entry *dst; |
584 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; | 635 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; |
585 | 636 | ||
586 | if (saddr) { | 637 | if (saddr) { |
587 | memcpy(&fl.fl6_src, saddr, sizeof(*saddr)); | 638 | memcpy(&fl6.saddr, saddr, sizeof(*saddr)); |
588 | flags |= RT6_LOOKUP_F_HAS_SADDR; | 639 | flags |= RT6_LOOKUP_F_HAS_SADDR; |
589 | } | 640 | } |
590 | 641 | ||
591 | dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_lookup); | 642 | dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup); |
592 | if (dst->error == 0) | 643 | if (dst->error == 0) |
593 | return (struct rt6_info *) dst; | 644 | return (struct rt6_info *) dst; |
594 | 645 | ||
@@ -709,7 +760,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d | |||
709 | } | 760 | } |
710 | 761 | ||
711 | static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, | 762 | static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, |
712 | struct flowi *fl, int flags) | 763 | struct flowi6 *fl6, int flags) |
713 | { | 764 | { |
714 | struct fib6_node *fn; | 765 | struct fib6_node *fn; |
715 | struct rt6_info *rt, *nrt; | 766 | struct rt6_info *rt, *nrt; |
@@ -724,12 +775,12 @@ relookup: | |||
724 | read_lock_bh(&table->tb6_lock); | 775 | read_lock_bh(&table->tb6_lock); |
725 | 776 | ||
726 | restart_2: | 777 | restart_2: |
727 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 778 | fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); |
728 | 779 | ||
729 | restart: | 780 | restart: |
730 | rt = rt6_select(fn, oif, strict | reachable); | 781 | rt = rt6_select(fn, oif, strict | reachable); |
731 | 782 | ||
732 | BACKTRACK(net, &fl->fl6_src); | 783 | BACKTRACK(net, &fl6->saddr); |
733 | if (rt == net->ipv6.ip6_null_entry || | 784 | if (rt == net->ipv6.ip6_null_entry || |
734 | rt->rt6i_flags & RTF_CACHE) | 785 | rt->rt6i_flags & RTF_CACHE) |
735 | goto out; | 786 | goto out; |
@@ -738,9 +789,11 @@ restart: | |||
738 | read_unlock_bh(&table->tb6_lock); | 789 | read_unlock_bh(&table->tb6_lock); |
739 | 790 | ||
740 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 791 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
741 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); | 792 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); |
793 | else if (!(rt->dst.flags & DST_HOST)) | ||
794 | nrt = rt6_alloc_clone(rt, &fl6->daddr); | ||
742 | else | 795 | else |
743 | nrt = rt6_alloc_clone(rt, &fl->fl6_dst); | 796 | goto out2; |
744 | 797 | ||
745 | dst_release(&rt->dst); | 798 | dst_release(&rt->dst); |
746 | rt = nrt ? : net->ipv6.ip6_null_entry; | 799 | rt = nrt ? : net->ipv6.ip6_null_entry; |
@@ -777,9 +830,9 @@ out2: | |||
777 | } | 830 | } |
778 | 831 | ||
779 | static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, | 832 | static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, |
780 | struct flowi *fl, int flags) | 833 | struct flowi6 *fl6, int flags) |
781 | { | 834 | { |
782 | return ip6_pol_route(net, table, fl->iif, fl, flags); | 835 | return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags); |
783 | } | 836 | } |
784 | 837 | ||
785 | void ip6_route_input(struct sk_buff *skb) | 838 | void ip6_route_input(struct sk_buff *skb) |
@@ -787,56 +840,54 @@ void ip6_route_input(struct sk_buff *skb) | |||
787 | struct ipv6hdr *iph = ipv6_hdr(skb); | 840 | struct ipv6hdr *iph = ipv6_hdr(skb); |
788 | struct net *net = dev_net(skb->dev); | 841 | struct net *net = dev_net(skb->dev); |
789 | int flags = RT6_LOOKUP_F_HAS_SADDR; | 842 | int flags = RT6_LOOKUP_F_HAS_SADDR; |
790 | struct flowi fl = { | 843 | struct flowi6 fl6 = { |
791 | .iif = skb->dev->ifindex, | 844 | .flowi6_iif = skb->dev->ifindex, |
792 | .fl6_dst = iph->daddr, | 845 | .daddr = iph->daddr, |
793 | .fl6_src = iph->saddr, | 846 | .saddr = iph->saddr, |
794 | .fl6_flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, | 847 | .flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, |
795 | .mark = skb->mark, | 848 | .flowi6_mark = skb->mark, |
796 | .proto = iph->nexthdr, | 849 | .flowi6_proto = iph->nexthdr, |
797 | }; | 850 | }; |
798 | 851 | ||
799 | if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG) | 852 | if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG) |
800 | flags |= RT6_LOOKUP_F_IFACE; | 853 | flags |= RT6_LOOKUP_F_IFACE; |
801 | 854 | ||
802 | skb_dst_set(skb, fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input)); | 855 | skb_dst_set(skb, fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_input)); |
803 | } | 856 | } |
804 | 857 | ||
805 | static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, | 858 | static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, |
806 | struct flowi *fl, int flags) | 859 | struct flowi6 *fl6, int flags) |
807 | { | 860 | { |
808 | return ip6_pol_route(net, table, fl->oif, fl, flags); | 861 | return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); |
809 | } | 862 | } |
810 | 863 | ||
811 | struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, | 864 | struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk, |
812 | struct flowi *fl) | 865 | struct flowi6 *fl6) |
813 | { | 866 | { |
814 | int flags = 0; | 867 | int flags = 0; |
815 | 868 | ||
816 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl->fl6_dst)) | 869 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr)) |
817 | flags |= RT6_LOOKUP_F_IFACE; | 870 | flags |= RT6_LOOKUP_F_IFACE; |
818 | 871 | ||
819 | if (!ipv6_addr_any(&fl->fl6_src)) | 872 | if (!ipv6_addr_any(&fl6->saddr)) |
820 | flags |= RT6_LOOKUP_F_HAS_SADDR; | 873 | flags |= RT6_LOOKUP_F_HAS_SADDR; |
821 | else if (sk) | 874 | else if (sk) |
822 | flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); | 875 | flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); |
823 | 876 | ||
824 | return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); | 877 | return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output); |
825 | } | 878 | } |
826 | 879 | ||
827 | EXPORT_SYMBOL(ip6_route_output); | 880 | EXPORT_SYMBOL(ip6_route_output); |
828 | 881 | ||
829 | int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl) | 882 | struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) |
830 | { | 883 | { |
831 | struct rt6_info *ort = (struct rt6_info *) *dstp; | 884 | struct rt6_info *rt = dst_alloc(&ip6_dst_blackhole_ops, 1); |
832 | struct rt6_info *rt = (struct rt6_info *) | 885 | struct rt6_info *ort = (struct rt6_info *) dst_orig; |
833 | dst_alloc(&ip6_dst_blackhole_ops); | ||
834 | struct dst_entry *new = NULL; | 886 | struct dst_entry *new = NULL; |
835 | 887 | ||
836 | if (rt) { | 888 | if (rt) { |
837 | new = &rt->dst; | 889 | new = &rt->dst; |
838 | 890 | ||
839 | atomic_set(&new->__refcnt, 1); | ||
840 | new->__use = 1; | 891 | new->__use = 1; |
841 | new->input = dst_discard; | 892 | new->input = dst_discard; |
842 | new->output = dst_discard; | 893 | new->output = dst_discard; |
@@ -862,11 +913,9 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl | |||
862 | dst_free(new); | 913 | dst_free(new); |
863 | } | 914 | } |
864 | 915 | ||
865 | dst_release(*dstp); | 916 | dst_release(dst_orig); |
866 | *dstp = new; | 917 | return new ? new : ERR_PTR(-ENOMEM); |
867 | return new ? 0 : -ENOMEM; | ||
868 | } | 918 | } |
869 | EXPORT_SYMBOL_GPL(ip6_dst_blackhole); | ||
870 | 919 | ||
871 | /* | 920 | /* |
872 | * Destination cache support functions | 921 | * Destination cache support functions |
@@ -878,9 +927,14 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) | |||
878 | 927 | ||
879 | rt = (struct rt6_info *) dst; | 928 | rt = (struct rt6_info *) dst; |
880 | 929 | ||
881 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) | 930 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) { |
931 | if (rt->rt6i_peer_genid != rt6_peer_genid()) { | ||
932 | if (!rt->rt6i_peer) | ||
933 | rt6_bind_peer(rt, 0); | ||
934 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
935 | } | ||
882 | return dst; | 936 | return dst; |
883 | 937 | } | |
884 | return NULL; | 938 | return NULL; |
885 | } | 939 | } |
886 | 940 | ||
@@ -931,7 +985,6 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
931 | dst_metric_set(dst, RTAX_FEATURES, features); | 985 | dst_metric_set(dst, RTAX_FEATURES, features); |
932 | } | 986 | } |
933 | dst_metric_set(dst, RTAX_MTU, mtu); | 987 | dst_metric_set(dst, RTAX_MTU, mtu); |
934 | call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst); | ||
935 | } | 988 | } |
936 | } | 989 | } |
937 | 990 | ||
@@ -1028,11 +1081,9 @@ out: | |||
1028 | 1081 | ||
1029 | int icmp6_dst_gc(void) | 1082 | int icmp6_dst_gc(void) |
1030 | { | 1083 | { |
1031 | struct dst_entry *dst, *next, **pprev; | 1084 | struct dst_entry *dst, **pprev; |
1032 | int more = 0; | 1085 | int more = 0; |
1033 | 1086 | ||
1034 | next = NULL; | ||
1035 | |||
1036 | spin_lock_bh(&icmp6_dst_lock); | 1087 | spin_lock_bh(&icmp6_dst_lock); |
1037 | pprev = &icmp6_dst_gc_list; | 1088 | pprev = &icmp6_dst_gc_list; |
1038 | 1089 | ||
@@ -1400,16 +1451,16 @@ static int ip6_route_del(struct fib6_config *cfg) | |||
1400 | * Handle redirects | 1451 | * Handle redirects |
1401 | */ | 1452 | */ |
1402 | struct ip6rd_flowi { | 1453 | struct ip6rd_flowi { |
1403 | struct flowi fl; | 1454 | struct flowi6 fl6; |
1404 | struct in6_addr gateway; | 1455 | struct in6_addr gateway; |
1405 | }; | 1456 | }; |
1406 | 1457 | ||
1407 | static struct rt6_info *__ip6_route_redirect(struct net *net, | 1458 | static struct rt6_info *__ip6_route_redirect(struct net *net, |
1408 | struct fib6_table *table, | 1459 | struct fib6_table *table, |
1409 | struct flowi *fl, | 1460 | struct flowi6 *fl6, |
1410 | int flags) | 1461 | int flags) |
1411 | { | 1462 | { |
1412 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl; | 1463 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6; |
1413 | struct rt6_info *rt; | 1464 | struct rt6_info *rt; |
1414 | struct fib6_node *fn; | 1465 | struct fib6_node *fn; |
1415 | 1466 | ||
@@ -1425,7 +1476,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, | |||
1425 | */ | 1476 | */ |
1426 | 1477 | ||
1427 | read_lock_bh(&table->tb6_lock); | 1478 | read_lock_bh(&table->tb6_lock); |
1428 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 1479 | fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); |
1429 | restart: | 1480 | restart: |
1430 | for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { | 1481 | for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { |
1431 | /* | 1482 | /* |
@@ -1440,7 +1491,7 @@ restart: | |||
1440 | continue; | 1491 | continue; |
1441 | if (!(rt->rt6i_flags & RTF_GATEWAY)) | 1492 | if (!(rt->rt6i_flags & RTF_GATEWAY)) |
1442 | continue; | 1493 | continue; |
1443 | if (fl->oif != rt->rt6i_dev->ifindex) | 1494 | if (fl6->flowi6_oif != rt->rt6i_dev->ifindex) |
1444 | continue; | 1495 | continue; |
1445 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) | 1496 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) |
1446 | continue; | 1497 | continue; |
@@ -1449,7 +1500,7 @@ restart: | |||
1449 | 1500 | ||
1450 | if (!rt) | 1501 | if (!rt) |
1451 | rt = net->ipv6.ip6_null_entry; | 1502 | rt = net->ipv6.ip6_null_entry; |
1452 | BACKTRACK(net, &fl->fl6_src); | 1503 | BACKTRACK(net, &fl6->saddr); |
1453 | out: | 1504 | out: |
1454 | dst_hold(&rt->dst); | 1505 | dst_hold(&rt->dst); |
1455 | 1506 | ||
@@ -1466,10 +1517,10 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | |||
1466 | int flags = RT6_LOOKUP_F_HAS_SADDR; | 1517 | int flags = RT6_LOOKUP_F_HAS_SADDR; |
1467 | struct net *net = dev_net(dev); | 1518 | struct net *net = dev_net(dev); |
1468 | struct ip6rd_flowi rdfl = { | 1519 | struct ip6rd_flowi rdfl = { |
1469 | .fl = { | 1520 | .fl6 = { |
1470 | .oif = dev->ifindex, | 1521 | .flowi6_oif = dev->ifindex, |
1471 | .fl6_dst = *dest, | 1522 | .daddr = *dest, |
1472 | .fl6_src = *src, | 1523 | .saddr = *src, |
1473 | }, | 1524 | }, |
1474 | }; | 1525 | }; |
1475 | 1526 | ||
@@ -1478,7 +1529,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | |||
1478 | if (rt6_need_strict(dest)) | 1529 | if (rt6_need_strict(dest)) |
1479 | flags |= RT6_LOOKUP_F_IFACE; | 1530 | flags |= RT6_LOOKUP_F_IFACE; |
1480 | 1531 | ||
1481 | return (struct rt6_info *)fib6_rule_lookup(net, (struct flowi *)&rdfl, | 1532 | return (struct rt6_info *)fib6_rule_lookup(net, &rdfl.fl6, |
1482 | flags, __ip6_route_redirect); | 1533 | flags, __ip6_route_redirect); |
1483 | } | 1534 | } |
1484 | 1535 | ||
@@ -1968,7 +2019,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1968 | rt->dst.output = ip6_output; | 2019 | rt->dst.output = ip6_output; |
1969 | rt->rt6i_dev = net->loopback_dev; | 2020 | rt->rt6i_dev = net->loopback_dev; |
1970 | rt->rt6i_idev = idev; | 2021 | rt->rt6i_idev = idev; |
1971 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1); | ||
1972 | rt->dst.obsolete = -1; | 2022 | rt->dst.obsolete = -1; |
1973 | 2023 | ||
1974 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; | 2024 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; |
@@ -1980,12 +2030,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1980 | if (IS_ERR(neigh)) { | 2030 | if (IS_ERR(neigh)) { |
1981 | dst_free(&rt->dst); | 2031 | dst_free(&rt->dst); |
1982 | 2032 | ||
1983 | /* We are casting this because that is the return | 2033 | 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 | } | 2034 | } |
1990 | rt->rt6i_nexthop = neigh; | 2035 | rt->rt6i_nexthop = neigh; |
1991 | 2036 | ||
@@ -2346,7 +2391,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2346 | struct rt6_info *rt; | 2391 | struct rt6_info *rt; |
2347 | struct sk_buff *skb; | 2392 | struct sk_buff *skb; |
2348 | struct rtmsg *rtm; | 2393 | struct rtmsg *rtm; |
2349 | struct flowi fl; | 2394 | struct flowi6 fl6; |
2350 | int err, iif = 0; | 2395 | int err, iif = 0; |
2351 | 2396 | ||
2352 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); | 2397 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
@@ -2354,27 +2399,27 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2354 | goto errout; | 2399 | goto errout; |
2355 | 2400 | ||
2356 | err = -EINVAL; | 2401 | err = -EINVAL; |
2357 | memset(&fl, 0, sizeof(fl)); | 2402 | memset(&fl6, 0, sizeof(fl6)); |
2358 | 2403 | ||
2359 | if (tb[RTA_SRC]) { | 2404 | if (tb[RTA_SRC]) { |
2360 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) | 2405 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) |
2361 | goto errout; | 2406 | goto errout; |
2362 | 2407 | ||
2363 | ipv6_addr_copy(&fl.fl6_src, nla_data(tb[RTA_SRC])); | 2408 | ipv6_addr_copy(&fl6.saddr, nla_data(tb[RTA_SRC])); |
2364 | } | 2409 | } |
2365 | 2410 | ||
2366 | if (tb[RTA_DST]) { | 2411 | if (tb[RTA_DST]) { |
2367 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) | 2412 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) |
2368 | goto errout; | 2413 | goto errout; |
2369 | 2414 | ||
2370 | ipv6_addr_copy(&fl.fl6_dst, nla_data(tb[RTA_DST])); | 2415 | ipv6_addr_copy(&fl6.daddr, nla_data(tb[RTA_DST])); |
2371 | } | 2416 | } |
2372 | 2417 | ||
2373 | if (tb[RTA_IIF]) | 2418 | if (tb[RTA_IIF]) |
2374 | iif = nla_get_u32(tb[RTA_IIF]); | 2419 | iif = nla_get_u32(tb[RTA_IIF]); |
2375 | 2420 | ||
2376 | if (tb[RTA_OIF]) | 2421 | if (tb[RTA_OIF]) |
2377 | fl.oif = nla_get_u32(tb[RTA_OIF]); | 2422 | fl6.flowi6_oif = nla_get_u32(tb[RTA_OIF]); |
2378 | 2423 | ||
2379 | if (iif) { | 2424 | if (iif) { |
2380 | struct net_device *dev; | 2425 | struct net_device *dev; |
@@ -2397,10 +2442,10 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2397 | skb_reset_mac_header(skb); | 2442 | skb_reset_mac_header(skb); |
2398 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | 2443 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); |
2399 | 2444 | ||
2400 | rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); | 2445 | rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl6); |
2401 | skb_dst_set(skb, &rt->dst); | 2446 | skb_dst_set(skb, &rt->dst); |
2402 | 2447 | ||
2403 | err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, | 2448 | err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, |
2404 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2449 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, |
2405 | nlh->nlmsg_seq, 0, 0, 0); | 2450 | nlh->nlmsg_seq, 0, 0, 0); |
2406 | if (err < 0) { | 2451 | if (err < 0) { |
@@ -2557,14 +2602,16 @@ static | |||
2557 | int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, | 2602 | int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, |
2558 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2603 | void __user *buffer, size_t *lenp, loff_t *ppos) |
2559 | { | 2604 | { |
2560 | struct net *net = current->nsproxy->net_ns; | 2605 | struct net *net; |
2561 | int delay = net->ipv6.sysctl.flush_delay; | 2606 | int delay; |
2562 | if (write) { | 2607 | 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; | 2608 | return -EINVAL; |
2609 | |||
2610 | net = (struct net *)ctl->extra1; | ||
2611 | delay = net->ipv6.sysctl.flush_delay; | ||
2612 | proc_dointvec(ctl, write, buffer, lenp, ppos); | ||
2613 | fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); | ||
2614 | return 0; | ||
2568 | } | 2615 | } |
2569 | 2616 | ||
2570 | ctl_table ipv6_route_table_template[] = { | 2617 | ctl_table ipv6_route_table_template[] = { |
@@ -2651,6 +2698,7 @@ struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) | |||
2651 | 2698 | ||
2652 | if (table) { | 2699 | if (table) { |
2653 | table[0].data = &net->ipv6.sysctl.flush_delay; | 2700 | table[0].data = &net->ipv6.sysctl.flush_delay; |
2701 | table[0].extra1 = net; | ||
2654 | table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh; | 2702 | table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh; |
2655 | table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; | 2703 | table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; |
2656 | table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; | 2704 | table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; |
@@ -2684,7 +2732,8 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2684 | net->ipv6.ip6_null_entry->dst.path = | 2732 | net->ipv6.ip6_null_entry->dst.path = |
2685 | (struct dst_entry *)net->ipv6.ip6_null_entry; | 2733 | (struct dst_entry *)net->ipv6.ip6_null_entry; |
2686 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2734 | 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); | 2735 | dst_init_metrics(&net->ipv6.ip6_null_entry->dst, |
2736 | ip6_template_metrics, true); | ||
2688 | 2737 | ||
2689 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 2738 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
2690 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, | 2739 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, |
@@ -2695,7 +2744,8 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2695 | net->ipv6.ip6_prohibit_entry->dst.path = | 2744 | net->ipv6.ip6_prohibit_entry->dst.path = |
2696 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; | 2745 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; |
2697 | net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2746 | 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); | 2747 | dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst, |
2748 | ip6_template_metrics, true); | ||
2699 | 2749 | ||
2700 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, | 2750 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, |
2701 | sizeof(*net->ipv6.ip6_blk_hole_entry), | 2751 | sizeof(*net->ipv6.ip6_blk_hole_entry), |
@@ -2705,7 +2755,8 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2705 | net->ipv6.ip6_blk_hole_entry->dst.path = | 2755 | net->ipv6.ip6_blk_hole_entry->dst.path = |
2706 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; | 2756 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; |
2707 | net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2757 | 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); | 2758 | dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, |
2759 | ip6_template_metrics, true); | ||
2709 | #endif | 2760 | #endif |
2710 | 2761 | ||
2711 | net->ipv6.sysctl.flush_delay = 0; | 2762 | net->ipv6.sysctl.flush_delay = 0; |