[NET]: Avoid unnecessary cloning for ingress filtering
authorHerbert Xu <herbert@gondor.apana.org.au>
Sun, 14 Oct 2007 07:38:47 +0000 (00:38 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 15 Oct 2007 19:26:26 +0000 (12:26 -0700)
As it is we always invoke pt_prev before ing_filter, even if there are no
ingress filters attached.  This can cause unnecessary cloning in pt_prev.

This patch changes it so that we only invoke pt_prev if there are ingress
filters attached.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/dev.c

index 99b7bda..39aba48 100644 (file)
@@ -1949,27 +1949,51 @@ static int ing_filter(struct sk_buff *skb)
        struct Qdisc *q;
        struct net_device *dev = skb->dev;
        int result = TC_ACT_OK;
+       u32 ttl = G_TC_RTTL(skb->tc_verd);
 
-       if (dev->qdisc_ingress) {
-               __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd);
-               if (MAX_RED_LOOP < ttl++) {
-                       printk(KERN_WARNING "Redir loop detected Dropping packet (%d->%d)\n",
-                               skb->iif, skb->dev->ifindex);
-                       return TC_ACT_SHOT;
-               }
+       if (MAX_RED_LOOP < ttl++) {
+               printk(KERN_WARNING
+                      "Redir loop detected Dropping packet (%d->%d)\n",
+                      skb->iif, dev->ifindex);
+               return TC_ACT_SHOT;
+       }
 
-               skb->tc_verd = SET_TC_RTTL(skb->tc_verd,ttl);
+       skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl);
+       skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS);
 
-               skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
+       spin_lock(&dev->ingress_lock);
+       if ((q = dev->qdisc_ingress) != NULL)
+               result = q->enqueue(skb, q);
+       spin_unlock(&dev->ingress_lock);
+
+       return result;
+}
 
-               spin_lock(&dev->ingress_lock);
-               if ((q = dev->qdisc_ingress) != NULL)
-                       result = q->enqueue(skb, q);
-               spin_unlock(&dev->ingress_lock);
+static inline struct sk_buff *handle_ing(struct sk_buff *skb,
+                                        struct packet_type **pt_prev,
+                                        int *ret, struct net_device *orig_dev)
+{
+       if (!skb->dev->qdisc_ingress)
+               goto out;
 
+       if (*pt_prev) {
+               *ret = deliver_skb(skb, *pt_prev, orig_dev);
+               *pt_prev = NULL;
+       } else {
+               /* Huh? Why does turning on AF_PACKET affect this? */
+               skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
        }
 
-       return result;
+       switch (ing_filter(skb)) {
+       case TC_ACT_SHOT:
+       case TC_ACT_STOLEN:
+               kfree_skb(skb);
+               return NULL;
+       }
+
+out:
+       skb->tc_verd = 0;
+       return skb;
 }
 #endif
 
@@ -2021,21 +2045,9 @@ int netif_receive_skb(struct sk_buff *skb)
        }
 
 #ifdef CONFIG_NET_CLS_ACT
-       if (pt_prev) {
-               ret = deliver_skb(skb, pt_prev, orig_dev);
-               pt_prev = NULL; /* noone else should process this after*/
-       } else {
-               skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
-       }
-
-       ret = ing_filter(skb);
-
-       if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) {
-               kfree_skb(skb);
+       skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
+       if (!skb)
                goto out;
-       }
-
-       skb->tc_verd = 0;
 ncls:
 #endif