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

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

nfp: compile flower vxlan tunnel metadata match fields



Compile ovs-tc flower vxlan metadata match fields for offloading. Only
support offload of tunnel data when the VXLAN port specifically matches
well known port 4789.

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 79ede4ae
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -83,6 +83,14 @@
#define NFP_FL_PUSH_VLAN_CFI		BIT(12)
#define NFP_FL_PUSH_VLAN_VID		GENMASK(11, 0)

/* Tunnel ports */
#define NFP_FL_PORT_TYPE_TUN		0x50000000

enum nfp_flower_tun_type {
	NFP_FL_TUNNEL_NONE =	0,
	NFP_FL_TUNNEL_VXLAN =	2,
};

struct nfp_fl_output {
	__be16 a_op;
	__be16 flags;
@@ -230,6 +238,36 @@ struct nfp_flower_ipv6 {
	struct in6_addr ipv6_dst;
};

/* Flow Frame VXLAN --> Tunnel details (4W/16B)
 * -----------------------------------------------------------------
 *    3                   2                   1
 *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                         ipv4_addr_src                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                         ipv4_addr_dst                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |           tun_flags           |       tos     |       ttl     |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |   gpe_flags   |            Reserved           | Next Protocol |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                     VNI                       |   Reserved    |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
struct nfp_flower_vxlan {
	__be32 ip_src;
	__be32 ip_dst;
	__be16 tun_flags;
	u8 tos;
	u8 ttl;
	u8 gpe_flags;
	u8 reserved[2];
	u8 nxt_proto;
	__be32 tun_id;
};

#define NFP_FL_TUN_VNI_OFFSET 8

/* The base header for a control message packet.
 * Defines an 8-bit version, and an 8-bit type, padded
 * to a 32-bit word. Rest of the packet is type-specific.
+2 −0
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@ struct nfp_app;
#define NFP_FL_MASK_REUSE_TIME_NS	40000
#define NFP_FL_MASK_ID_LOCATION		1

#define NFP_FL_VXLAN_PORT		4789

struct nfp_fl_mask_id {
	struct circ_buf mask_id_free_list;
	struct timespec64 *last_used;
+56 −4
Original line number Diff line number Diff line
@@ -77,13 +77,16 @@ nfp_flower_compile_meta(struct nfp_flower_meta_one *frame, u8 key_type)

static int
nfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port,
			bool mask_version)
			bool mask_version, enum nfp_flower_tun_type tun_type)
{
	if (mask_version) {
		frame->in_port = cpu_to_be32(~0);
		return 0;
	}

	if (tun_type)
		frame->in_port = cpu_to_be32(NFP_FL_PORT_TYPE_TUN | tun_type);
	else
		frame->in_port = cpu_to_be32(cmsg_port);

	return 0;
@@ -189,15 +192,53 @@ nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *frame,
	}
}

static void
nfp_flower_compile_vxlan(struct nfp_flower_vxlan *frame,
			 struct tc_cls_flower_offload *flow,
			 bool mask_version)
{
	struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
	struct flow_dissector_key_ipv4_addrs *vxlan_ips;
	struct flow_dissector_key_keyid *vni;

	/* Wildcard TOS/TTL/GPE_FLAGS/NXT_PROTO for now. */
	memset(frame, 0, sizeof(struct nfp_flower_vxlan));

	if (dissector_uses_key(flow->dissector,
			       FLOW_DISSECTOR_KEY_ENC_KEYID)) {
		u32 temp_vni;

		vni = skb_flow_dissector_target(flow->dissector,
						FLOW_DISSECTOR_KEY_ENC_KEYID,
						target);
		temp_vni = be32_to_cpu(vni->keyid) << NFP_FL_TUN_VNI_OFFSET;
		frame->tun_id = cpu_to_be32(temp_vni);
	}

	if (dissector_uses_key(flow->dissector,
			       FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
		vxlan_ips =
		   skb_flow_dissector_target(flow->dissector,
					     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
					     target);
		frame->ip_src = vxlan_ips->src;
		frame->ip_dst = vxlan_ips->dst;
	}
}

int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
				  struct nfp_fl_key_ls *key_ls,
				  struct net_device *netdev,
				  struct nfp_fl_payload *nfp_flow)
{
	enum nfp_flower_tun_type tun_type = NFP_FL_TUNNEL_NONE;
	int err;
	u8 *ext;
	u8 *msk;

	if (key_ls->key_layer & NFP_FLOWER_LAYER_VXLAN)
		tun_type = NFP_FL_TUNNEL_VXLAN;

	memset(nfp_flow->unmasked_data, 0, key_ls->key_size);
	memset(nfp_flow->mask_data, 0, key_ls->key_size);

@@ -216,14 +257,14 @@ int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
		/* Populate Exact Port data. */
		err = nfp_flower_compile_port((struct nfp_flower_in_port *)ext,
					      nfp_repr_get_port_id(netdev),
					      false);
					      false, tun_type);
		if (err)
			return err;

		/* Populate Mask Port Data. */
		err = nfp_flower_compile_port((struct nfp_flower_in_port *)msk,
					      nfp_repr_get_port_id(netdev),
					      true);
					      true, tun_type);
		if (err)
			return err;

@@ -291,5 +332,16 @@ int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
		msk += sizeof(struct nfp_flower_ipv6);
	}

	if (key_ls->key_layer & NFP_FLOWER_LAYER_VXLAN) {
		/* Populate Exact VXLAN Data. */
		nfp_flower_compile_vxlan((struct nfp_flower_vxlan *)ext,
					 flow, false);
		/* Populate Mask VXLAN Data. */
		nfp_flower_compile_vxlan((struct nfp_flower_vxlan *)msk,
					 flow, true);
		ext += sizeof(struct nfp_flower_vxlan);
		msk += sizeof(struct nfp_flower_vxlan);
	}

	return 0;
}
+62 −8
Original line number Diff line number Diff line
@@ -52,8 +52,25 @@
	 BIT(FLOW_DISSECTOR_KEY_PORTS) | \
	 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | \
	 BIT(FLOW_DISSECTOR_KEY_VLAN) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
	 BIT(FLOW_DISSECTOR_KEY_IP))

#define NFP_FLOWER_WHITELIST_TUN_DISSECTOR \
	(BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_PORTS))

#define NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R \
	(BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_PORTS))

static int
nfp_flower_xmit_flow(struct net_device *netdev,
		     struct nfp_fl_payload *nfp_flow, u8 mtype)
@@ -125,15 +142,58 @@ nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls,
	if (flow->dissector->used_keys & ~NFP_FLOWER_WHITELIST_DISSECTOR)
		return -EOPNOTSUPP;

	/* If any tun dissector is used then the required set must be used. */
	if (flow->dissector->used_keys & NFP_FLOWER_WHITELIST_TUN_DISSECTOR &&
	    (flow->dissector->used_keys & NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R)
	    != NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R)
		return -EOPNOTSUPP;

	key_layer_two = 0;
	key_layer = NFP_FLOWER_LAYER_PORT | NFP_FLOWER_LAYER_MAC;
	key_size = sizeof(struct nfp_flower_meta_one) +
		   sizeof(struct nfp_flower_in_port) +
		   sizeof(struct nfp_flower_mac_mpls);

	if (dissector_uses_key(flow->dissector,
			       FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
		struct flow_dissector_key_ipv4_addrs *mask_ipv4 = NULL;
		struct flow_dissector_key_ports *mask_enc_ports = NULL;
		struct flow_dissector_key_ports *enc_ports = NULL;
		struct flow_dissector_key_control *mask_enc_ctl =
			skb_flow_dissector_target(flow->dissector,
						  FLOW_DISSECTOR_KEY_ENC_CONTROL,
						  flow->mask);
		/* We are expecting a tunnel. For now we ignore offloading. */
		if (mask_enc_ctl->addr_type)
		struct flow_dissector_key_control *enc_ctl =
			skb_flow_dissector_target(flow->dissector,
						  FLOW_DISSECTOR_KEY_ENC_CONTROL,
						  flow->key);
		if (mask_enc_ctl->addr_type != 0xffff ||
		    enc_ctl->addr_type != FLOW_DISSECTOR_KEY_IPV4_ADDRS)
			return -EOPNOTSUPP;

		/* These fields are already verified as used. */
		mask_ipv4 =
			skb_flow_dissector_target(flow->dissector,
						  FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
						  flow->mask);
		if (mask_ipv4->dst != cpu_to_be32(~0))
			return -EOPNOTSUPP;

		mask_enc_ports =
			skb_flow_dissector_target(flow->dissector,
						  FLOW_DISSECTOR_KEY_ENC_PORTS,
						  flow->mask);
		enc_ports =
			skb_flow_dissector_target(flow->dissector,
						  FLOW_DISSECTOR_KEY_ENC_PORTS,
						  flow->key);

		if (mask_enc_ports->dst != cpu_to_be16(~0) ||
		    enc_ports->dst != htons(NFP_FL_VXLAN_PORT))
			return -EOPNOTSUPP;

		key_layer |= NFP_FLOWER_LAYER_VXLAN;
		key_size += sizeof(struct nfp_flower_vxlan);
	}

	if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
@@ -151,12 +211,6 @@ nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls,
						    FLOW_DISSECTOR_KEY_IP,
						    flow->mask);

	key_layer_two = 0;
	key_layer = NFP_FLOWER_LAYER_PORT | NFP_FLOWER_LAYER_MAC;
	key_size = sizeof(struct nfp_flower_meta_one) +
		   sizeof(struct nfp_flower_in_port) +
		   sizeof(struct nfp_flower_mac_mpls);

	if (mask_basic && mask_basic->n_proto) {
		/* Ethernet type is present in the key. */
		switch (key_basic->n_proto) {