Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f3f6500 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'TC-refactor-act_mirred-packets-re-injection'



Paolo Abeni says:

====================
TC: refactor act_mirred packets re-injection

This series is aimed at improving the act_mirred redirect performances.
Such action is used by OVS to represent TC S/W flows, and it's current largest
bottle-neck is the need for a skb_clone() for each packet.

The first 2 patches introduce some cleanup and safeguards to allow extending
tca_result - we will use it to store RCU protected redirect information - and
introduce a clear separation between user-space accessible tcfa_action
values and internal values accessible only by the kernel.
Then a new tcfa_action value is introduced: TC_ACT_REINJECT, similar to
TC_ACT_REDIRECT, but preserving the mirred semantic. Such value is not
accessible from user-space.
The last patch exploits the newly introduced infrastructure in the act_mirred
action, to avoid a skb_clone, when possible.

Overall this the above gives a ~10% performance improvement in forwarding tput,
when using the TC S/W datapath.

v1 -> v2:
 - preserve the rcu lock in act_bpf
 - add and use a new action value to reinject the packets, preserving the mirred
   semantic

v2 -> v3:
 - renamed to new action as TC_ACT_REINJECT
 - TC_ACT_REINJECT is not exposed to user-space

v3 -> v4:
 - dropped the TC_ACT_REDIRECT patch
 - report failure via extack, too
 - rename the new action as TC_ACT_REINSERT
 - skip clone only if the control action don't touch tcf_result

v4 -> v5:
 - fix a couple of build issue reported by kbuild bot
 - dont split messages
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c87fffc5 e5cf1baf
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ struct tc_action_ops {
	size_t	size;
	struct module		*owner;
	int     (*act)(struct sk_buff *, const struct tc_action *,
		       struct tcf_result *);
		       struct tcf_result *); /* called under RCU BH lock*/
	int     (*dump)(struct sk_buff *, struct tc_action *, int, int);
	void	(*cleanup)(struct tc_action *);
	int     (*lookup)(struct net *net, struct tc_action **a, u32 index,
+3 −0
Original line number Diff line number Diff line
@@ -7,6 +7,9 @@
#include <net/sch_generic.h>
#include <net/act_api.h>

/* TC action not accessible from user space */
#define TC_ACT_REINSERT		(TC_ACT_VALUE_MAX + 1)

/* Basic packet classifier frontend definitions. */

struct tcf_walker {
+30 −0
Original line number Diff line number Diff line
@@ -235,6 +235,12 @@ struct tcf_result {
			u32		classid;
		};
		const struct tcf_proto *goto_tp;

		/* used by the TC_ACT_REINSERT action */
		struct {
			bool		ingress;
			struct gnet_stats_queue *qstats;
		};
	};
};

@@ -285,6 +291,8 @@ struct tcf_proto {
	/* Fast access part */
	struct tcf_proto __rcu	*next;
	void __rcu		*root;

	/* called under RCU BH lock*/
	int			(*classify)(struct sk_buff *,
					    const struct tcf_proto *,
					    struct tcf_result *);
@@ -567,6 +575,15 @@ static inline void skb_reset_tc(struct sk_buff *skb)
#endif
}

static inline bool skb_is_tc_redirected(const struct sk_buff *skb)
{
#ifdef CONFIG_NET_CLS_ACT
	return skb->tc_redirected;
#else
	return false;
#endif
}

static inline bool skb_at_tc_ingress(const struct sk_buff *skb)
{
#ifdef CONFIG_NET_CLS_ACT
@@ -1106,4 +1123,17 @@ void mini_qdisc_pair_swap(struct mini_Qdisc_pair *miniqp,
void mini_qdisc_pair_init(struct mini_Qdisc_pair *miniqp, struct Qdisc *qdisc,
			  struct mini_Qdisc __rcu **p_miniq);

static inline void skb_tc_reinsert(struct sk_buff *skb, struct tcf_result *res)
{
	struct gnet_stats_queue *stats = res->qstats;
	int ret;

	if (res->ingress)
		ret = netif_receive_skb(skb);
	else
		ret = dev_queue_xmit(skb);
	if (ret && stats)
		qstats_overlimit_inc(res->qstats);
}

#endif
+4 −2
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ enum {
				   * the skb and act like everything
				   * is alright.
				   */
#define TC_ACT_VALUE_MAX	TC_ACT_TRAP

/* There is a special kind of actions called "extended actions",
 * which need a value parameter. These have a local opcode located in
@@ -55,11 +56,12 @@ enum {
#define __TC_ACT_EXT_SHIFT 28
#define __TC_ACT_EXT(local) ((local) << __TC_ACT_EXT_SHIFT)
#define TC_ACT_EXT_VAL_MASK ((1 << __TC_ACT_EXT_SHIFT) - 1)
#define TC_ACT_EXT_CMP(combined, opcode) \
	(((combined) & (~TC_ACT_EXT_VAL_MASK)) == opcode)
#define TC_ACT_EXT_OPCODE(combined) ((combined) & (~TC_ACT_EXT_VAL_MASK))
#define TC_ACT_EXT_CMP(combined, opcode) (TC_ACT_EXT_OPCODE(combined) == opcode)

#define TC_ACT_JUMP __TC_ACT_EXT(1)
#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2)
#define TC_ACT_EXT_OPCODE_MAX	TC_ACT_GOTO_CHAIN

/* Action type identifiers*/
enum {
+5 −1
Original line number Diff line number Diff line
@@ -4252,7 +4252,7 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
	/* Reinjected packets coming from act_mirred or similar should
	 * not get XDP generic processing.
	 */
	if (skb_cloned(skb))
	if (skb_cloned(skb) || skb_is_tc_redirected(skb))
		return XDP_PASS;

	/* XDP packets must be linear and must have sufficient headroom
@@ -4602,6 +4602,10 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
		__skb_push(skb, skb->mac_len);
		skb_do_redirect(skb);
		return NULL;
	case TC_ACT_REINSERT:
		/* this does not scrub the packet, and updates stats on error */
		skb_tc_reinsert(skb, &cl_res);
		return NULL;
	default:
		break;
	}
Loading