Commit 95a7233c authored by Paul Blakey's avatar Paul Blakey Committed by David S. Miller
Browse files

net: openvswitch: Set OvS recirc_id from tc chain index



Offloaded OvS datapath rules are translated one to one to tc rules,
for example the following simplified OvS rule:

recirc_id(0),in_port(dev1),eth_type(0x0800),ct_state(-trk) actions:ct(),recirc(2)

Will be translated to the following tc rule:

$ tc filter add dev dev1 ingress \
	    prio 1 chain 0 proto ip \
		flower tcp ct_state -trk \
		action ct pipe \
		action goto chain 2

Received packets will first travel though tc, and if they aren't stolen
by it, like in the above rule, they will continue to OvS datapath.
Since we already did some actions (action ct in this case) which might
modify the packets, and updated action stats, we would like to continue
the proccessing with the correct recirc_id in OvS (here recirc_id(2))
where we left off.

To support this, introduce a new skb extension for tc, which
will be used for translating tc chain to ovs recirc_id to
handle these miss cases. Last tc chain index will be set
by tc goto chain action and read by OvS datapath.

Signed-off-by: default avatarPaul Blakey <paulb@mellanox.com>
Signed-off-by: default avatarVlad Buslov <vladbu@mellanox.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Acked-by: default avatarPravin B Shelar <pshelar@ovn.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 47e25277
Loading
Loading
Loading
Loading
+13 −0
Original line number Original line Diff line number Diff line
@@ -279,6 +279,16 @@ struct nf_bridge_info {
};
};
#endif
#endif


#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
/* Chain in tc_skb_ext will be used to share the tc chain with
 * ovs recirc_id. It will be set to the current chain by tc
 * and read by ovs to recirc_id.
 */
struct tc_skb_ext {
	__u32 chain;
};
#endif

struct sk_buff_head {
struct sk_buff_head {
	/* These two members must be first. */
	/* These two members must be first. */
	struct sk_buff	*next;
	struct sk_buff	*next;
@@ -4057,6 +4067,9 @@ enum skb_ext_id {
#endif
#endif
#ifdef CONFIG_XFRM
#ifdef CONFIG_XFRM
	SKB_EXT_SEC_PATH,
	SKB_EXT_SEC_PATH,
#endif
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
	TC_SKB_EXT,
#endif
#endif
	SKB_EXT_NUM, /* must be last */
	SKB_EXT_NUM, /* must be last */
};
};
+3 −0
Original line number Original line Diff line number Diff line
@@ -123,6 +123,9 @@ struct ovs_vport_stats {
/* Allow datapath to associate multiple Netlink PIDs to each vport */
/* Allow datapath to associate multiple Netlink PIDs to each vport */
#define OVS_DP_F_VPORT_PIDS	(1 << 1)
#define OVS_DP_F_VPORT_PIDS	(1 << 1)


/* Allow tc offload recirc sharing */
#define OVS_DP_F_TC_RECIRC_SHARING	(1 << 2)

/* Fixed logical ports. */
/* Fixed logical ports. */
#define OVSP_LOCAL      ((__u32)0)
#define OVSP_LOCAL      ((__u32)0)


+6 −0
Original line number Original line Diff line number Diff line
@@ -4087,6 +4087,9 @@ static const u8 skb_ext_type_len[] = {
#ifdef CONFIG_XFRM
#ifdef CONFIG_XFRM
	[SKB_EXT_SEC_PATH] = SKB_EXT_CHUNKSIZEOF(struct sec_path),
	[SKB_EXT_SEC_PATH] = SKB_EXT_CHUNKSIZEOF(struct sec_path),
#endif
#endif
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
	[TC_SKB_EXT] = SKB_EXT_CHUNKSIZEOF(struct tc_skb_ext),
#endif
};
};


static __always_inline unsigned int skb_ext_total_length(void)
static __always_inline unsigned int skb_ext_total_length(void)
@@ -4097,6 +4100,9 @@ static __always_inline unsigned int skb_ext_total_length(void)
#endif
#endif
#ifdef CONFIG_XFRM
#ifdef CONFIG_XFRM
		skb_ext_type_len[SKB_EXT_SEC_PATH] +
		skb_ext_type_len[SKB_EXT_SEC_PATH] +
#endif
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
		skb_ext_type_len[TC_SKB_EXT] +
#endif
#endif
		0;
		0;
}
}
+33 −5
Original line number Original line Diff line number Diff line
@@ -1545,10 +1545,34 @@ static void ovs_dp_reset_user_features(struct sk_buff *skb, struct genl_info *in
	dp->user_features = 0;
	dp->user_features = 0;
}
}


static void ovs_dp_change(struct datapath *dp, struct nlattr *a[])
DEFINE_STATIC_KEY_FALSE(tc_recirc_sharing_support);

static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
{
{
	if (a[OVS_DP_ATTR_USER_FEATURES])
	u32 user_features = 0;
		dp->user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);

	if (a[OVS_DP_ATTR_USER_FEATURES]) {
		user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);

		if (user_features & ~(OVS_DP_F_VPORT_PIDS |
				      OVS_DP_F_UNALIGNED |
				      OVS_DP_F_TC_RECIRC_SHARING))
			return -EOPNOTSUPP;

#if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
		if (user_features & OVS_DP_F_TC_RECIRC_SHARING)
			return -EOPNOTSUPP;
#endif
	}

	dp->user_features = user_features;

	if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING)
		static_branch_enable(&tc_recirc_sharing_support);
	else
		static_branch_disable(&tc_recirc_sharing_support);

	return 0;
}
}


static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
@@ -1610,7 +1634,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
	parms.port_no = OVSP_LOCAL;
	parms.port_no = OVSP_LOCAL;
	parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
	parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];


	ovs_dp_change(dp, a);
	err = ovs_dp_change(dp, a);
	if (err)
		goto err_destroy_meters;


	/* So far only local changes have been made, now need the lock. */
	/* So far only local changes have been made, now need the lock. */
	ovs_lock();
	ovs_lock();
@@ -1736,7 +1762,9 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
	if (IS_ERR(dp))
	if (IS_ERR(dp))
		goto err_unlock_free;
		goto err_unlock_free;


	ovs_dp_change(dp, info->attrs);
	err = ovs_dp_change(dp, info->attrs);
	if (err)
		goto err_unlock_free;


	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
				   info->snd_seq, 0, OVS_DP_CMD_SET);
				   info->snd_seq, 0, OVS_DP_CMD_SET);
+2 −0
Original line number Original line Diff line number Diff line
@@ -218,6 +218,8 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
extern struct notifier_block ovs_dp_device_notifier;
extern struct notifier_block ovs_dp_device_notifier;
extern struct genl_family dp_vport_genl_family;
extern struct genl_family dp_vport_genl_family;


DECLARE_STATIC_KEY_FALSE(tc_recirc_sharing_support);

void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key);
void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key);
void ovs_dp_detach_port(struct vport *);
void ovs_dp_detach_port(struct vport *);
int ovs_dp_upcall(struct datapath *, struct sk_buff *,
int ovs_dp_upcall(struct datapath *, struct sk_buff *,
Loading