Skip to content

Commit e5cf1ba

Browse files
Paolo Abenidavem330
authored andcommitted
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 <[email protected]> Acked-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent cd11b16 commit e5cf1ba

File tree

1 file changed

+43
-10
lines changed

1 file changed

+43
-10
lines changed

net/sched/act_mirred.c

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <net/net_namespace.h>
2626
#include <net/netlink.h>
2727
#include <net/pkt_sched.h>
28+
#include <net/pkt_cls.h>
2829
#include <linux/tc_act/tc_mirred.h>
2930
#include <net/tc_act/tc_mirred.h>
3031

@@ -49,6 +50,18 @@ static bool tcf_mirred_act_wants_ingress(int action)
4950
}
5051
}
5152

53+
static bool tcf_mirred_can_reinsert(int action)
54+
{
55+
switch (action) {
56+
case TC_ACT_SHOT:
57+
case TC_ACT_STOLEN:
58+
case TC_ACT_QUEUED:
59+
case TC_ACT_TRAP:
60+
return true;
61+
}
62+
return false;
63+
}
64+
5265
static void tcf_mirred_release(struct tc_action *a)
5366
{
5467
struct tcf_mirred *m = to_mirred(a);
@@ -171,10 +184,13 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
171184
struct tcf_result *res)
172185
{
173186
struct tcf_mirred *m = to_mirred(a);
187+
struct sk_buff *skb2 = skb;
174188
bool m_mac_header_xmit;
175189
struct net_device *dev;
176-
struct sk_buff *skb2;
177190
int retval, err = 0;
191+
bool use_reinsert;
192+
bool want_ingress;
193+
bool is_redirect;
178194
int m_eaction;
179195
int mac_len;
180196

@@ -196,16 +212,25 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
196212
goto out;
197213
}
198214

199-
skb2 = skb_clone(skb, GFP_ATOMIC);
200-
if (!skb2)
201-
goto out;
215+
/* we could easily avoid the clone only if called by ingress and clsact;
216+
* since we can't easily detect the clsact caller, skip clone only for
217+
* ingress - that covers the TC S/W datapath.
218+
*/
219+
is_redirect = tcf_mirred_is_act_redirect(m_eaction);
220+
use_reinsert = skb_at_tc_ingress(skb) && is_redirect &&
221+
tcf_mirred_can_reinsert(retval);
222+
if (!use_reinsert) {
223+
skb2 = skb_clone(skb, GFP_ATOMIC);
224+
if (!skb2)
225+
goto out;
226+
}
202227

203228
/* If action's target direction differs than filter's direction,
204229
* and devices expect a mac header on xmit, then mac push/pull is
205230
* needed.
206231
*/
207-
if (skb_at_tc_ingress(skb) != tcf_mirred_act_wants_ingress(m_eaction) &&
208-
m_mac_header_xmit) {
232+
want_ingress = tcf_mirred_act_wants_ingress(m_eaction);
233+
if (skb_at_tc_ingress(skb) != want_ingress && m_mac_header_xmit) {
209234
if (!skb_at_tc_ingress(skb)) {
210235
/* caught at egress, act ingress: pull mac */
211236
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,
216241
}
217242
}
218243

244+
skb2->skb_iif = skb->dev->ifindex;
245+
skb2->dev = dev;
246+
219247
/* mirror is always swallowed */
220-
if (tcf_mirred_is_act_redirect(m_eaction)) {
248+
if (is_redirect) {
221249
skb2->tc_redirected = 1;
222250
skb2->tc_from_ingress = skb2->tc_at_ingress;
251+
252+
/* let's the caller reinsert the packet, if possible */
253+
if (use_reinsert) {
254+
res->ingress = want_ingress;
255+
res->qstats = this_cpu_ptr(m->common.cpu_qstats);
256+
return TC_ACT_REINSERT;
257+
}
223258
}
224259

225-
skb2->skb_iif = skb->dev->ifindex;
226-
skb2->dev = dev;
227-
if (!tcf_mirred_act_wants_ingress(m_eaction))
260+
if (!want_ingress)
228261
err = dev_queue_xmit(skb2);
229262
else
230263
err = netif_receive_skb(skb2);

0 commit comments

Comments
 (0)