]> Pileus Git - ~andy/linux/blobdiff - net/ipv6/route.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[~andy/linux] / net / ipv6 / route.c
index 7faa9d5e15033ae45715d63a33c21150e74f8665..11dac21e658690cdf01d7eb41c7e653d142ad9d4 100644 (file)
@@ -66,8 +66,9 @@
 #endif
 
 enum rt6_nud_state {
-       RT6_NUD_FAIL_HARD = -2,
-       RT6_NUD_FAIL_SOFT = -1,
+       RT6_NUD_FAIL_HARD = -3,
+       RT6_NUD_FAIL_PROBE = -2,
+       RT6_NUD_FAIL_DO_RR = -1,
        RT6_NUD_SUCCEED = 1
 };
 
@@ -84,6 +85,8 @@ static int             ip6_dst_gc(struct dst_ops *ops);
 
 static int             ip6_pkt_discard(struct sk_buff *skb);
 static int             ip6_pkt_discard_out(struct sk_buff *skb);
+static int             ip6_pkt_prohibit(struct sk_buff *skb);
+static int             ip6_pkt_prohibit_out(struct sk_buff *skb);
 static void            ip6_link_failure(struct sk_buff *skb);
 static void            ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
                                           struct sk_buff *skb, u32 mtu);
@@ -101,6 +104,36 @@ static struct rt6_info *rt6_get_route_info(struct net *net,
                                           const struct in6_addr *gwaddr, int ifindex);
 #endif
 
+static void rt6_bind_peer(struct rt6_info *rt, int create)
+{
+       struct inet_peer_base *base;
+       struct inet_peer *peer;
+
+       base = inetpeer_base_ptr(rt->_rt6i_peer);
+       if (!base)
+               return;
+
+       peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create);
+       if (peer) {
+               if (!rt6_set_peer(rt, peer))
+                       inet_putpeer(peer);
+       }
+}
+
+static struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create)
+{
+       if (rt6_has_peer(rt))
+               return rt6_peer_ptr(rt);
+
+       rt6_bind_peer(rt, create);
+       return (rt6_has_peer(rt) ? rt6_peer_ptr(rt) : NULL);
+}
+
+static struct inet_peer *rt6_get_peer_create(struct rt6_info *rt)
+{
+       return __rt6_get_peer(rt, 1);
+}
+
 static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
 {
        struct rt6_info *rt = (struct rt6_info *) dst;
@@ -234,9 +267,6 @@ static const struct rt6_info ip6_null_entry_template = {
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 
-static int ip6_pkt_prohibit(struct sk_buff *skb);
-static int ip6_pkt_prohibit_out(struct sk_buff *skb);
-
 static const struct rt6_info ip6_prohibit_entry_template = {
        .dst = {
                .__refcnt       = ATOMIC_INIT(1),
@@ -312,22 +342,6 @@ static void ip6_dst_destroy(struct dst_entry *dst)
        }
 }
 
-void rt6_bind_peer(struct rt6_info *rt, int create)
-{
-       struct inet_peer_base *base;
-       struct inet_peer *peer;
-
-       base = inetpeer_base_ptr(rt->_rt6i_peer);
-       if (!base)
-               return;
-
-       peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create);
-       if (peer) {
-               if (!rt6_set_peer(rt, peer))
-                       inet_putpeer(peer);
-       }
-}
-
 static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
                           int how)
 {
@@ -522,7 +536,7 @@ static void rt6_probe(struct rt6_info *rt)
                work = kmalloc(sizeof(*work), GFP_ATOMIC);
 
                if (neigh && work)
-                       neigh->updated = jiffies;
+                       __neigh_set_probe_once(neigh);
 
                if (neigh)
                        write_unlock(&neigh->lock);
@@ -578,11 +592,13 @@ static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
 #ifdef CONFIG_IPV6_ROUTER_PREF
                else if (!(neigh->nud_state & NUD_FAILED))
                        ret = RT6_NUD_SUCCEED;
+               else
+                       ret = RT6_NUD_FAIL_PROBE;
 #endif
                read_unlock(&neigh->lock);
        } else {
                ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
-                     RT6_NUD_SUCCEED : RT6_NUD_FAIL_SOFT;
+                     RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
        }
        rcu_read_unlock_bh();
 
@@ -619,16 +635,17 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
                goto out;
 
        m = rt6_score_route(rt, oif, strict);
-       if (m == RT6_NUD_FAIL_SOFT) {
+       if (m == RT6_NUD_FAIL_DO_RR) {
                match_do_rr = true;
                m = 0; /* lowest valid score */
-       } else if (m < 0) {
+       } else if (m == RT6_NUD_FAIL_HARD) {
                goto out;
        }
 
        if (strict & RT6_LOOKUP_F_REACHABLE)
                rt6_probe(rt);
 
+       /* note that m can be RT6_NUD_FAIL_PROBE at this point */
        if (m > *mpri) {
                *do_rr = match_do_rr;
                *mpri = m;
@@ -1565,21 +1582,24 @@ int ip6_route_add(struct fib6_config *cfg)
                                goto out;
                        }
                }
-               rt->dst.output = ip6_pkt_discard_out;
-               rt->dst.input = ip6_pkt_discard;
                rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
                switch (cfg->fc_type) {
                case RTN_BLACKHOLE:
                        rt->dst.error = -EINVAL;
+                       rt->dst.output = dst_discard;
+                       rt->dst.input = dst_discard;
                        break;
                case RTN_PROHIBIT:
                        rt->dst.error = -EACCES;
+                       rt->dst.output = ip6_pkt_prohibit_out;
+                       rt->dst.input = ip6_pkt_prohibit;
                        break;
                case RTN_THROW:
-                       rt->dst.error = -EAGAIN;
-                       break;
                default:
-                       rt->dst.error = -ENETUNREACH;
+                       rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
+                                       : -ENETUNREACH;
+                       rt->dst.output = ip6_pkt_discard_out;
+                       rt->dst.input = ip6_pkt_discard;
                        break;
                }
                goto install_route;
@@ -1903,9 +1923,7 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
                else
                        rt->rt6i_gateway = *dest;
                rt->rt6i_flags = ort->rt6i_flags;
-               if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ==
-                   (RTF_DEFAULT | RTF_ADDRCONF))
-                       rt6_set_from(rt, ort);
+               rt6_set_from(rt, ort);
                rt->rt6i_metric = 0;
 
 #ifdef CONFIG_IPV6_SUBTREES
@@ -2144,8 +2162,6 @@ static int ip6_pkt_discard_out(struct sk_buff *skb)
        return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
 }
 
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-
 static int ip6_pkt_prohibit(struct sk_buff *skb)
 {
        return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
@@ -2157,8 +2173,6 @@ static int ip6_pkt_prohibit_out(struct sk_buff *skb)
        return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
 }
 
-#endif
-
 /*
  *     Allocate a dst for local (unicast / anycast) address.
  */
@@ -2168,12 +2182,10 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
                                    bool anycast)
 {
        struct net *net = dev_net(idev->dev);
-       struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
-
-       if (!rt) {
-               net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
+       struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
+                                           DST_NOCOUNT, NULL);
+       if (!rt)
                return ERR_PTR(-ENOMEM);
-       }
 
        in6_dev_hold(idev);
 
@@ -2244,7 +2256,7 @@ void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
                .net = net,
                .addr = &ifp->addr,
        };
-       fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
+       fib6_clean_all(net, fib6_remove_prefsrc, &adni);
 }
 
 struct arg_dev_net {
@@ -2271,7 +2283,7 @@ void rt6_ifdown(struct net *net, struct net_device *dev)
                .net = net,
        };
 
-       fib6_clean_all(net, fib6_ifdown, 0, &adn);
+       fib6_clean_all(net, fib6_ifdown, &adn);
        icmp6_clean_all(fib6_ifdown, &adn);
 }
 
@@ -2326,7 +2338,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
                .mtu = mtu,
        };
 
-       fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg);
+       fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
 }
 
 static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {