aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c77
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
666static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, 666static 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
684restart: 684restart:
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
738static 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
738void ip6_route_input(struct sk_buff *skb) 744void 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)
761static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, 767static 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
773relookup:
774 read_lock_bh(&table->tb6_lock);
775
776restart_2:
777 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
778
779restart:
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
819out:
820 if (reachable) {
821 reachable = 0;
822 goto restart_2;
823 }
824 dst_hold(&rt->u.dst);
825 read_unlock_bh(&table->tb6_lock);
826out2:
827 rt->u.dst.lastuse = jiffies;
828 rt->u.dst.__use++;
829 return rt;
830} 771}
831 772
832struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) 773struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)