net: sched: use counter to break reclassify loops
authorFlorian Westphal <fw@strlen.de>
Mon, 11 May 2015 17:50:41 +0000 (19:50 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 13 May 2015 19:08:14 +0000 (15:08 -0400)
Seems all we want here is to avoid endless 'goto reclassify' loop.
tc_classify_compat even resets this counter when something other
than TC_ACT_RECLASSIFY is returned, so this skb-counter doesn't
break hypothetical loops induced by something other than perpetual
TC_ACT_RECLASSIFY return values.

skb_act_clone is now identical to skb_clone, so just use that.

Tested with following (bogus) filter:
tc filter add dev eth0 parent ffff: \
 protocol ip u32 match u32 0 0 police rate 10Kbit burst \
 64000 mtu 1500 action reclassify

Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/networking/tc-actions-env-rules.txt
include/net/sch_generic.h
include/uapi/linux/pkt_cls.h
net/sched/act_mirred.c
net/sched/sch_api.c

index 95c7171..f378146 100644 (file)
@@ -8,10 +8,6 @@ For example if your action queues a packet to be processed later,
 or intentionally branches by redirecting a packet, then you need to
 clone the packet.
 
-There are certain fields in the skb tc_verd that need to be reset so we
-avoid loops, etc.  A few are generic enough that skb_act_clone()
-resets them for you, so invoke skb_act_clone() rather than skb_clone().
-
 2) If you munge any packet thou shalt call pskb_expand_head in the case
 someone else is referencing the skb. After that you "own" the skb.
 
index 1b0a2e8..2738f6f 100644 (file)
@@ -739,21 +739,6 @@ static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen)
        return rtab->data[slot];
 }
 
-#ifdef CONFIG_NET_CLS_ACT
-static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask,
-                                           int action)
-{
-       struct sk_buff *n;
-
-       n = skb_clone(skb, gfp_mask);
-
-       if (n) {
-               n->tc_verd = SET_TC_VERD(n->tc_verd, 0);
-       }
-       return n;
-}
-#endif
-
 struct psched_ratecfg {
        u64     rate_bytes_ps; /* bytes per second */
        u32     mult;
index 596ffa0..ffc112c 100644 (file)
@@ -44,13 +44,13 @@ bits 9,10,11: redirect counter -  redirect TTL. Loop avoidance
 #define TC_OK2MUNGE        _TC_MAKEMASK1(1)
 #define SET_TC_OK2MUNGE(v)   ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE))
 #define CLR_TC_OK2MUNGE(v)   ( v & ~TC_OK2MUNGE)
-#endif
 
 #define S_TC_VERD          _TC_MAKE32(2)
 #define M_TC_VERD          _TC_MAKEMASK(4,S_TC_VERD)
 #define G_TC_VERD(x)       _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD)
 #define V_TC_VERD(x)       _TC_MAKEVALUE(x,S_TC_VERD)
 #define SET_TC_VERD(v,n)   ((V_TC_VERD(n)) | (v & ~M_TC_VERD))
+#endif
 
 #define S_TC_FROM          _TC_MAKE32(6)
 #define M_TC_FROM          _TC_MAKEMASK(2,S_TC_FROM)
index 3f63cea..a42a3b2 100644 (file)
@@ -151,7 +151,7 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
        }
 
        at = G_TC_AT(skb->tc_verd);
-       skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action);
+       skb2 = skb_clone(skb, GFP_ATOMIC);
        if (skb2 == NULL)
                goto out;
 
index ad9eed7..0b74dc0 100644 (file)
@@ -1816,13 +1816,8 @@ int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp,
                        continue;
                err = tp->classify(skb, tp, res);
 
-               if (err >= 0) {
-#ifdef CONFIG_NET_CLS_ACT
-                       if (err != TC_ACT_RECLASSIFY && skb->tc_verd)
-                               skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0);
-#endif
+               if (err >= 0)
                        return err;
-               }
        }
        return -1;
 }
@@ -1834,23 +1829,22 @@ int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
        int err = 0;
 #ifdef CONFIG_NET_CLS_ACT
        const struct tcf_proto *otp = tp;
+       int limit = 0;
 reclassify:
 #endif
 
        err = tc_classify_compat(skb, tp, res);
 #ifdef CONFIG_NET_CLS_ACT
        if (err == TC_ACT_RECLASSIFY) {
-               u32 verd = G_TC_VERD(skb->tc_verd);
                tp = otp;
 
-               if (verd++ >= MAX_REC_LOOP) {
+               if (unlikely(limit++ >= MAX_REC_LOOP)) {
                        net_notice_ratelimited("%s: packet reclassify loop rule prio %u protocol %02x\n",
                                               tp->q->ops->id,
                                               tp->prio & 0xffff,
                                               ntohs(tp->protocol));
                        return TC_ACT_SHOT;
                }
-               skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd);
                goto reclassify;
        }
 #endif