net: sched: consolidate tc_classify{,_compat}
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>
This commit is contained in:
parent
fe2188236a
commit
3b3ae88026
@ -110,10 +110,8 @@ static inline void qdisc_run(struct Qdisc *q)
|
|||||||
__qdisc_run(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,
|
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)
|
static inline __be16 tc_skb_protocol(const struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS);
|
||||||
qdisc_bstats_cpu_update(cl->q, skb);
|
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_OK:
|
||||||
case TC_ACT_RECLASSIFY:
|
case TC_ACT_RECLASSIFY:
|
||||||
skb->tc_index = TC_H_MIN(cl_res.classid);
|
skb->tc_index = TC_H_MIN(cl_res.classid);
|
||||||
|
@ -1806,51 +1806,46 @@ done:
|
|||||||
* to this qdisc, (optionally) tests for protocol and asks
|
* to this qdisc, (optionally) tests for protocol and asks
|
||||||
* specific classifiers.
|
* specific classifiers.
|
||||||
*/
|
*/
|
||||||
int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp,
|
int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
|
||||||
struct tcf_result *res)
|
struct tcf_result *res, bool compat_mode)
|
||||||
{
|
{
|
||||||
__be16 protocol = tc_skb_protocol(skb);
|
__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)) {
|
for (; tp; tp = rcu_dereference_bh(tp->next)) {
|
||||||
|
int err;
|
||||||
|
|
||||||
if (tp->protocol != protocol &&
|
if (tp->protocol != protocol &&
|
||||||
tp->protocol != htons(ETH_P_ALL))
|
tp->protocol != htons(ETH_P_ALL))
|
||||||
continue;
|
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)
|
if (err >= 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
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
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
const struct tcf_proto *otp = tp;
|
reset:
|
||||||
int limit = 0;
|
if (unlikely(limit++ >= MAX_REC_LOOP)) {
|
||||||
reclassify:
|
net_notice_ratelimited("%s: reclassify loop, rule prio %u, "
|
||||||
#endif
|
"protocol %02x\n", tp->q->ops->id,
|
||||||
|
tp->prio & 0xffff, ntohs(tp->protocol));
|
||||||
err = tc_classify_compat(skb, tp, res);
|
return TC_ACT_SHOT;
|
||||||
#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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tp = old_tp;
|
||||||
|
goto reclassify;
|
||||||
#endif
|
#endif
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tc_classify);
|
EXPORT_SYMBOL(tc_classify);
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
|||||||
list_for_each_entry(flow, &p->flows, list) {
|
list_for_each_entry(flow, &p->flows, list) {
|
||||||
fl = rcu_dereference_bh(flow->filter_list);
|
fl = rcu_dereference_bh(flow->filter_list);
|
||||||
if (fl) {
|
if (fl) {
|
||||||
result = tc_classify_compat(skb, fl, &res);
|
result = tc_classify(skb, fl, &res, true);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
continue;
|
continue;
|
||||||
flow = (struct atm_flow_data *)res.class;
|
flow = (struct atm_flow_data *)res.class;
|
||||||
|
@ -240,7 +240,7 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
|
|||||||
/*
|
/*
|
||||||
* Step 2+n. Apply classifier.
|
* Step 2+n. Apply classifier.
|
||||||
*/
|
*/
|
||||||
result = tc_classify_compat(skb, fl, &res);
|
result = tc_classify(skb, fl, &res, true);
|
||||||
if (!fl || result < 0)
|
if (!fl || result < 0)
|
||||||
goto fallback;
|
goto fallback;
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ static bool choke_classify(struct sk_buff *skb,
|
|||||||
int result;
|
int result;
|
||||||
|
|
||||||
fl = rcu_dereference_bh(q->filter_list);
|
fl = rcu_dereference_bh(q->filter_list);
|
||||||
result = tc_classify(skb, fl, &res);
|
result = tc_classify(skb, fl, &res, false);
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
#ifdef CONFIG_NET_CLS_ACT
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -331,7 +331,7 @@ static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch,
|
|||||||
|
|
||||||
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
||||||
fl = rcu_dereference_bh(q->filter_list);
|
fl = rcu_dereference_bh(q->filter_list);
|
||||||
result = tc_classify(skb, fl, &res);
|
result = tc_classify(skb, fl, &res, false);
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
#ifdef CONFIG_NET_CLS_ACT
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -230,7 +230,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
|||||||
else {
|
else {
|
||||||
struct tcf_result res;
|
struct tcf_result res;
|
||||||
struct tcf_proto *fl = rcu_dereference_bh(p->filter_list);
|
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);
|
pr_debug("result %d class 0x%04x\n", result, res.classid);
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch,
|
|||||||
return fq_codel_hash(q, skb) + 1;
|
return fq_codel_hash(q, skb) + 1;
|
||||||
|
|
||||||
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
||||||
result = tc_classify(skb, filter, &res);
|
result = tc_classify(skb, filter, &res, false);
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
#ifdef CONFIG_NET_CLS_ACT
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -1165,7 +1165,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
|
|||||||
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
||||||
head = &q->root;
|
head = &q->root;
|
||||||
tcf = rcu_dereference_bh(q->root.filter_list);
|
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
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case TC_ACT_QUEUED:
|
case TC_ACT_QUEUED:
|
||||||
|
@ -229,7 +229,7 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
*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
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case TC_ACT_QUEUED:
|
case TC_ACT_QUEUED:
|
||||||
|
@ -46,7 +46,7 @@ multiq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
*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
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case TC_ACT_STOLEN:
|
case TC_ACT_STOLEN:
|
||||||
|
@ -42,7 +42,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
|
|||||||
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
||||||
if (TC_H_MAJ(skb->priority) != sch->handle) {
|
if (TC_H_MAJ(skb->priority) != sch->handle) {
|
||||||
fl = rcu_dereference_bh(q->filter_list);
|
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
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case TC_ACT_STOLEN:
|
case TC_ACT_STOLEN:
|
||||||
|
@ -717,7 +717,7 @@ static struct qfq_class *qfq_classify(struct sk_buff *skb, struct Qdisc *sch,
|
|||||||
|
|
||||||
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
||||||
fl = rcu_dereference_bh(q->filter_list);
|
fl = rcu_dereference_bh(q->filter_list);
|
||||||
result = tc_classify(skb, fl, &res);
|
result = tc_classify(skb, fl, &res, false);
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
#ifdef CONFIG_NET_CLS_ACT
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -258,7 +258,7 @@ static bool sfb_classify(struct sk_buff *skb, struct tcf_proto *fl,
|
|||||||
struct tcf_result res;
|
struct tcf_result res;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = tc_classify(skb, fl, &res);
|
result = tc_classify(skb, fl, &res, false);
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
#ifdef CONFIG_NET_CLS_ACT
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -179,7 +179,7 @@ static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
|
|||||||
return sfq_hash(q, skb) + 1;
|
return sfq_hash(q, skb) + 1;
|
||||||
|
|
||||||
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
||||||
result = tc_classify(skb, fl, &res);
|
result = tc_classify(skb, fl, &res, false);
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
#ifdef CONFIG_NET_CLS_ACT
|
#ifdef CONFIG_NET_CLS_ACT
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
Loading…
Reference in New Issue
Block a user