net: sched: consolidate tc_classify{,_compat}
authorDaniel Borkmann <daniel@iogearbox.net>
Wed, 26 Aug 2015 21:00:06 +0000 (23:00 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Aug 2015 21:18:48 +0000 (14:18 -0700)
For classifiers getting invoked via tc_classify(), we always need an
extra function call into tc_classify_compat(), as both are being
exported as symbols and tc_classify() itself doesn't do much except
handling of reclassifications when tp->classify() returned with
TC_ACT_RECLASSIFY.

CBQ and ATM are the only qdiscs that directly call into tc_classify_compat(),
all others use tc_classify(). When tc actions are being configured
out in the kernel, tc_classify() effectively does nothing besides
delegating.

We could spare this layer and consolidate both functions. pktgen on
single CPU constantly pushing skbs directly into the netif_receive_skb()
path with a dummy classifier on ingress qdisc attached, improves
slightly from 22.3Mpps to 23.1Mpps.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
16 files changed:
include/net/pkt_sched.h
net/core/dev.c
net/sched/sch_api.c
net/sched/sch_atm.c
net/sched/sch_cbq.c
net/sched/sch_choke.c
net/sched/sch_drr.c
net/sched/sch_dsmark.c
net/sched/sch_fq_codel.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c
net/sched/sch_multiq.c
net/sched/sch_prio.c
net/sched/sch_qfq.c
net/sched/sch_sfb.c
net/sched/sch_sfq.c

index 2342bf12cb78a07fb44cbd389fb548cf38801ec3..401038d2f9b88c536788507b6168675333d02fe0 100644 (file)
@@ -110,10 +110,8 @@ static inline void qdisc_run(struct Qdisc *q)
                __qdisc_run(q);
 }
 
-int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp,
-                      struct tcf_result *res);
 int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
-               struct tcf_result *res);
+               struct tcf_result *res, bool compat_mode);
 
 static inline __be16 tc_skb_protocol(const struct sk_buff *skb)
 {
index b1f3f4844e60c21248f97ef4c2a3c0b0dddc1bca..7bb24f1879b895b017ab312b6482e21419de07cc 100644 (file)
@@ -3657,7 +3657,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,
        skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS);
        qdisc_bstats_cpu_update(cl->q, skb);
 
-       switch (tc_classify(skb, cl, &cl_res)) {
+       switch (tc_classify(skb, cl, &cl_res, false)) {
        case TC_ACT_OK:
        case TC_ACT_RECLASSIFY:
                skb->tc_index = TC_H_MIN(cl_res.classid);
index f06aa01d60fd344bc853c9363dcff1dcec27fab3..59c227f26b56f84f7dce499d4f1dc73464b14b37 100644 (file)
@@ -1806,51 +1806,46 @@ done:
  * to this qdisc, (optionally) tests for protocol and asks
  * specific classifiers.
  */
-int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp,
-                      struct tcf_result *res)
+int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
+               struct tcf_result *res, bool compat_mode)
 {
        __be16 protocol = tc_skb_protocol(skb);
-       int err;
+#ifdef CONFIG_NET_CLS_ACT
+       const struct tcf_proto *old_tp = tp;
+       int limit = 0;
 
+reclassify:
+#endif
        for (; tp; tp = rcu_dereference_bh(tp->next)) {
+               int err;
+
                if (tp->protocol != protocol &&
                    tp->protocol != htons(ETH_P_ALL))
                        continue;
-               err = tp->classify(skb, tp, res);
 
+               err = tp->classify(skb, tp, res);
+#ifdef CONFIG_NET_CLS_ACT
+               if (unlikely(err == TC_ACT_RECLASSIFY &&
+                            !compat_mode))
+                       goto reset;
+#endif
                if (err >= 0)
                        return err;
        }
-       return -1;
-}
-EXPORT_SYMBOL(tc_classify_compat);
 
-int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
-               struct tcf_result *res)
-{
-       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);
+       return -1;
 #ifdef CONFIG_NET_CLS_ACT
-       if (err == TC_ACT_RECLASSIFY) {
-               tp = otp;
-
-               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;
-               }
-               goto reclassify;
+reset:
+       if (unlikely(limit++ >= MAX_REC_LOOP)) {
+               net_notice_ratelimited("%s: reclassify loop, rule prio %u, "
+                                      "protocol %02x\n", tp->q->ops->id,
+                                      tp->prio & 0xffff, ntohs(tp->protocol));
+               return TC_ACT_SHOT;
        }
+
+       tp = old_tp;
+       goto reclassify;
 #endif
-       return err;
 }
 EXPORT_SYMBOL(tc_classify);
 
index e3e2cc5fd0689e6ac5b6226ab7ca0987601ad733..1911af3ca7c0103b70c5be647cebcda65b5579fb 100644 (file)
@@ -375,7 +375,7 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                list_for_each_entry(flow, &p->flows, list) {
                        fl = rcu_dereference_bh(flow->filter_list);
                        if (fl) {
-                               result = tc_classify_compat(skb, fl, &res);
+                               result = tc_classify(skb, fl, &res, true);
                                if (result < 0)
                                        continue;
                                flow = (struct atm_flow_data *)res.class;
index beeb75f80fdb970139b030fbb9ac268983b617e9..c538d9e4a8f6c02b0f895fdb8de7951b41069be7 100644 (file)
@@ -240,7 +240,7 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
                /*
                 * Step 2+n. Apply classifier.
                 */
-               result = tc_classify_compat(skb, fl, &res);
+               result = tc_classify(skb, fl, &res, true);
                if (!fl || result < 0)
                        goto fallback;
 
index 6a783afe4960052912bf1241a22ab16d38d9e81a..665bde07916b833955a872fc2deff503f85226cf 100644 (file)
@@ -201,7 +201,7 @@ static bool choke_classify(struct sk_buff *skb,
        int result;
 
        fl = rcu_dereference_bh(q->filter_list);
-       result = tc_classify(skb, fl, &res);
+       result = tc_classify(skb, fl, &res, false);
        if (result >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
                switch (result) {
index 338706092c27d1255a5c16bb2cc4c5564f79e558..f26bdea875c1a8413774e767bb897012d969d2e6 100644 (file)
@@ -331,7 +331,7 @@ static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch,
 
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
        fl = rcu_dereference_bh(q->filter_list);
-       result = tc_classify(skb, fl, &res);
+       result = tc_classify(skb, fl, &res, false);
        if (result >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
                switch (result) {
index 66700a6116aa98332e4996366378a633b9da552a..c4d45fd8c551ef5b2c42910459b06c35667590ae 100644 (file)
@@ -230,7 +230,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        else {
                struct tcf_result res;
                struct tcf_proto *fl = rcu_dereference_bh(p->filter_list);
-               int result = tc_classify(skb, fl, &res);
+               int result = tc_classify(skb, fl, &res, false);
 
                pr_debug("result %d class 0x%04x\n", result, res.classid);
 
index a9ba030435a2a5c2ca4bea21d62c6d631c6168f4..4c834e93dafbe27bea51435113552819f7496d5b 100644 (file)
@@ -92,7 +92,7 @@ static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch,
                return fq_codel_hash(q, skb) + 1;
 
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
-       result = tc_classify(skb, filter, &res);
+       result = tc_classify(skb, filter, &res, false);
        if (result >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
                switch (result) {
index e6c7416d033219a66932bc8b2208a2046ffdd8eb..b7ebe2c87586416d615a13ce470bdfddf117a80d 100644 (file)
@@ -1165,7 +1165,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
        head = &q->root;
        tcf = rcu_dereference_bh(q->root.filter_list);
-       while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) {
+       while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
                switch (result) {
                case TC_ACT_QUEUED:
index cf4b0f865d1bc6a87873b54bb89cfe8e28f36ea6..15ccd7f8fb2ae35d940119e203259bb67e6e807d 100644 (file)
@@ -229,7 +229,7 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
        }
 
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
-       while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) {
+       while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
                switch (result) {
                case TC_ACT_QUEUED:
index 42dd218871e09a3d6cce471a41afecde8fdfdb05..4e904ca0af9d1630c4828a6316025c781daae38b 100644 (file)
@@ -46,7 +46,7 @@ multiq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
        int err;
 
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
-       err = tc_classify(skb, fl, &res);
+       err = tc_classify(skb, fl, &res, false);
 #ifdef CONFIG_NET_CLS_ACT
        switch (err) {
        case TC_ACT_STOLEN:
index 8e5cd34aaa74dbaddc4b38be4916bb79526e90fb..ba6487f2741f9fb20e55d39eeab4e7448b76cdac 100644 (file)
@@ -42,7 +42,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
        if (TC_H_MAJ(skb->priority) != sch->handle) {
                fl = rcu_dereference_bh(q->filter_list);
-               err = tc_classify(skb, fl, &res);
+               err = tc_classify(skb, fl, &res, false);
 #ifdef CONFIG_NET_CLS_ACT
                switch (err) {
                case TC_ACT_STOLEN:
index ffaeea63d47381c480a7c97e00c64c7a4eb6e80d..3dc3a6e560520a6f3b9b3bdf3bfa88277a08c266 100644 (file)
@@ -717,7 +717,7 @@ static struct qfq_class *qfq_classify(struct sk_buff *skb, struct Qdisc *sch,
 
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
        fl = rcu_dereference_bh(q->filter_list);
-       result = tc_classify(skb, fl, &res);
+       result = tc_classify(skb, fl, &res, false);
        if (result >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
                switch (result) {
index dcdff5c769a1c28e6ea476ce822c8fbe74f9fc53..5bbb6332ec5746dd1f33a04f4e22bcde5eb787c0 100644 (file)
@@ -258,7 +258,7 @@ static bool sfb_classify(struct sk_buff *skb, struct tcf_proto *fl,
        struct tcf_result res;
        int result;
 
-       result = tc_classify(skb, fl, &res);
+       result = tc_classify(skb, fl, &res, false);
        if (result >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
                switch (result) {
index 52f75a5473e120f8d0a02a2ff1c0215ff02437b5..3abab534eb5cd3646ea476b77433b10215602099 100644 (file)
@@ -179,7 +179,7 @@ static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
                return sfq_hash(q, skb) + 1;
 
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
-       result = tc_classify(skb, fl, &res);
+       result = tc_classify(skb, fl, &res, false);
        if (result >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
                switch (result) {