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

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

Merge branch 'nfp-ttl-tos-geneve'



Simon Horman says:

====================
nfp: flower: tunnel TTL & TOS, and Geneve options set & match support

this series contains updates for the TC Flower classifier
and the offload facility for it in the NFP driver.

* Patches 1 & 2: update the NFP driver to allow offload
  of matching and setting tunnel ToS/TTL of flows using the TC Flower
  classifier and tun_key action

* Patches 3 & 4: enhance the flow dissector and TC Flower classifier
  to allow match on Geneve options

* Patch 5 & 6: update the NFP driver to allow offload of
  matching and setting Geneve options of flows using the TC Flower
  classifier and tun_key action
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 50ee42b9 0a22b17a
Loading
Loading
Loading
Loading
+115 −24
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
 */

#include <linux/bitfield.h>
#include <net/geneve.h>
#include <net/pkt_cls.h>
#include <net/switchdev.h>
#include <net/tc_act/tc_csum.h>
@@ -45,7 +46,15 @@
#include "main.h"
#include "../nfp_net_repr.h"

#define NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS	(TUNNEL_CSUM | TUNNEL_KEY)
/* The kernel versions of TUNNEL_* are not ABI and therefore vulnerable
 * to change. Such changes will break our FW ABI.
 */
#define NFP_FL_TUNNEL_CSUM			cpu_to_be16(0x01)
#define NFP_FL_TUNNEL_KEY			cpu_to_be16(0x04)
#define NFP_FL_TUNNEL_GENEVE_OPT		cpu_to_be16(0x0800)
#define NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS	(NFP_FL_TUNNEL_CSUM | \
						 NFP_FL_TUNNEL_KEY | \
						 NFP_FL_TUNNEL_GENEVE_OPT)

static void nfp_fl_pop_vlan(struct nfp_fl_pop_vlan *pop_vlan)
{
@@ -229,7 +238,71 @@ static struct nfp_fl_pre_tunnel *nfp_fl_pre_tunnel(char *act_data, int act_len)
}

static int
nfp_fl_set_ipv4_udp_tun(struct nfp_fl_set_ipv4_udp_tun *set_tun,
nfp_fl_push_geneve_options(struct nfp_fl_payload *nfp_fl, int *list_len,
			   const struct tc_action *action)
{
	struct ip_tunnel_info *ip_tun = tcf_tunnel_info(action);
	int opt_len, opt_cnt, act_start, tot_push_len;
	u8 *src = ip_tunnel_info_opts(ip_tun);

	/* We need to populate the options in reverse order for HW.
	 * Therefore we go through the options, calculating the
	 * number of options and the total size, then we populate
	 * them in reverse order in the action list.
	 */
	opt_cnt = 0;
	tot_push_len = 0;
	opt_len = ip_tun->options_len;
	while (opt_len > 0) {
		struct geneve_opt *opt = (struct geneve_opt *)src;

		opt_cnt++;
		if (opt_cnt > NFP_FL_MAX_GENEVE_OPT_CNT)
			return -EOPNOTSUPP;

		tot_push_len += sizeof(struct nfp_fl_push_geneve) +
			       opt->length * 4;
		if (tot_push_len > NFP_FL_MAX_GENEVE_OPT_ACT)
			return -EOPNOTSUPP;

		opt_len -= sizeof(struct geneve_opt) + opt->length * 4;
		src += sizeof(struct geneve_opt) + opt->length * 4;
	}

	if (*list_len + tot_push_len > NFP_FL_MAX_A_SIZ)
		return -EOPNOTSUPP;

	act_start = *list_len;
	*list_len += tot_push_len;
	src = ip_tunnel_info_opts(ip_tun);
	while (opt_cnt) {
		struct geneve_opt *opt = (struct geneve_opt *)src;
		struct nfp_fl_push_geneve *push;
		size_t act_size, len;

		opt_cnt--;
		act_size = sizeof(struct nfp_fl_push_geneve) + opt->length * 4;
		tot_push_len -= act_size;
		len = act_start + tot_push_len;

		push = (struct nfp_fl_push_geneve *)&nfp_fl->action_data[len];
		push->head.jump_id = NFP_FL_ACTION_OPCODE_PUSH_GENEVE;
		push->head.len_lw = act_size >> NFP_FL_LW_SIZ;
		push->reserved = 0;
		push->class = opt->opt_class;
		push->type = opt->type;
		push->length = opt->length;
		memcpy(&push->opt_data, opt->opt_data, opt->length * 4);

		src += sizeof(struct geneve_opt) + opt->length * 4;
	}

	return 0;
}

static int
nfp_fl_set_ipv4_udp_tun(struct nfp_app *app,
			struct nfp_fl_set_ipv4_udp_tun *set_tun,
			const struct tc_action *action,
			struct nfp_fl_pre_tunnel *pre_tun,
			enum nfp_flower_tun_type tun_type,
@@ -237,19 +310,19 @@ nfp_fl_set_ipv4_udp_tun(struct nfp_fl_set_ipv4_udp_tun *set_tun,
{
	size_t act_size = sizeof(struct nfp_fl_set_ipv4_udp_tun);
	struct ip_tunnel_info *ip_tun = tcf_tunnel_info(action);
	struct nfp_flower_priv *priv = app->priv;
	u32 tmp_set_ip_tun_type_index = 0;
	struct flowi4 flow = {};
	/* Currently support one pre-tunnel so index is always 0. */
	int pretun_idx = 0;
	struct rtable *rt;
	struct net *net;
	int err;

	if (ip_tun->options_len)
	BUILD_BUG_ON(NFP_FL_TUNNEL_CSUM != TUNNEL_CSUM ||
		     NFP_FL_TUNNEL_KEY	!= TUNNEL_KEY ||
		     NFP_FL_TUNNEL_GENEVE_OPT != TUNNEL_GENEVE_OPT);
	if (ip_tun->options_len &&
	    (tun_type != NFP_FL_TUNNEL_GENEVE ||
	    !(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT)))
		return -EOPNOTSUPP;

	net = dev_net(netdev);

	set_tun->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL;
	set_tun->head.len_lw = act_size >> NFP_FL_LW_SIZ;

@@ -261,9 +334,17 @@ nfp_fl_set_ipv4_udp_tun(struct nfp_fl_set_ipv4_udp_tun *set_tun,
	set_tun->tun_type_index = cpu_to_be32(tmp_set_ip_tun_type_index);
	set_tun->tun_id = ip_tun->key.tun_id;

	/* Do a route lookup to determine ttl - if fails then use default.
	 * Note that CONFIG_INET is a requirement of CONFIG_NET_SWITCHDEV so
	 * must be defined here.
	if (ip_tun->key.ttl) {
		set_tun->ttl = ip_tun->key.ttl;
	} else {
		struct net *net = dev_net(netdev);
		struct flowi4 flow = {};
		struct rtable *rt;
		int err;

		/* Do a route lookup to determine ttl - if fails then use
		 * default. Note that CONFIG_INET is a requirement of
		 * CONFIG_NET_SWITCHDEV so must be defined here.
		 */
		flow.daddr = ip_tun->key.u.ipv4.dst;
		flow.flowi4_proto = IPPROTO_UDP;
@@ -275,14 +356,20 @@ nfp_fl_set_ipv4_udp_tun(struct nfp_fl_set_ipv4_udp_tun *set_tun,
		} else {
			set_tun->ttl = net->ipv4.sysctl_ip_default_ttl;
		}
	}

	set_tun->tos = ip_tun->key.tos;

	if (!(ip_tun->key.tun_flags & TUNNEL_KEY) ||
	if (!(ip_tun->key.tun_flags & NFP_FL_TUNNEL_KEY) ||
	    ip_tun->key.tun_flags & ~NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS)
		return -EOPNOTSUPP;
	set_tun->tun_flags = ip_tun->key.tun_flags;

	if (tun_type == NFP_FL_TUNNEL_GENEVE) {
		set_tun->tun_proto = htons(ETH_P_TEB);
		set_tun->tun_len = ip_tun->options_len / 4;
	}

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

@@ -671,9 +758,13 @@ nfp_flower_loop_action(struct nfp_app *app, const struct tc_action *a,
		nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
		*a_len += sizeof(struct nfp_fl_pre_tunnel);

		err = nfp_fl_push_geneve_options(nfp_fl, a_len, a);
		if (err)
			return err;

		set_tun = (void *)&nfp_fl->action_data[*a_len];
		err = nfp_fl_set_ipv4_udp_tun(set_tun, a, pre_tun, *tun_type,
					      netdev);
		err = nfp_fl_set_ipv4_udp_tun(app, set_tun, a, pre_tun,
					      *tun_type, netdev);
		if (err)
			return err;
		*a_len += sizeof(struct nfp_fl_set_ipv4_udp_tun);
+30 −3
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/bitfield.h>
#include <linux/skbuff.h>
#include <linux/types.h>
#include <net/geneve.h>

#include "../nfp_app.h"
#include "../nfpcore/nfp_cpp.h"
@@ -51,6 +52,7 @@
#define NFP_FLOWER_LAYER_VXLAN		BIT(7)

#define NFP_FLOWER_LAYER2_GENEVE	BIT(5)
#define NFP_FLOWER_LAYER2_GENEVE_OP	BIT(6)

#define NFP_FLOWER_MASK_VLAN_PRIO	GENMASK(15, 13)
#define NFP_FLOWER_MASK_VLAN_CFI	BIT(12)
@@ -81,6 +83,11 @@
#define NFP_FL_MAX_A_SIZ		1216
#define NFP_FL_LW_SIZ			2

/* Maximum allowed geneve options */
#define NFP_FL_MAX_GENEVE_OPT_ACT	32
#define NFP_FL_MAX_GENEVE_OPT_CNT	64
#define NFP_FL_MAX_GENEVE_OPT_KEY	32

/* Action opcodes */
#define NFP_FL_ACTION_OPCODE_OUTPUT		0
#define NFP_FL_ACTION_OPCODE_PUSH_VLAN		1
@@ -94,6 +101,7 @@
#define NFP_FL_ACTION_OPCODE_SET_TCP		15
#define NFP_FL_ACTION_OPCODE_PRE_LAG		16
#define NFP_FL_ACTION_OPCODE_PRE_TUNNEL		17
#define NFP_FL_ACTION_OPCODE_PUSH_GENEVE	26
#define NFP_FL_ACTION_OPCODE_NUM		32

#define NFP_FL_OUT_FLAGS_LAST		BIT(15)
@@ -206,7 +214,19 @@ struct nfp_fl_set_ipv4_udp_tun {
	__be16 tun_flags;
	u8 ttl;
	u8 tos;
	__be32 extra[2];
	__be32 extra;
	u8 tun_len;
	u8 res2;
	__be16 tun_proto;
};

struct nfp_fl_push_geneve {
	struct nfp_fl_act_head head;
	__be16 reserved;
	__be16 class;
	u8 type;
	u8 length;
	u8 opt_data[];
};

/* Metadata with L2 (1W/4B)
@@ -346,7 +366,7 @@ struct nfp_flower_ipv6 {
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                         ipv4_addr_dst                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                            Reserved                           |
 * |           Reserved            |      tos      |      ttl      |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                            Reserved                           |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -356,10 +376,17 @@ struct nfp_flower_ipv6 {
struct nfp_flower_ipv4_udp_tun {
	__be32 ip_src;
	__be32 ip_dst;
	__be32 reserved[2];
	__be16 reserved1;
	u8 tos;
	u8 ttl;
	__be32 reserved2;
	__be32 tun_id;
};

struct nfp_flower_geneve_options {
	u8 data[NFP_FL_MAX_GENEVE_OPT_KEY];
};

#define NFP_FL_TUN_VNI_OFFSET 8

/* The base header for a control message packet.
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ struct nfp_app;
/* Extra features bitmap. */
#define NFP_FL_FEATS_GENEVE		BIT(0)
#define NFP_FL_NBI_MTU_SETTING		BIT(1)
#define NFP_FL_FEATS_GENEVE_OPT		BIT(2)
#define NFP_FL_FEATS_LAG		BIT(31)

struct nfp_fl_mask_id {
+34 −0
Original line number Diff line number Diff line
@@ -262,6 +262,21 @@ nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *frame,
	nfp_flower_compile_ip_ext(&frame->ip_ext, flow, mask_version);
}

static int
nfp_flower_compile_geneve_opt(void *key_buf, struct tc_cls_flower_offload *flow,
			      bool mask_version)
{
	struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
	struct flow_dissector_key_enc_opts *opts;

	opts = skb_flow_dissector_target(flow->dissector,
					 FLOW_DISSECTOR_KEY_ENC_OPTS,
					 target);
	memcpy(key_buf, opts->data, opts->len);

	return 0;
}

static void
nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame,
				struct tc_cls_flower_offload *flow,
@@ -270,6 +285,7 @@ nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame,
	struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
	struct flow_dissector_key_ipv4_addrs *tun_ips;
	struct flow_dissector_key_keyid *vni;
	struct flow_dissector_key_ip *ip;

	memset(frame, 0, sizeof(struct nfp_flower_ipv4_udp_tun));

@@ -293,6 +309,14 @@ nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame,
		frame->ip_src = tun_ips->src;
		frame->ip_dst = tun_ips->dst;
	}

	if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_ENC_IP)) {
		ip = skb_flow_dissector_target(flow->dissector,
					       FLOW_DISSECTOR_KEY_ENC_IP,
					       target);
		frame->tos = ip->tos;
		frame->ttl = ip->ttl;
	}
}

int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
@@ -415,6 +439,16 @@ int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
			nfp_flow->nfp_tun_ipv4_addr = tun_dst;
			nfp_tunnel_add_ipv4_off(netdev_repr->app, tun_dst);
		}

		if (key_ls->key_layer_two & NFP_FLOWER_LAYER2_GENEVE_OP) {
			err = nfp_flower_compile_geneve_opt(ext, flow, false);
			if (err)
				return err;

			err = nfp_flower_compile_geneve_opt(msk, flow, true);
			if (err)
				return err;
		}
	}

	return 0;
+41 −1
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@
	 BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_IP) | \
	 BIT(FLOW_DISSECTOR_KEY_MPLS) | \
	 BIT(FLOW_DISSECTOR_KEY_IP))

@@ -74,7 +76,9 @@
	 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))
	 BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
	 BIT(FLOW_DISSECTOR_KEY_ENC_IP))

#define NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R \
	(BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
@@ -138,6 +142,21 @@ static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f)
		dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ICMP);
}

static int
nfp_flower_calc_opt_layer(struct flow_dissector_key_enc_opts *enc_opts,
			  u32 *key_layer_two, int *key_size)
{
	if (enc_opts->len > NFP_FL_MAX_GENEVE_OPT_KEY)
		return -EOPNOTSUPP;

	if (enc_opts->len > 0) {
		*key_layer_two |= NFP_FLOWER_LAYER2_GENEVE_OP;
		*key_size += sizeof(struct nfp_flower_geneve_options);
	}

	return 0;
}

static int
nfp_flower_calculate_key_layers(struct nfp_app *app,
				struct nfp_fl_key_ls *ret_key_ls,
@@ -151,6 +170,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
	u32 key_layer_two;
	u8 key_layer;
	int key_size;
	int err;

	if (flow->dissector->used_keys & ~NFP_FLOWER_WHITELIST_DISSECTOR)
		return -EOPNOTSUPP;
@@ -176,6 +196,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
			       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_enc_opts *enc_op = NULL;
		struct flow_dissector_key_ports *enc_ports = NULL;
		struct flow_dissector_key_control *mask_enc_ctl =
			skb_flow_dissector_target(flow->dissector,
@@ -212,11 +233,21 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
		if (mask_enc_ports->dst != cpu_to_be16(~0))
			return -EOPNOTSUPP;

		if (dissector_uses_key(flow->dissector,
				       FLOW_DISSECTOR_KEY_ENC_OPTS)) {
			enc_op = skb_flow_dissector_target(flow->dissector,
							   FLOW_DISSECTOR_KEY_ENC_OPTS,
							   flow->key);
		}

		switch (enc_ports->dst) {
		case htons(NFP_FL_VXLAN_PORT):
			*tun_type = NFP_FL_TUNNEL_VXLAN;
			key_layer |= NFP_FLOWER_LAYER_VXLAN;
			key_size += sizeof(struct nfp_flower_ipv4_udp_tun);

			if (enc_op)
				return -EOPNOTSUPP;
			break;
		case htons(NFP_FL_GENEVE_PORT):
			if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE))
@@ -226,6 +257,15 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
			key_size += sizeof(struct nfp_flower_ext_meta);
			key_layer_two |= NFP_FLOWER_LAYER2_GENEVE;
			key_size += sizeof(struct nfp_flower_ipv4_udp_tun);

			if (!enc_op)
				break;
			if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT))
				return -EOPNOTSUPP;
			err = nfp_flower_calc_opt_layer(enc_op, &key_layer_two,
							&key_size);
			if (err)
				return err;
			break;
		default:
			return -EOPNOTSUPP;
Loading