forked from mirrors/linux
		
	act_mirred: use TC_ACT_REINSERT when possible
When mirred is invoked from the ingress path, and it wants to redirect the processed packet, it can now use the TC_ACT_REINSERT action, filling the tcf_result accordingly, and avoiding a per packet skb_clone(). Overall this gives a ~10% improvement in forwarding performance for the TC S/W data path and TC S/W performances are now comparable to the kernel openvswitch datapath. v1 -> v2: use ACT_MIRRED instead of ACT_REDIRECT v2 -> v3: updated after action rename, fixed typo into the commit message v3 -> v4: updated again after action rename, added more comments to the code (JiriP), skip the optimization if the control action need to touch the tcf_result (Paolo) v4 -> v5: fix sparse warning (kbuild bot) Signed-off-by: Paolo Abeni <pabeni@redhat.com> Acked-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									cd11b16407
								
							
						
					
					
						commit
						e5cf1baf92
					
				
					 1 changed files with 46 additions and 13 deletions
				
			
		|  | @ -25,6 +25,7 @@ | ||||||
| #include <net/net_namespace.h> | #include <net/net_namespace.h> | ||||||
| #include <net/netlink.h> | #include <net/netlink.h> | ||||||
| #include <net/pkt_sched.h> | #include <net/pkt_sched.h> | ||||||
|  | #include <net/pkt_cls.h> | ||||||
| #include <linux/tc_act/tc_mirred.h> | #include <linux/tc_act/tc_mirred.h> | ||||||
| #include <net/tc_act/tc_mirred.h> | #include <net/tc_act/tc_mirred.h> | ||||||
| 
 | 
 | ||||||
|  | @ -49,6 +50,18 @@ static bool tcf_mirred_act_wants_ingress(int action) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool tcf_mirred_can_reinsert(int action) | ||||||
|  | { | ||||||
|  | 	switch (action) { | ||||||
|  | 	case TC_ACT_SHOT: | ||||||
|  | 	case TC_ACT_STOLEN: | ||||||
|  | 	case TC_ACT_QUEUED: | ||||||
|  | 	case TC_ACT_TRAP: | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void tcf_mirred_release(struct tc_action *a) | static void tcf_mirred_release(struct tc_action *a) | ||||||
| { | { | ||||||
| 	struct tcf_mirred *m = to_mirred(a); | 	struct tcf_mirred *m = to_mirred(a); | ||||||
|  | @ -171,10 +184,13 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, | ||||||
| 		      struct tcf_result *res) | 		      struct tcf_result *res) | ||||||
| { | { | ||||||
| 	struct tcf_mirred *m = to_mirred(a); | 	struct tcf_mirred *m = to_mirred(a); | ||||||
|  | 	struct sk_buff *skb2 = skb; | ||||||
| 	bool m_mac_header_xmit; | 	bool m_mac_header_xmit; | ||||||
| 	struct net_device *dev; | 	struct net_device *dev; | ||||||
| 	struct sk_buff *skb2; |  | ||||||
| 	int retval, err = 0; | 	int retval, err = 0; | ||||||
|  | 	bool use_reinsert; | ||||||
|  | 	bool want_ingress; | ||||||
|  | 	bool is_redirect; | ||||||
| 	int m_eaction; | 	int m_eaction; | ||||||
| 	int mac_len; | 	int mac_len; | ||||||
| 
 | 
 | ||||||
|  | @ -196,16 +212,25 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	skb2 = skb_clone(skb, GFP_ATOMIC); | 	/* we could easily avoid the clone only if called by ingress and clsact;
 | ||||||
| 	if (!skb2) | 	 * since we can't easily detect the clsact caller, skip clone only for | ||||||
| 		goto out; | 	 * ingress - that covers the TC S/W datapath. | ||||||
|  | 	 */ | ||||||
|  | 	is_redirect = tcf_mirred_is_act_redirect(m_eaction); | ||||||
|  | 	use_reinsert = skb_at_tc_ingress(skb) && is_redirect && | ||||||
|  | 		       tcf_mirred_can_reinsert(retval); | ||||||
|  | 	if (!use_reinsert) { | ||||||
|  | 		skb2 = skb_clone(skb, GFP_ATOMIC); | ||||||
|  | 		if (!skb2) | ||||||
|  | 			goto out; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* If action's target direction differs than filter's direction,
 | 	/* If action's target direction differs than filter's direction,
 | ||||||
| 	 * and devices expect a mac header on xmit, then mac push/pull is | 	 * and devices expect a mac header on xmit, then mac push/pull is | ||||||
| 	 * needed. | 	 * needed. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (skb_at_tc_ingress(skb) != tcf_mirred_act_wants_ingress(m_eaction) && | 	want_ingress = tcf_mirred_act_wants_ingress(m_eaction); | ||||||
| 	    m_mac_header_xmit) { | 	if (skb_at_tc_ingress(skb) != want_ingress && m_mac_header_xmit) { | ||||||
| 		if (!skb_at_tc_ingress(skb)) { | 		if (!skb_at_tc_ingress(skb)) { | ||||||
| 			/* caught at egress, act ingress: pull mac */ | 			/* caught at egress, act ingress: pull mac */ | ||||||
| 			mac_len = skb_network_header(skb) - skb_mac_header(skb); | 			mac_len = skb_network_header(skb) - skb_mac_header(skb); | ||||||
|  | @ -216,15 +241,23 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* mirror is always swallowed */ |  | ||||||
| 	if (tcf_mirred_is_act_redirect(m_eaction)) { |  | ||||||
| 		skb2->tc_redirected = 1; |  | ||||||
| 		skb2->tc_from_ingress = skb2->tc_at_ingress; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	skb2->skb_iif = skb->dev->ifindex; | 	skb2->skb_iif = skb->dev->ifindex; | ||||||
| 	skb2->dev = dev; | 	skb2->dev = dev; | ||||||
| 	if (!tcf_mirred_act_wants_ingress(m_eaction)) | 
 | ||||||
|  | 	/* mirror is always swallowed */ | ||||||
|  | 	if (is_redirect) { | ||||||
|  | 		skb2->tc_redirected = 1; | ||||||
|  | 		skb2->tc_from_ingress = skb2->tc_at_ingress; | ||||||
|  | 
 | ||||||
|  | 		/* let's the caller reinsert the packet, if possible */ | ||||||
|  | 		if (use_reinsert) { | ||||||
|  | 			res->ingress = want_ingress; | ||||||
|  | 			res->qstats = this_cpu_ptr(m->common.cpu_qstats); | ||||||
|  | 			return TC_ACT_REINSERT; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!want_ingress) | ||||||
| 		err = dev_queue_xmit(skb2); | 		err = dev_queue_xmit(skb2); | ||||||
| 	else | 	else | ||||||
| 		err = netif_receive_skb(skb2); | 		err = netif_receive_skb(skb2); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Paolo Abeni
						Paolo Abeni