Commit 39a86d05 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-mlx5e-add-gbp-vxlan-hw-offload-support'

Gavin Li says:

====================
net/mlx5e: Add GBP VxLAN HW offload support

Patch-1: Remove unused argument from functions.
Patch-2: Expose helper function vxlan_build_gbp_hdr.
Patch-3: Add helper function for encap_info_equal for tunnels with options.
Patch-4: Preserving the const-ness of the pointer in ip_tunnel_info_opts.
Patch-5: Add HW offloading support for TC flows with VxLAN GBP encap/decap
        in mlx ethernet driver.
====================

Link: https://lore.kernel.org/r/20230316070758.83512-1-gavinl@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 36bd28c1 6ee44c51
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -115,6 +115,9 @@ int mlx5e_tc_tun_parse_udp_ports(struct mlx5e_priv *priv,
bool mlx5e_tc_tun_encap_info_equal_generic(struct mlx5e_encap_key *a,
					   struct mlx5e_encap_key *b);

bool mlx5e_tc_tun_encap_info_equal_options(struct mlx5e_encap_key *a,
					   struct mlx5e_encap_key *b,
					   __be16 tun_flags);
#endif /* CONFIG_MLX5_ESWITCH */

#endif //__MLX5_EN_TC_TUNNEL_H__
+32 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

#include <net/fib_notifier.h>
#include <net/nexthop.h>
#include <net/ip_tunnels.h>
#include "tc_tun_encap.h"
#include "en_tc.h"
#include "tc_tun.h"
@@ -571,6 +572,37 @@ bool mlx5e_tc_tun_encap_info_equal_generic(struct mlx5e_encap_key *a,
		a->tc_tunnel->tunnel_type == b->tc_tunnel->tunnel_type;
}

bool mlx5e_tc_tun_encap_info_equal_options(struct mlx5e_encap_key *a,
					   struct mlx5e_encap_key *b,
					   __be16 tun_flags)
{
	struct ip_tunnel_info *a_info;
	struct ip_tunnel_info *b_info;
	bool a_has_opts, b_has_opts;

	if (!mlx5e_tc_tun_encap_info_equal_generic(a, b))
		return false;

	a_has_opts = !!(a->ip_tun_key->tun_flags & tun_flags);
	b_has_opts = !!(b->ip_tun_key->tun_flags & tun_flags);

	/* keys are equal when both don't have any options attached */
	if (!a_has_opts && !b_has_opts)
		return true;

	if (a_has_opts != b_has_opts)
		return false;

	/* options stored in memory next to ip_tunnel_info struct */
	a_info = container_of(a->ip_tun_key, struct ip_tunnel_info, key);
	b_info = container_of(b->ip_tun_key, struct ip_tunnel_info, key);

	return a_info->options_len == b_info->options_len &&
	       !memcmp(ip_tunnel_info_opts(a_info),
		       ip_tunnel_info_opts(b_info),
		       a_info->options_len);
}

static int cmp_decap_info(struct mlx5e_decap_key *a,
			  struct mlx5e_decap_key *b)
{
+1 −23
Original line number Diff line number Diff line
@@ -337,29 +337,7 @@ static int mlx5e_tc_tun_parse_geneve(struct mlx5e_priv *priv,
static bool mlx5e_tc_tun_encap_info_equal_geneve(struct mlx5e_encap_key *a,
						 struct mlx5e_encap_key *b)
{
	struct ip_tunnel_info *a_info;
	struct ip_tunnel_info *b_info;
	bool a_has_opts, b_has_opts;

	if (!mlx5e_tc_tun_encap_info_equal_generic(a, b))
		return false;

	a_has_opts = !!(a->ip_tun_key->tun_flags & TUNNEL_GENEVE_OPT);
	b_has_opts = !!(b->ip_tun_key->tun_flags & TUNNEL_GENEVE_OPT);

	/* keys are equal when both don't have any options attached */
	if (!a_has_opts && !b_has_opts)
		return true;

	if (a_has_opts != b_has_opts)
		return false;

	/* geneve options stored in memory next to ip_tunnel_info struct */
	a_info = container_of(a->ip_tun_key, struct ip_tunnel_info, key);
	b_info = container_of(b->ip_tun_key, struct ip_tunnel_info, key);

	return a_info->options_len == b_info->options_len &&
		memcmp(a_info + 1, b_info + 1, a_info->options_len) == 0;
	return mlx5e_tc_tun_encap_info_equal_options(a, b, TUNNEL_GENEVE_OPT);
}

struct mlx5e_tc_tunnel geneve_tunnel = {
+70 −2
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2018 Mellanox Technologies. */

#include <net/ip_tunnels.h>
#include <net/vxlan.h>
#include "lib/vxlan.h"
#include "en/tc_tun.h"
@@ -86,9 +87,11 @@ static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[],
	const struct ip_tunnel_key *tun_key = &e->tun_info->key;
	__be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
	struct udphdr *udp = (struct udphdr *)(buf);
	const struct vxlan_metadata *md;
	struct vxlanhdr *vxh;

	if (tun_key->tun_flags & TUNNEL_VXLAN_OPT)
	if ((tun_key->tun_flags & TUNNEL_VXLAN_OPT) &&
	    e->tun_info->options_len != sizeof(*md))
		return -EOPNOTSUPP;
	vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
	*ip_proto = IPPROTO_UDP;
@@ -96,6 +99,57 @@ static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[],
	udp->dest = tun_key->tp_dst;
	vxh->vx_flags = VXLAN_HF_VNI;
	vxh->vx_vni = vxlan_vni_field(tun_id);
	if (tun_key->tun_flags & TUNNEL_VXLAN_OPT) {
		md = ip_tunnel_info_opts(e->tun_info);
		vxlan_build_gbp_hdr(vxh, md);
	}

	return 0;
}

static int mlx5e_tc_tun_parse_vxlan_gbp_option(struct mlx5e_priv *priv,
					       struct mlx5_flow_spec *spec,
					       struct flow_cls_offload *f)
{
	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
	struct netlink_ext_ack *extack = f->common.extack;
	struct flow_match_enc_opts enc_opts;
	void *misc5_c, *misc5_v;
	u32 *gbp, *gbp_mask;

	flow_rule_match_enc_opts(rule, &enc_opts);

	if (memchr_inv(&enc_opts.mask->data, 0, sizeof(enc_opts.mask->data)) &&
	    !MLX5_CAP_ESW_FT_FIELD_SUPPORT_2(priv->mdev, tunnel_header_0_1)) {
		NL_SET_ERR_MSG_MOD(extack, "Matching on VxLAN GBP is not supported");
		return -EOPNOTSUPP;
	}

	if (enc_opts.key->dst_opt_type != TUNNEL_VXLAN_OPT) {
		NL_SET_ERR_MSG_MOD(extack, "Wrong VxLAN option type: not GBP");
		return -EOPNOTSUPP;
	}

	if (enc_opts.key->len != sizeof(*gbp) ||
	    enc_opts.mask->len != sizeof(*gbp_mask)) {
		NL_SET_ERR_MSG_MOD(extack, "VxLAN GBP option/mask len is not 32 bits");
		return -EINVAL;
	}

	gbp = (u32 *)&enc_opts.key->data[0];
	gbp_mask = (u32 *)&enc_opts.mask->data[0];

	if (*gbp_mask & ~VXLAN_GBP_MASK) {
		NL_SET_ERR_MSG_FMT_MOD(extack, "Wrong VxLAN GBP mask(0x%08X)\n", *gbp_mask);
		return -EINVAL;
	}

	misc5_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_5);
	misc5_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_5);
	MLX5_SET(fte_match_set_misc5, misc5_c, tunnel_header_0, *gbp_mask);
	MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_0, *gbp);

	spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_5;

	return 0;
}
@@ -122,6 +176,14 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
	if (!enc_keyid.mask->keyid)
		return 0;

	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS)) {
		int err;

		err = mlx5e_tc_tun_parse_vxlan_gbp_option(priv, spec, f);
		if (err)
			return err;
	}

	/* match on VNI is required */

	if (!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev,
@@ -143,6 +205,12 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
	return 0;
}

static bool mlx5e_tc_tun_encap_info_equal_vxlan(struct mlx5e_encap_key *a,
						struct mlx5e_encap_key *b)
{
	return mlx5e_tc_tun_encap_info_equal_options(a, b, TUNNEL_VXLAN_OPT);
}

static int mlx5e_tc_tun_get_remote_ifindex(struct net_device *mirred_dev)
{
	const struct vxlan_dev *vxlan = netdev_priv(mirred_dev);
@@ -160,6 +228,6 @@ struct mlx5e_tc_tunnel vxlan_tunnel = {
	.generate_ip_tun_hdr  = mlx5e_gen_ip_tunnel_header_vxlan,
	.parse_udp_ports      = mlx5e_tc_tun_parse_udp_ports_vxlan,
	.parse_tunnel         = mlx5e_tc_tun_parse_vxlan,
	.encap_info_equal     = mlx5e_tc_tun_encap_info_equal_generic,
	.encap_info_equal     = mlx5e_tc_tun_encap_info_equal_vxlan,
	.get_remote_ifindex   = mlx5e_tc_tun_get_remote_ifindex,
};
+3 −24
Original line number Diff line number Diff line
@@ -2093,28 +2093,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
	return false;
}

static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags,
				struct vxlan_metadata *md)
{
	struct vxlanhdr_gbp *gbp;

	if (!md->gbp)
		return;

	gbp = (struct vxlanhdr_gbp *)vxh;
	vxh->vx_flags |= VXLAN_HF_GBP;

	if (md->gbp & VXLAN_GBP_DONT_LEARN)
		gbp->dont_learn = 1;

	if (md->gbp & VXLAN_GBP_POLICY_APPLIED)
		gbp->policy_applied = 1;

	gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK);
}

static int vxlan_build_gpe_hdr(struct vxlanhdr *vxh, u32 vxflags,
			       __be16 protocol)
static int vxlan_build_gpe_hdr(struct vxlanhdr *vxh, __be16 protocol)
{
	struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)vxh;

@@ -2177,9 +2156,9 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,
	}

	if (vxflags & VXLAN_F_GBP)
		vxlan_build_gbp_hdr(vxh, vxflags, md);
		vxlan_build_gbp_hdr(vxh, md);
	if (vxflags & VXLAN_F_GPE) {
		err = vxlan_build_gpe_hdr(vxh, vxflags, skb->protocol);
		err = vxlan_build_gpe_hdr(vxh, skb->protocol);
		if (err < 0)
			return err;
		inner_protocol = skb->protocol;
Loading