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

Commit b27d6a95 authored by John Hurley's avatar John Hurley Committed by David S. Miller
Browse files

nfp: compile flower vxlan tunnel set actions



Compile set tunnel actions for tc flower. Only support VXLAN and ensure a
tunnel destination port of 4789 is used.

Signed-off-by: default avatarJohn Hurley <john.hurley@netronome.com>
Signed-off-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 611aec10
Loading
Loading
Loading
Loading
+152 −17
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <net/tc_act/tc_gact.h>
#include <net/tc_act/tc_mirred.h>
#include <net/tc_act/tc_vlan.h>
#include <net/tc_act/tc_tunnel_key.h>

#include "cmsg.h"
#include "main.h"
@@ -80,14 +81,27 @@ nfp_fl_push_vlan(struct nfp_fl_push_vlan *push_vlan,
	push_vlan->vlan_tci = cpu_to_be16(tmp_push_vlan_tci);
}

static bool nfp_fl_netdev_is_tunnel_type(struct net_device *out_dev,
					 enum nfp_flower_tun_type tun_type)
{
	if (!out_dev->rtnl_link_ops)
		return false;

	if (!strcmp(out_dev->rtnl_link_ops->kind, "vxlan"))
		return tun_type == NFP_FL_TUNNEL_VXLAN;

	return false;
}

static int
nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action,
	      struct nfp_fl_payload *nfp_flow, bool last,
	      struct net_device *in_dev)
	      struct net_device *in_dev, enum nfp_flower_tun_type tun_type,
	      int *tun_out_cnt)
{
	size_t act_size = sizeof(struct nfp_fl_output);
	u16 tmp_output_op, tmp_flags;
	struct net_device *out_dev;
	u16 tmp_output_op;
	int ifindex;

	/* Set action opcode to output action. */
@@ -97,16 +111,31 @@ nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action,

	output->a_op = cpu_to_be16(tmp_output_op);

	/* Set action output parameters. */
	output->flags = cpu_to_be16(last ? NFP_FL_OUT_FLAGS_LAST : 0);

	ifindex = tcf_mirred_ifindex(action);
	out_dev = __dev_get_by_index(dev_net(in_dev), ifindex);
	if (!out_dev)
		return -EOPNOTSUPP;

	/* Only offload egress ports are on the same device as the ingress
	 * port.
	tmp_flags = last ? NFP_FL_OUT_FLAGS_LAST : 0;

	if (tun_type) {
		/* Verify the egress netdev matches the tunnel type. */
		if (!nfp_fl_netdev_is_tunnel_type(out_dev, tun_type))
			return -EOPNOTSUPP;

		if (*tun_out_cnt)
			return -EOPNOTSUPP;
		(*tun_out_cnt)++;

		output->flags = cpu_to_be16(tmp_flags |
					    NFP_FL_OUT_FLAGS_USE_TUN);
		output->port = cpu_to_be32(NFP_FL_PORT_TYPE_TUN | tun_type);
	} else {
		/* Set action output parameters. */
		output->flags = cpu_to_be16(tmp_flags);

		/* Only offload if egress ports are on the same device as the
		 * ingress port.
		 */
		if (!switchdev_port_same_parent_id(in_dev, out_dev))
			return -EOPNOTSUPP;
@@ -114,17 +143,94 @@ nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action,
		output->port = cpu_to_be32(nfp_repr_get_port_id(out_dev));
		if (!output->port)
			return -EOPNOTSUPP;

	}
	nfp_flow->meta.shortcut = output->port;

	return 0;
}

static bool nfp_fl_supported_tun_port(const struct tc_action *action)
{
	struct ip_tunnel_info *tun = tcf_tunnel_info(action);

	return tun->key.tp_dst == htons(NFP_FL_VXLAN_PORT);
}

static struct nfp_fl_pre_tunnel *nfp_fl_pre_tunnel(char *act_data, int act_len)
{
	size_t act_size = sizeof(struct nfp_fl_pre_tunnel);
	struct nfp_fl_pre_tunnel *pre_tun_act;
	u16 tmp_pre_tun_op;

	/* Pre_tunnel action must be first on action list.
	 * If other actions already exist they need pushed forward.
	 */
	if (act_len)
		memmove(act_data + act_size, act_data, act_len);

	pre_tun_act = (struct nfp_fl_pre_tunnel *)act_data;

	memset(pre_tun_act, 0, act_size);

	tmp_pre_tun_op =
		FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) |
		FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_PRE_TUNNEL);

	pre_tun_act->a_op = cpu_to_be16(tmp_pre_tun_op);

	return pre_tun_act;
}

static int
nfp_fl_set_vxlan(struct nfp_fl_set_vxlan *set_vxlan,
		 const struct tc_action *action,
		 struct nfp_fl_pre_tunnel *pre_tun)
{
	struct ip_tunnel_info *vxlan = tcf_tunnel_info(action);
	size_t act_size = sizeof(struct nfp_fl_set_vxlan);
	u32 tmp_set_vxlan_type_index = 0;
	u16 tmp_set_vxlan_op;
	/* Currently support one pre-tunnel so index is always 0. */
	int pretun_idx = 0;

	if (vxlan->options_len) {
		/* Do not support options e.g. vxlan gpe. */
		return -EOPNOTSUPP;
	}

	tmp_set_vxlan_op =
		FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) |
		FIELD_PREP(NFP_FL_ACT_JMP_ID,
			   NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL);

	set_vxlan->a_op = cpu_to_be16(tmp_set_vxlan_op);

	/* Set tunnel type and pre-tunnel index. */
	tmp_set_vxlan_type_index |=
		FIELD_PREP(NFP_FL_IPV4_TUNNEL_TYPE, NFP_FL_TUNNEL_VXLAN) |
		FIELD_PREP(NFP_FL_IPV4_PRE_TUN_INDEX, pretun_idx);

	set_vxlan->tun_type_index = cpu_to_be32(tmp_set_vxlan_type_index);

	set_vxlan->tun_id = vxlan->key.tun_id;
	set_vxlan->tun_flags = vxlan->key.tun_flags;
	set_vxlan->ipv4_ttl = vxlan->key.ttl;
	set_vxlan->ipv4_tos = vxlan->key.tos;

	/* Complete pre_tunnel action. */
	pre_tun->ipv4_dst = vxlan->key.u.ipv4.dst;

	return 0;
}

static int
nfp_flower_loop_action(const struct tc_action *a,
		       struct nfp_fl_payload *nfp_fl, int *a_len,
		       struct net_device *netdev)
		       struct net_device *netdev,
		       enum nfp_flower_tun_type *tun_type, int *tun_out_cnt)
{
	struct nfp_fl_pre_tunnel *pre_tun;
	struct nfp_fl_set_vxlan *s_vxl;
	struct nfp_fl_push_vlan *psh_v;
	struct nfp_fl_pop_vlan *pop_v;
	struct nfp_fl_output *output;
@@ -137,7 +243,8 @@ nfp_flower_loop_action(const struct tc_action *a,
			return -EOPNOTSUPP;

		output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len];
		err = nfp_fl_output(output, a, nfp_fl, true, netdev);
		err = nfp_fl_output(output, a, nfp_fl, true, netdev, *tun_type,
				    tun_out_cnt);
		if (err)
			return err;

@@ -147,7 +254,8 @@ nfp_flower_loop_action(const struct tc_action *a,
			return -EOPNOTSUPP;

		output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len];
		err = nfp_fl_output(output, a, nfp_fl, false, netdev);
		err = nfp_fl_output(output, a, nfp_fl, false, netdev, *tun_type,
				    tun_out_cnt);
		if (err)
			return err;

@@ -170,6 +278,29 @@ nfp_flower_loop_action(const struct tc_action *a,

		nfp_fl_push_vlan(psh_v, a);
		*a_len += sizeof(struct nfp_fl_push_vlan);
	} else if (is_tcf_tunnel_set(a) && nfp_fl_supported_tun_port(a)) {
		/* Pre-tunnel action is required for tunnel encap.
		 * This checks for next hop entries on NFP.
		 * If none, the packet falls back before applying other actions.
		 */
		if (*a_len + sizeof(struct nfp_fl_pre_tunnel) +
		    sizeof(struct nfp_fl_set_vxlan) > NFP_FL_MAX_A_SIZ)
			return -EOPNOTSUPP;

		*tun_type = NFP_FL_TUNNEL_VXLAN;
		pre_tun = nfp_fl_pre_tunnel(nfp_fl->action_data, *a_len);
		nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
		*a_len += sizeof(struct nfp_fl_pre_tunnel);

		s_vxl = (struct nfp_fl_set_vxlan *)&nfp_fl->action_data[*a_len];
		err = nfp_fl_set_vxlan(s_vxl, a, pre_tun);
		if (err)
			return err;

		*a_len += sizeof(struct nfp_fl_set_vxlan);
	} else if (is_tcf_tunnel_release(a)) {
		/* Tunnel decap is handled by default so accept action. */
		return 0;
	} else {
		/* Currently we do not handle any other actions. */
		return -EOPNOTSUPP;
@@ -182,18 +313,22 @@ int nfp_flower_compile_action(struct tc_cls_flower_offload *flow,
			      struct net_device *netdev,
			      struct nfp_fl_payload *nfp_flow)
{
	int act_len, act_cnt, err;
	int act_len, act_cnt, err, tun_out_cnt;
	enum nfp_flower_tun_type tun_type;
	const struct tc_action *a;
	LIST_HEAD(actions);

	memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ);
	nfp_flow->meta.act_len = 0;
	tun_type = NFP_FL_TUNNEL_NONE;
	act_len = 0;
	act_cnt = 0;
	tun_out_cnt = 0;

	tcf_exts_to_list(flow->exts, &actions);
	list_for_each_entry(a, &actions, list) {
		err = nfp_flower_loop_action(a, nfp_flow, &act_len, netdev);
		err = nfp_flower_loop_action(a, nfp_flow, &act_len, netdev,
					     &tun_type, &tun_out_cnt);
		if (err)
			return err;
		act_cnt++;
+27 −4
Original line number Diff line number Diff line
@@ -70,6 +70,8 @@
#define NFP_FL_ACTION_OPCODE_OUTPUT		0
#define NFP_FL_ACTION_OPCODE_PUSH_VLAN		1
#define NFP_FL_ACTION_OPCODE_POP_VLAN		2
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL	6
#define NFP_FL_ACTION_OPCODE_PRE_TUNNEL		17
#define NFP_FL_ACTION_OPCODE_NUM		32

#define NFP_FL_ACT_JMP_ID		GENMASK(15, 8)
@@ -85,6 +87,8 @@

/* Tunnel ports */
#define NFP_FL_PORT_TYPE_TUN		0x50000000
#define NFP_FL_IPV4_TUNNEL_TYPE		GENMASK(7, 4)
#define NFP_FL_IPV4_PRE_TUN_INDEX	GENMASK(2, 0)

enum nfp_flower_tun_type {
	NFP_FL_TUNNEL_NONE =	0,
@@ -123,6 +127,25 @@ struct nfp_flower_meta_one {
	u16 reserved;
};

struct nfp_fl_pre_tunnel {
	__be16 a_op;
	__be16 reserved;
	__be32 ipv4_dst;
	/* reserved for use with IPv6 addresses */
	__be32 extra[3];
};

struct nfp_fl_set_vxlan {
	__be16 a_op;
	__be16 reserved;
	__be64 tun_id;
	__be32 tun_type_index;
	__be16 tun_flags;
	u8 ipv4_ttl;
	u8 ipv4_tos;
	__be32 extra[2];
} __packed;

/* Metadata with L2 (1W/4B)
 * ----------------------------------------------------------------
 *    3                   2                   1