Commit f697c3e8 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[NET]: Avoid unnecessary cloning for ingress filtering



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: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 776c729e
Loading
Loading
Loading
Loading
+40 −28
Original line number Diff line number Diff line
@@ -1949,17 +1949,16 @@ 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);
		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_AT(skb->tc_verd, AT_INGRESS);

	spin_lock(&dev->ingress_lock);
@@ -1967,9 +1966,34 @@ static int ing_filter(struct sk_buff *skb)
		result = q->enqueue(skb, q);
	spin_unlock(&dev->ingress_lock);

	return result;
}

	return result;
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);
	}

	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