diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/route.c | 77 |
1 files changed, 9 insertions, 68 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6ff19f9eb9ee..cce9941c11c6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -663,7 +663,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d | |||
663 | return rt; | 663 | return rt; |
664 | } | 664 | } |
665 | 665 | ||
666 | static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, | 666 | static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif, |
667 | struct flowi *fl, int flags) | 667 | struct flowi *fl, int flags) |
668 | { | 668 | { |
669 | struct fib6_node *fn; | 669 | struct fib6_node *fn; |
@@ -682,7 +682,7 @@ restart_2: | |||
682 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 682 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
683 | 683 | ||
684 | restart: | 684 | restart: |
685 | rt = rt6_select(fn, fl->iif, strict | reachable); | 685 | rt = rt6_select(fn, oif, strict | reachable); |
686 | BACKTRACK(&fl->fl6_src); | 686 | BACKTRACK(&fl->fl6_src); |
687 | if (rt == &ip6_null_entry || | 687 | if (rt == &ip6_null_entry || |
688 | rt->rt6i_flags & RTF_CACHE) | 688 | rt->rt6i_flags & RTF_CACHE) |
@@ -735,6 +735,12 @@ out2: | |||
735 | return rt; | 735 | return rt; |
736 | } | 736 | } |
737 | 737 | ||
738 | static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, | ||
739 | struct flowi *fl, int flags) | ||
740 | { | ||
741 | return ip6_pol_route(table, fl->iif, fl, flags); | ||
742 | } | ||
743 | |||
738 | void ip6_route_input(struct sk_buff *skb) | 744 | void ip6_route_input(struct sk_buff *skb) |
739 | { | 745 | { |
740 | struct ipv6hdr *iph = ipv6_hdr(skb); | 746 | struct ipv6hdr *iph = ipv6_hdr(skb); |
@@ -761,72 +767,7 @@ void ip6_route_input(struct sk_buff *skb) | |||
761 | static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, | 767 | static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, |
762 | struct flowi *fl, int flags) | 768 | struct flowi *fl, int flags) |
763 | { | 769 | { |
764 | struct fib6_node *fn; | 770 | return ip6_pol_route(table, fl->oif, fl, flags); |
765 | struct rt6_info *rt, *nrt; | ||
766 | int strict = 0; | ||
767 | int attempts = 3; | ||
768 | int err; | ||
769 | int reachable = ipv6_devconf.forwarding ? 0 : RT6_LOOKUP_F_REACHABLE; | ||
770 | |||
771 | strict |= flags & RT6_LOOKUP_F_IFACE; | ||
772 | |||
773 | relookup: | ||
774 | read_lock_bh(&table->tb6_lock); | ||
775 | |||
776 | restart_2: | ||
777 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | ||
778 | |||
779 | restart: | ||
780 | rt = rt6_select(fn, fl->oif, strict | reachable); | ||
781 | BACKTRACK(&fl->fl6_src); | ||
782 | if (rt == &ip6_null_entry || | ||
783 | rt->rt6i_flags & RTF_CACHE) | ||
784 | goto out; | ||
785 | |||
786 | dst_hold(&rt->u.dst); | ||
787 | read_unlock_bh(&table->tb6_lock); | ||
788 | |||
789 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | ||
790 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); | ||
791 | else { | ||
792 | #if CLONE_OFFLINK_ROUTE | ||
793 | nrt = rt6_alloc_clone(rt, &fl->fl6_dst); | ||
794 | #else | ||
795 | goto out2; | ||
796 | #endif | ||
797 | } | ||
798 | |||
799 | dst_release(&rt->u.dst); | ||
800 | rt = nrt ? : &ip6_null_entry; | ||
801 | |||
802 | dst_hold(&rt->u.dst); | ||
803 | if (nrt) { | ||
804 | err = ip6_ins_rt(nrt); | ||
805 | if (!err) | ||
806 | goto out2; | ||
807 | } | ||
808 | |||
809 | if (--attempts <= 0) | ||
810 | goto out2; | ||
811 | |||
812 | /* | ||
813 | * Race condition! In the gap, when table->tb6_lock was | ||
814 | * released someone could insert this route. Relookup. | ||
815 | */ | ||
816 | dst_release(&rt->u.dst); | ||
817 | goto relookup; | ||
818 | |||
819 | out: | ||
820 | if (reachable) { | ||
821 | reachable = 0; | ||
822 | goto restart_2; | ||
823 | } | ||
824 | dst_hold(&rt->u.dst); | ||
825 | read_unlock_bh(&table->tb6_lock); | ||
826 | out2: | ||
827 | rt->u.dst.lastuse = jiffies; | ||
828 | rt->u.dst.__use++; | ||
829 | return rt; | ||
830 | } | 771 | } |
831 | 772 | ||
832 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | 773 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) |