]> err.no Git - linux-2.6/blobdiff - net/ipv4/route.c
[IPV6]: Don't redo xfrm_lookup for cached dst entries
[linux-2.6] / net / ipv4 / route.c
index 726ea5e8180a1275e58ebc919490f24516c37d14..8549f26e2495089c8987fd4c241b9ae002a74393 100644 (file)
@@ -240,7 +240,9 @@ static unsigned                     rt_hash_mask;
 static int                     rt_hash_log;
 static unsigned int            rt_hash_rnd;
 
-struct rt_cache_stat *rt_cache_stat;
+static struct rt_cache_stat *rt_cache_stat;
+#define RT_CACHE_STAT_INC(field)                                         \
+               (per_cpu_ptr(rt_cache_stat, raw_smp_processor_id())->field++)
 
 static int rt_intern_hash(unsigned hash, struct rtable *rth,
                                struct rtable **res);
@@ -1685,7 +1687,7 @@ static void ip_handle_martian_source(struct net_device *dev,
                printk(KERN_WARNING "martian source %u.%u.%u.%u from "
                        "%u.%u.%u.%u, on dev %s\n",
                        NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
-               if (dev->hard_header_len) {
+               if (dev->hard_header_len && skb->mac.raw) {
                        int i;
                        unsigned char *p = skb->mac.raw;
                        printk(KERN_WARNING "ll header: ");
@@ -1758,6 +1760,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
                goto cleanup;
        }
 
+       atomic_set(&rth->u.dst.__refcnt, 1);
        rth->u.dst.flags= DST_HOST;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
        if (res->fi->fib_nhs > 1)
@@ -1818,7 +1821,6 @@ static inline int ip_mkroute_input_def(struct sk_buff *skb,
        err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
        if (err)
                return err;
-       atomic_set(&rth->u.dst.__refcnt, 1);
 
        /* put it into the cache */
        hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
@@ -1832,8 +1834,8 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
                                   u32 daddr, u32 saddr, u32 tos)
 {
 #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
-       struct rtable* rth = NULL;
-       unsigned char hop, hopcount, lasthop;
+       struct rtable* rth = NULL, *rtres;
+       unsigned char hop, hopcount;
        int err = -EINVAL;
        unsigned int hash;
 
@@ -1842,8 +1844,6 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
        else
                hopcount = 1;
 
-       lasthop = hopcount - 1;
-
        /* distinguish between multipath and singlepath */
        if (hopcount < 2)
                return ip_mkroute_input_def(skb, res, fl, in_dev, daddr,
@@ -1853,6 +1853,10 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
        for (hop = 0; hop < hopcount; hop++) {
                res->nh_sel = hop;
 
+               /* put reference to previous result */
+               if (hop)
+                       ip_rt_put(rtres);
+
                /* create a routing cache entry */
                err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos,
                                      &rth);
@@ -1861,7 +1865,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
 
                /* put it into the cache */
                hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
-               err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+               err = rt_intern_hash(hash, rth, &rtres);
                if (err)
                        return err;
 
@@ -1871,13 +1875,8 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
                                     FIB_RES_NETMASK(*res),
                                     res->prefixlen,
                                     &FIB_RES_NH(*res));
-
-               /* only for the last hop the reference count is handled
-                * outside
-                */
-               if (hop == lasthop)
-                       atomic_set(&(skb->dst->__refcnt), 1);
        }
+       skb->dst = &rtres->u.dst;
        return err;
 #else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED  */
        return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos);
@@ -2206,6 +2205,7 @@ static inline int __mkroute_output(struct rtable **result,
                goto cleanup;
        }               
 
+       atomic_set(&rth->u.dst.__refcnt, 1);
        rth->u.dst.flags= DST_HOST;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
        if (res->fi) {
@@ -2288,8 +2288,6 @@ static inline int ip_mkroute_output_def(struct rtable **rp,
        if (err == 0) {
                u32 tos = RT_FL_TOS(oldflp);
 
-               atomic_set(&rth->u.dst.__refcnt, 1);
-               
                hash = rt_hash_code(oldflp->fl4_dst, 
                                    oldflp->fl4_src ^ (oldflp->oif << 5), tos);
                err = rt_intern_hash(hash, rth, rp);
@@ -2324,6 +2322,10 @@ static inline int ip_mkroute_output(struct rtable** rp,
                        dev2nexthop = FIB_RES_DEV(*res);
                        dev_hold(dev2nexthop);
 
+                       /* put reference to previous result */
+                       if (hop)
+                               ip_rt_put(*rp);
+
                        err = __mkroute_output(&rth, res, fl, oldflp,
                                               dev2nexthop, flags);
 
@@ -2348,7 +2350,6 @@ static inline int ip_mkroute_output(struct rtable** rp,
                        if (err != 0)
                                return err;
                }
-               atomic_set(&(*rp)->u.dst.__refcnt, 1);
                return err;
        } else {
                return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out,
@@ -2600,6 +2601,8 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
        return ip_route_output_slow(rp, flp);
 }
 
+EXPORT_SYMBOL_GPL(__ip_route_output_key);
+
 int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags)
 {
        int err;
@@ -2618,6 +2621,8 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk,
        return 0;
 }
 
+EXPORT_SYMBOL_GPL(ip_route_output_flow);
+
 int ip_route_output_key(struct rtable **rp, struct flowi *flp)
 {
        return ip_route_output_flow(rp, flp, NULL, 0);