forked from mirrors/linux
		
	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
					
				
					 16 changed files with 40 additions and 47 deletions
				
			
		| 
						 | 
					@ -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 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
 | 
				
			||||||
 * 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);
 | 
				
			||||||
 | 
					#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;
 | 
							int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (; tp; tp = rcu_dereference_bh(tp->next)) {
 | 
					 | 
				
			||||||
		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;
 | 
					 | 
				
			||||||
reclassify:
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = tc_classify_compat(skb, tp, res);
 | 
					 | 
				
			||||||
#ifdef CONFIG_NET_CLS_ACT
 | 
					 | 
				
			||||||
	if (err == TC_ACT_RECLASSIFY) {
 | 
					 | 
				
			||||||
		tp = otp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (unlikely(limit++ >= MAX_REC_LOOP)) {
 | 
						if (unlikely(limit++ >= MAX_REC_LOOP)) {
 | 
				
			||||||
			net_notice_ratelimited("%s: packet reclassify loop rule prio %u protocol %02x\n",
 | 
							net_notice_ratelimited("%s: reclassify loop, rule prio %u, "
 | 
				
			||||||
					       tp->q->ops->id,
 | 
									       "protocol %02x\n", tp->q->ops->id,
 | 
				
			||||||
					       tp->prio & 0xffff,
 | 
									       tp->prio & 0xffff, ntohs(tp->protocol));
 | 
				
			||||||
					       ntohs(tp->protocol));
 | 
					 | 
				
			||||||
		return TC_ACT_SHOT;
 | 
							return TC_ACT_SHOT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tp = old_tp;
 | 
				
			||||||
	goto reclassify;
 | 
						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 a new issue