DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels
@ 2018-02-27 12:45 Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 01/14] net/sfc/base: support filters for encapsulated packets Andrew Rybchenko
                   ` (14 more replies)
  0 siblings, 15 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev

Update base driver and the PMD itself to support flow API
patterns for tunnels: VXLAN, NVGRE and Geneve.

Applicable to SFN8xxx NICs with full-feature firmware variant running.

Andrew Rybchenko (1):
  doc: add net/sfc flow API support for tunnels

Roman Zhukov (12):
  net/sfc/base: support filters for encapsulated packets
  net/sfc/base: support VNI/VSID and inner frame local MAC
  net/sfc/base: distinguish filters for encapsulated packets
  net/sfc: add VXLAN in flow API filters support
  net/sfc: add NVGRE in flow API filters support
  net/sfc: add GENEVE in flow API filters support
  net/sfc: add inner frame ETH in flow API filters support
  net/sfc: add infrastructure to make many filters from flow
  net/sfc: multiply of specs with an unknown EtherType
  net/sfc: multiply of specs w/o inner frame destination MAC
  net/sfc: multiply of specs with an unknown destination MAC
  net/sfc: avoid creation of ineffective flow rules

Vijay Srivastava (1):
  net/sfc/base: support VXLAN filter creation

 doc/guides/nics/sfc_efx.rst            |   28 +-
 doc/guides/rel_notes/release_18_05.rst |    6 +
 drivers/net/sfc/base/ef10_filter.c     |  100 +++-
 drivers/net/sfc/base/efx.h             |   20 +
 drivers/net/sfc/base/efx_filter.c      |   39 +-
 drivers/net/sfc/sfc_flow.c             | 1001 ++++++++++++++++++++++++++++++--
 drivers/net/sfc/sfc_flow.h             |   19 +-
 7 files changed, 1161 insertions(+), 52 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 01/14] net/sfc/base: support filters for encapsulated packets
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-03-06 15:13   ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 02/14] net/sfc/base: support VNI/VSID and inner frame local MAC Andrew Rybchenko
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

This adds filters for encapsulated packets to the list
returned by ef10_filter_supported_filters().

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 drivers/net/sfc/base/ef10_filter.c | 65 ++++++++++++++++++++++++++++++++------
 1 file changed, 55 insertions(+), 10 deletions(-)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index 27b5998..f643cdb 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -890,6 +890,7 @@ efx_mcdi_get_parser_disp_info(
 	__in				efx_nic_t *enp,
 	__out_ecount(buffer_length)	uint32_t *buffer,
 	__in				size_t buffer_length,
+	__in				boolean_t encap,
 	__out				size_t *list_lengthp)
 {
 	efx_mcdi_req_t req;
@@ -906,7 +907,8 @@ efx_mcdi_get_parser_disp_info(
 	req.emr_out_buf = payload;
 	req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX;
 
-	MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP,
+	MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, encap ?
+	    MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_ENCAP_RX_MATCHES :
 	    MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);
 
 	efx_mcdi_execute(enp, &req);
@@ -966,28 +968,66 @@ ef10_filter_supported_filters(
 	__in				size_t buffer_length,
 	__out				size_t *list_lengthp)
 {
-
+	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 	size_t mcdi_list_length;
+	size_t mcdi_encap_list_length;
 	size_t list_length;
 	uint32_t i;
+	uint32_t next_buf_idx;
+	size_t next_buf_length;
 	efx_rc_t rc;
+	boolean_t no_space = B_FALSE;
 	efx_filter_match_flags_t all_filter_flags =
 	    (EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST |
 	    EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT |
 	    EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
 	    EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID |
 	    EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO |
+	    EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
+	    EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
 	    EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
 	    EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
 
-	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length,
-					    &mcdi_list_length);
+	/*
+	 * Two calls to MC_CMD_GET_PARSER_DISP_INFO are needed: one to get the
+	 * list of supported filters for ordinary packets, and then another to
+	 * get the list of supported filters for encapsulated packets.
+	 */
+	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, B_FALSE,
+	    &mcdi_list_length);
 	if (rc != 0) {
-		if (rc == ENOSPC) {
-			/* Pass through mcdi_list_length for the list length */
-			*list_lengthp = mcdi_list_length;
+		if (rc == ENOSPC)
+			no_space = B_TRUE;
+		else
+			goto fail1;
+	}
+
+	if (no_space) {
+		next_buf_idx = 0;
+		next_buf_length = 0;
+	} else {
+		EFSYS_ASSERT(mcdi_list_length < buffer_length);
+		next_buf_idx = mcdi_list_length;
+		next_buf_length = buffer_length - mcdi_list_length;
+	}
+
+	if (encp->enc_tunnel_encapsulations_supported != 0) {
+		rc = efx_mcdi_get_parser_disp_info(enp, &buffer[next_buf_idx],
+		    next_buf_length, B_TRUE, &mcdi_encap_list_length);
+		if (rc != 0) {
+			if (rc == ENOSPC)
+				no_space = B_TRUE;
+			else
+				goto fail2;
 		}
-		goto fail1;
+	} else {
+		mcdi_encap_list_length = 0;
+	}
+
+	if (no_space) {
+		*list_lengthp = mcdi_list_length + mcdi_encap_list_length;
+		rc = ENOSPC;
+		goto fail3;
 	}
 
 	/*
@@ -1000,9 +1040,10 @@ ef10_filter_supported_filters(
 	 * of the matches is preserved as they are ordered from highest to
 	 * lowest priority.
 	 */
-	EFSYS_ASSERT(mcdi_list_length <= buffer_length);
+	EFSYS_ASSERT(mcdi_list_length + mcdi_encap_list_length <=
+	    buffer_length);
 	list_length = 0;
-	for (i = 0; i < mcdi_list_length; i++) {
+	for (i = 0; i < mcdi_list_length + mcdi_encap_list_length; i++) {
 		if ((buffer[i] & ~all_filter_flags) == 0) {
 			buffer[list_length] = buffer[i];
 			list_length++;
@@ -1013,6 +1054,10 @@ ef10_filter_supported_filters(
 
 	return (0);
 
+fail3:
+	EFSYS_PROBE(fail3);
+fail2:
+	EFSYS_PROBE(fail2);
 fail1:
 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 02/14] net/sfc/base: support VNI/VSID and inner frame local MAC
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 01/14] net/sfc/base: support filters for encapsulated packets Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 03/14] net/sfc/base: support VXLAN filter creation Andrew Rybchenko
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

This supports VNI/VSID and inner frame local MAC fields to
match in VXLAN, GENEVE, or NVGRE packets.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 drivers/net/sfc/base/ef10_filter.c | 18 ++++++++++++++++++
 drivers/net/sfc/base/efx.h         |  8 ++++++++
 2 files changed, 26 insertions(+)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index f643cdb..8026b1a 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -118,6 +118,10 @@ ef10_filter_init(
 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN));
 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO));
+	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_VNI_OR_VSID ==
+	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID));
+	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_LOC_MAC ==
+	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC));
 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST ==
 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST));
 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST ==
@@ -290,6 +294,12 @@ efx_mcdi_filter_op_add(
 			rc = EINVAL;
 			goto fail2;
 		}
+
+		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_VNI_OR_VSID),
+		    spec->efs_vni_or_vsid, EFX_VNI_OR_VSID_LEN);
+
+		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_IFRM_DST_MAC),
+		    spec->efs_ifrm_loc_mac, EFX_MAC_ADDR_LEN);
 	}
 
 	efx_mcdi_execute(enp, &req);
@@ -413,6 +423,12 @@ ef10_filter_equal(
 		return (B_FALSE);
 	if (left->efs_encap_type != right->efs_encap_type)
 		return (B_FALSE);
+	if (memcmp(left->efs_vni_or_vsid, right->efs_vni_or_vsid,
+	    EFX_VNI_OR_VSID_LEN))
+		return (B_FALSE);
+	if (memcmp(left->efs_ifrm_loc_mac, right->efs_ifrm_loc_mac,
+	    EFX_MAC_ADDR_LEN))
+		return (B_FALSE);
 
 	return (B_TRUE);
 
@@ -983,6 +999,8 @@ ef10_filter_supported_filters(
 	    EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
 	    EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID |
 	    EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO |
+	    EFX_FILTER_MATCH_VNI_OR_VSID |
+	    EFX_FILTER_MATCH_IFRM_LOC_MAC |
 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
 	    EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index fe996e7..ac589f9 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -413,6 +413,8 @@ typedef enum efx_link_mode_e {
 
 #define	EFX_MAC_ADDR_LEN 6
 
+#define	EFX_VNI_OR_VSID_LEN 3
+
 #define	EFX_MAC_ADDR_IS_MULTICAST(_address) (((uint8_t *)_address)[0] & 0x01)
 
 #define	EFX_MAC_MULTICAST_LIST_MAX	256
@@ -2313,6 +2315,10 @@ typedef uint8_t efx_filter_flags_t;
 #define	EFX_FILTER_MATCH_OUTER_VID		0x00000100
 /* Match by IP transport protocol */
 #define	EFX_FILTER_MATCH_IP_PROTO		0x00000200
+/* Match by VNI or VSID */
+#define	EFX_FILTER_MATCH_VNI_OR_VSID		0x00000800
+/* For encapsulated packets, match by inner frame local MAC address */
+#define	EFX_FILTER_MATCH_IFRM_LOC_MAC		0x00010000
 /* For encapsulated packets, match all multicast inner frames */
 #define	EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST	0x01000000
 /* For encapsulated packets, match all unicast inner frames */
@@ -2359,6 +2365,8 @@ typedef struct efx_filter_spec_s {
 	uint16_t			efs_rem_port;
 	efx_oword_t			efs_rem_host;
 	efx_oword_t			efs_loc_host;
+	uint8_t				efs_vni_or_vsid[EFX_VNI_OR_VSID_LEN];
+	uint8_t				efs_ifrm_loc_mac[EFX_MAC_ADDR_LEN];
 } efx_filter_spec_t;
 
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 03/14] net/sfc/base: support VXLAN filter creation
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 01/14] net/sfc/base: support filters for encapsulated packets Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 02/14] net/sfc/base: support VNI/VSID and inner frame local MAC Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 04/14] net/sfc/base: distinguish filters for encapsulated packets Andrew Rybchenko
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Vijay Srivastava

From: Vijay Srivastava <vijays@solarflare.com>

Signed-off-by: Vijay Srivastava <vijays@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 drivers/net/sfc/base/efx.h        |  7 +++++++
 drivers/net/sfc/base/efx_filter.c | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index ac589f9..c0e4218 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -2462,6 +2462,13 @@ efx_filter_spec_set_encap_type(
 	__in		efx_tunnel_protocol_t encap_type,
 	__in		efx_filter_inner_frame_match_t inner_frame_match);
 
+extern	__checkReturn	efx_rc_t
+efx_filter_spec_set_vxlan_full(
+	__inout		efx_filter_spec_t *spec,
+	__in		const uint8_t *vxlan_id,
+	__in		const uint8_t *inner_addr,
+	__in		const uint8_t *outer_addr);
+
 #if EFSYS_OPT_RX_SCALE
 extern	__checkReturn	efx_rc_t
 efx_filter_spec_set_rss_context(
diff --git a/drivers/net/sfc/base/efx_filter.c b/drivers/net/sfc/base/efx_filter.c
index b92541a..4bce050 100644
--- a/drivers/net/sfc/base/efx_filter.c
+++ b/drivers/net/sfc/base/efx_filter.c
@@ -462,6 +462,42 @@ efx_filter_spec_set_encap_type(
 	return (rc);
 }
 
+/*
+ * Specify inner and outer Ethernet address and VXLAN ID in filter
+ * specification.
+ */
+	__checkReturn	efx_rc_t
+efx_filter_spec_set_vxlan_full(
+	__inout		efx_filter_spec_t *spec,
+	__in		const uint8_t *vxlan_id,
+	__in		const uint8_t *inner_addr,
+	__in		const uint8_t *outer_addr)
+{
+	EFSYS_ASSERT3P(spec, !=, NULL);
+	EFSYS_ASSERT3P(vxlan_id, !=, NULL);
+	EFSYS_ASSERT3P(inner_addr, !=, NULL);
+	EFSYS_ASSERT3P(outer_addr, !=, NULL);
+
+	if ((inner_addr == NULL) && (outer_addr == NULL))
+		return (EINVAL);
+
+	if (vxlan_id != NULL) {
+		spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
+		memcpy(spec->efs_vni_or_vsid, vxlan_id, EFX_VNI_OR_VSID_LEN);
+	}
+	if (outer_addr != NULL) {
+		spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
+		memcpy(spec->efs_loc_mac, outer_addr, EFX_MAC_ADDR_LEN);
+	}
+	if (inner_addr != NULL) {
+		spec->efs_match_flags |= EFX_FILTER_MATCH_IFRM_LOC_MAC;
+		memcpy(spec->efs_ifrm_loc_mac, inner_addr, EFX_MAC_ADDR_LEN);
+	}
+	spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
+
+	return (0);
+}
+
 #if EFSYS_OPT_RX_SCALE
 	__checkReturn	efx_rc_t
 efx_filter_spec_set_rss_context(
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 04/14] net/sfc/base: distinguish filters for encapsulated packets
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (2 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 03/14] net/sfc/base: support VXLAN filter creation Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 05/14] net/sfc: add VXLAN in flow API filters support Andrew Rybchenko
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Add filter match flag to distinguish filters applied only to
encapsulated packets.

Match flags set should allow to determine whether a filter
is supported or not. The problem is that if specification
has supported set outer match flags and specified
encapsulation without any inner flags, check says that it
is supported, and filter insertion is performed. However,
there is no filtering of the encapsulated traffic. A new
flag is added to solve this problem and separate the
filters for the encapsulated packets.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
Reviewed-by: Mark Spender <mspender@solarflare.com>
---
 drivers/net/sfc/base/ef10_filter.c | 19 +++++++++++++++++--
 drivers/net/sfc/base/efx.h         |  5 +++++
 drivers/net/sfc/base/efx_filter.c  |  3 ++-
 3 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index 8026b1a..54e1c35 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -172,6 +172,7 @@ efx_mcdi_filter_op_add(
 	efx_mcdi_req_t req;
 	uint8_t payload[MAX(MC_CMD_FILTER_OP_EXT_IN_LEN,
 			    MC_CMD_FILTER_OP_EXT_OUT_LEN)];
+	efx_filter_match_flags_t match_flags;
 	efx_rc_t rc;
 
 	memset(payload, 0, sizeof (payload));
@@ -181,6 +182,12 @@ efx_mcdi_filter_op_add(
 	req.emr_out_buf = payload;
 	req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN;
 
+	/*
+	 * Remove match flag for encapsulated filters that does not correspond
+	 * to the MCDI match flags
+	 */
+	match_flags = spec->efs_match_flags & ~EFX_FILTER_MATCH_ENCAP_TYPE;
+
 	switch (filter_op) {
 	case MC_CMD_FILTER_OP_IN_OP_REPLACE:
 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO,
@@ -201,7 +208,7 @@ efx_mcdi_filter_op_add(
 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_PORT_ID,
 	    EVB_PORT_ID_ASSIGNED);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_MATCH_FIELDS,
-	    spec->efs_match_flags);
+	    match_flags);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
 	    MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE,
@@ -1003,13 +1010,17 @@ ef10_filter_supported_filters(
 	    EFX_FILTER_MATCH_IFRM_LOC_MAC |
 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
+	    EFX_FILTER_MATCH_ENCAP_TYPE |
 	    EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
 	    EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
 
 	/*
 	 * Two calls to MC_CMD_GET_PARSER_DISP_INFO are needed: one to get the
 	 * list of supported filters for ordinary packets, and then another to
-	 * get the list of supported filters for encapsulated packets.
+	 * get the list of supported filters for encapsulated packets. To
+	 * distinguish the second list from the first, the
+	 * EFX_FILTER_MATCH_ENCAP_TYPE flag is added to each filter for
+	 * encapsulated packets.
 	 */
 	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, B_FALSE,
 	    &mcdi_list_length);
@@ -1037,6 +1048,10 @@ ef10_filter_supported_filters(
 				no_space = B_TRUE;
 			else
 				goto fail2;
+		} else {
+			for (i = next_buf_idx;
+			    i < next_buf_idx + mcdi_encap_list_length; i++)
+				buffer[i] |= EFX_FILTER_MATCH_ENCAP_TYPE;
 		}
 	} else {
 		mcdi_encap_list_length = 0;
diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index c0e4218..df1e23a 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -2323,6 +2323,11 @@ typedef uint8_t efx_filter_flags_t;
 #define	EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST	0x01000000
 /* For encapsulated packets, match all unicast inner frames */
 #define	EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST	0x02000000
+/*
+ * Match by encap type, this flag does not correspond to
+ * the MCDI match flags and any unoccupied value may be used
+ */
+#define	EFX_FILTER_MATCH_ENCAP_TYPE		0x20000000
 /* Match otherwise-unmatched multicast and broadcast packets */
 #define	EFX_FILTER_MATCH_UNKNOWN_MCAST_DST	0x40000000
 /* Match otherwise-unmatched unicast packets */
diff --git a/drivers/net/sfc/base/efx_filter.c b/drivers/net/sfc/base/efx_filter.c
index 4bce050..a37b5c1 100644
--- a/drivers/net/sfc/base/efx_filter.c
+++ b/drivers/net/sfc/base/efx_filter.c
@@ -412,7 +412,7 @@ efx_filter_spec_set_encap_type(
 	__in		efx_tunnel_protocol_t encap_type,
 	__in		efx_filter_inner_frame_match_t inner_frame_match)
 {
-	uint32_t match_flags = 0;
+	uint32_t match_flags = EFX_FILTER_MATCH_ENCAP_TYPE;
 	uint8_t ip_proto;
 	efx_rc_t rc;
 
@@ -493,6 +493,7 @@ efx_filter_spec_set_vxlan_full(
 		spec->efs_match_flags |= EFX_FILTER_MATCH_IFRM_LOC_MAC;
 		memcpy(spec->efs_ifrm_loc_mac, inner_addr, EFX_MAC_ADDR_LEN);
 	}
+	spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
 	spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
 
 	return (0);
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 05/14] net/sfc: add VXLAN in flow API filters support
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (3 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 04/14] net/sfc/base: distinguish filters for encapsulated packets Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 06/14] net/sfc: add NVGRE " Andrew Rybchenko
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Exact match of VXLAN network identifier is supported by parser.
IP protocol match are enforced to UDP.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |   2 +
 drivers/net/sfc/sfc_flow.c  | 165 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 167 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index ccdf5ff..5a4b2a6 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -166,6 +166,8 @@ Supported pattern items:
 
 - UDP (exact match of source/destination ports)
 
+- VXLAN (exact match of VXLAN network identifier)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 93cdf8f..20ba69d 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -57,6 +57,7 @@ static sfc_flow_item_parse sfc_flow_parse_ipv4;
 static sfc_flow_item_parse sfc_flow_parse_ipv6;
 static sfc_flow_item_parse sfc_flow_parse_tcp;
 static sfc_flow_item_parse sfc_flow_parse_udp;
+static sfc_flow_item_parse sfc_flow_parse_vxlan;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -696,6 +697,132 @@ sfc_flow_parse_udp(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+/*
+ * Filters for encapsulated packets match based on the EtherType and IP
+ * protocol in the outer frame.
+ */
+static int
+sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
+					efx_filter_spec_t *efx_spec,
+					uint8_t ip_proto,
+					struct rte_flow_error *error)
+{
+	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_IP_PROTO)) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
+		efx_spec->efs_ip_proto = ip_proto;
+	} else if (efx_spec->efs_ip_proto != ip_proto) {
+		switch (ip_proto) {
+		case EFX_IPPROTO_UDP:
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Outer IP header protocol must be UDP "
+				"in VxLAN pattern");
+			return -rte_errno;
+
+		default:
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Only VxLAN tunneling patterns "
+				"are supported");
+			return -rte_errno;
+		}
+	}
+
+	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Outer frame EtherType in pattern with tunneling "
+			"must be set");
+		return -rte_errno;
+	} else if (efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4 &&
+		   efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV6) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Outer frame EtherType in pattern with tunneling "
+			"must be IPv4 or IPv6");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
+static int
+sfc_flow_set_efx_spec_vni_or_vsid(efx_filter_spec_t *efx_spec,
+				  const uint8_t *vni_or_vsid_val,
+				  const uint8_t *vni_or_vsid_mask,
+				  const struct rte_flow_item *item,
+				  struct rte_flow_error *error)
+{
+	const uint8_t vni_or_vsid_full_mask[EFX_VNI_OR_VSID_LEN] = {
+		0xff, 0xff, 0xff
+	};
+
+	if (memcmp(vni_or_vsid_mask, vni_or_vsid_full_mask,
+		   EFX_VNI_OR_VSID_LEN) == 0) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
+		rte_memcpy(efx_spec->efs_vni_or_vsid, vni_or_vsid_val,
+			   EFX_VNI_OR_VSID_LEN);
+	} else if (!sfc_flow_is_zero(vni_or_vsid_mask, EFX_VNI_OR_VSID_LEN)) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "Unsupported VNI/VSID mask");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
+/**
+ * Convert VXLAN item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only VXLAN network identifier field is supported.
+ *   If the mask is NULL, default mask will be used.
+ *   Ranging is not supported.
+ * @param efx_spec[in, out]
+ *   EFX filter specification to update.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_parse_vxlan(const struct rte_flow_item *item,
+		     efx_filter_spec_t *efx_spec,
+		     struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_vxlan *spec = NULL;
+	const struct rte_flow_item_vxlan *mask = NULL;
+	const struct rte_flow_item_vxlan supp_mask = {
+		.vni = { 0xff, 0xff, 0xff }
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_vxlan_mask,
+				 sizeof(struct rte_flow_item_vxlan),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	rc = sfc_flow_set_match_flags_for_encap_pkts(item, efx_spec,
+						     EFX_IPPROTO_UDP, error);
+	if (rc != 0)
+		return rc;
+
+	efx_spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
+	efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
+
+	if (spec == NULL)
+		return 0;
+
+	rc = sfc_flow_set_efx_spec_vni_or_vsid(efx_spec, spec->vni,
+					       mask->vni, item, error);
+
+	return rc;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -739,6 +866,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L4,
 		.parse = sfc_flow_parse_udp,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_VXLAN,
+		.prev_layer = SFC_FLOW_ITEM_L4,
+		.layer = SFC_FLOW_ITEM_START_LAYER,
+		.parse = sfc_flow_parse_vxlan,
+	},
 };
 
 /*
@@ -806,6 +939,7 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 {
 	int rc;
 	unsigned int prev_layer = SFC_FLOW_ITEM_ANY_LAYER;
+	boolean_t is_ifrm = B_FALSE;
 	const struct sfc_flow_item *item;
 
 	if (pattern == NULL) {
@@ -837,6 +971,37 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 			return -rte_errno;
 		}
 
+		/*
+		 * Allow only VOID pattern item in the inner frame.
+		 * Also check that there is only one tunneling protocol.
+		 */
+		switch (item->type) {
+		case RTE_FLOW_ITEM_TYPE_VOID:
+			break;
+
+		case RTE_FLOW_ITEM_TYPE_VXLAN:
+			if (is_ifrm) {
+				rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					pattern,
+					"More than one tunneling protocol");
+				return -rte_errno;
+			}
+			is_ifrm = B_TRUE;
+			break;
+
+		default:
+			if (is_ifrm) {
+				rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					pattern,
+					"There is an unsupported pattern item "
+					"in the inner frame");
+				return -rte_errno;
+			}
+			break;
+		}
+
 		rc = item->parse(pattern, &flow->spec, error);
 		if (rc != 0)
 			return rc;
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 06/14] net/sfc: add NVGRE in flow API filters support
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (4 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 05/14] net/sfc: add VXLAN in flow API filters support Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 07/14] net/sfc: add GENEVE " Andrew Rybchenko
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Exact match of virtual subnet ID is supported by parser.
IP protocol match are enforced to GRE.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  2 ++
 drivers/net/sfc/sfc_flow.c  | 68 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 5a4b2a6..05dacb3 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -168,6 +168,8 @@ Supported pattern items:
 
 - VXLAN (exact match of VXLAN network identifier)
 
+- NVGRE (exact match of virtual subnet ID)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 20ba69d..126ec9b 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -58,6 +58,7 @@ static sfc_flow_item_parse sfc_flow_parse_ipv6;
 static sfc_flow_item_parse sfc_flow_parse_tcp;
 static sfc_flow_item_parse sfc_flow_parse_udp;
 static sfc_flow_item_parse sfc_flow_parse_vxlan;
+static sfc_flow_item_parse sfc_flow_parse_nvgre;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -719,10 +720,17 @@ sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
 				"in VxLAN pattern");
 			return -rte_errno;
 
+		case EFX_IPPROTO_GRE:
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Outer IP header protocol must be GRE "
+				"in NVGRE pattern");
+			return -rte_errno;
+
 		default:
 			rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_ITEM, item,
-				"Only VxLAN tunneling patterns "
+				"Only VxLAN/NVGRE tunneling patterns "
 				"are supported");
 			return -rte_errno;
 		}
@@ -823,6 +831,57 @@ sfc_flow_parse_vxlan(const struct rte_flow_item *item,
 	return rc;
 }
 
+/**
+ * Convert NVGRE item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only virtual subnet ID field is supported.
+ *   If the mask is NULL, default mask will be used.
+ *   Ranging is not supported.
+ * @param efx_spec[in, out]
+ *   EFX filter specification to update.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_parse_nvgre(const struct rte_flow_item *item,
+		     efx_filter_spec_t *efx_spec,
+		     struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_nvgre *spec = NULL;
+	const struct rte_flow_item_nvgre *mask = NULL;
+	const struct rte_flow_item_nvgre supp_mask = {
+		.tni = { 0xff, 0xff, 0xff }
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_nvgre_mask,
+				 sizeof(struct rte_flow_item_nvgre),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	rc = sfc_flow_set_match_flags_for_encap_pkts(item, efx_spec,
+						     EFX_IPPROTO_GRE, error);
+	if (rc != 0)
+		return rc;
+
+	efx_spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_NVGRE;
+	efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
+
+	if (spec == NULL)
+		return 0;
+
+	rc = sfc_flow_set_efx_spec_vni_or_vsid(efx_spec, spec->tni,
+					       mask->tni, item, error);
+
+	return rc;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -872,6 +931,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_START_LAYER,
 		.parse = sfc_flow_parse_vxlan,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_NVGRE,
+		.prev_layer = SFC_FLOW_ITEM_L3,
+		.layer = SFC_FLOW_ITEM_START_LAYER,
+		.parse = sfc_flow_parse_nvgre,
+	},
 };
 
 /*
@@ -980,6 +1045,7 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 			break;
 
 		case RTE_FLOW_ITEM_TYPE_VXLAN:
+		case RTE_FLOW_ITEM_TYPE_NVGRE:
 			if (is_ifrm) {
 				rte_flow_error_set(error, EINVAL,
 					RTE_FLOW_ERROR_TYPE_ITEM,
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 07/14] net/sfc: add GENEVE in flow API filters support
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (5 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 06/14] net/sfc: add NVGRE " Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 08/14] net/sfc: add inner frame ETH " Andrew Rybchenko
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Exact match of virtual network identifier is supported by parser.
IP protocol match are enforced to UDP.
Only Ethernet protocol type is supported.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  3 ++
 drivers/net/sfc/sfc_flow.c  | 80 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 05dacb3..943fe55 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -168,6 +168,9 @@ Supported pattern items:
 
 - VXLAN (exact match of VXLAN network identifier)
 
+- GENEVE (exact match of virtual network identifier, only Ethernet (0x6558)
+  protocol type is supported)
+
 - NVGRE (exact match of virtual subnet ID)
 
 Supported actions:
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 126ec9b..efdc664 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -58,6 +58,7 @@ static sfc_flow_item_parse sfc_flow_parse_ipv6;
 static sfc_flow_item_parse sfc_flow_parse_tcp;
 static sfc_flow_item_parse sfc_flow_parse_udp;
 static sfc_flow_item_parse sfc_flow_parse_vxlan;
+static sfc_flow_item_parse sfc_flow_parse_geneve;
 static sfc_flow_item_parse sfc_flow_parse_nvgre;
 
 static boolean_t
@@ -717,7 +718,7 @@ sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
 			rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_ITEM, item,
 				"Outer IP header protocol must be UDP "
-				"in VxLAN pattern");
+				"in VxLAN/GENEVE pattern");
 			return -rte_errno;
 
 		case EFX_IPPROTO_GRE:
@@ -730,7 +731,7 @@ sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
 		default:
 			rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_ITEM, item,
-				"Only VxLAN/NVGRE tunneling patterns "
+				"Only VxLAN/GENEVE/NVGRE tunneling patterns "
 				"are supported");
 			return -rte_errno;
 		}
@@ -832,6 +833,74 @@ sfc_flow_parse_vxlan(const struct rte_flow_item *item,
 }
 
 /**
+ * Convert GENEVE item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only Virtual Network Identifier and protocol type
+ *   fields are supported. But protocol type can be only Ethernet (0x6558).
+ *   If the mask is NULL, default mask will be used.
+ *   Ranging is not supported.
+ * @param efx_spec[in, out]
+ *   EFX filter specification to update.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_parse_geneve(const struct rte_flow_item *item,
+		      efx_filter_spec_t *efx_spec,
+		      struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_geneve *spec = NULL;
+	const struct rte_flow_item_geneve *mask = NULL;
+	const struct rte_flow_item_geneve supp_mask = {
+		.protocol = RTE_BE16(0xffff),
+		.vni = { 0xff, 0xff, 0xff }
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_geneve_mask,
+				 sizeof(struct rte_flow_item_geneve),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	rc = sfc_flow_set_match_flags_for_encap_pkts(item, efx_spec,
+						     EFX_IPPROTO_UDP, error);
+	if (rc != 0)
+		return rc;
+
+	efx_spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_GENEVE;
+	efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
+
+	if (spec == NULL)
+		return 0;
+
+	if (mask->protocol == supp_mask.protocol) {
+		if (spec->protocol != rte_cpu_to_be_16(ETHER_TYPE_TEB)) {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"GENEVE encap. protocol must be Ethernet "
+				"(0x6558) in the GENEVE pattern item");
+			return -rte_errno;
+		}
+	} else if (mask->protocol != 0) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Unsupported mask for GENEVE encap. protocol");
+		return -rte_errno;
+	}
+
+	rc = sfc_flow_set_efx_spec_vni_or_vsid(efx_spec, spec->vni,
+					       mask->vni, item, error);
+
+	return rc;
+}
+
+/**
  * Convert NVGRE item to EFX filter specification.
  *
  * @param item[in]
@@ -932,6 +1001,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.parse = sfc_flow_parse_vxlan,
 	},
 	{
+		.type = RTE_FLOW_ITEM_TYPE_GENEVE,
+		.prev_layer = SFC_FLOW_ITEM_L4,
+		.layer = SFC_FLOW_ITEM_START_LAYER,
+		.parse = sfc_flow_parse_geneve,
+	},
+	{
 		.type = RTE_FLOW_ITEM_TYPE_NVGRE,
 		.prev_layer = SFC_FLOW_ITEM_L3,
 		.layer = SFC_FLOW_ITEM_START_LAYER,
@@ -1045,6 +1120,7 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 			break;
 
 		case RTE_FLOW_ITEM_TYPE_VXLAN:
+		case RTE_FLOW_ITEM_TYPE_GENEVE:
 		case RTE_FLOW_ITEM_TYPE_NVGRE:
 			if (is_ifrm) {
 				rte_flow_error_set(error, EINVAL,
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 08/14] net/sfc: add inner frame ETH in flow API filters support
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (6 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 07/14] net/sfc: add GENEVE " Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 09/14] net/sfc: add infrastructure to make many filters from flow Andrew Rybchenko
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Support destination MAC address match in inner frames.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  4 ++-
 drivers/net/sfc/sfc_flow.c  | 73 +++++++++++++++++++++++++++++++++++----------
 2 files changed, 61 insertions(+), 16 deletions(-)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 943fe55..539ce90 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -152,7 +152,9 @@ Supported pattern items:
 - VOID
 
 - ETH (exact match of source/destination addresses, individual/group match
-  of destination address, EtherType)
+  of destination address, EtherType in the outer frame and exact match of
+  destination addresses, individual/group match of destination address in
+  the inner frame)
 
 - VLAN (exact match of VID, double-tagging is supported)
 
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index efdc664..c942a36 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -187,11 +187,11 @@ sfc_flow_parse_void(__rte_unused const struct rte_flow_item *item,
  * Convert Ethernet item to EFX filter specification.
  *
  * @param item[in]
- *   Item specification. Only source and destination addresses and
- *   Ethernet type fields are supported. In addition to full and
- *   empty masks of destination address, individual/group mask is
- *   also supported. If the mask is NULL, default mask will be used.
- *   Ranging is not supported.
+ *   Item specification. Outer frame specification may only comprise
+ *   source/destination addresses and Ethertype field.
+ *   Inner frame specification may contain destination address only.
+ *   There is support for individual/group mask as well as for empty and full.
+ *   If the mask is NULL, default mask will be used. Ranging is not supported.
  * @param efx_spec[in, out]
  *   EFX filter specification to update.
  * @param[out] error
@@ -210,40 +210,75 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 		.src.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
 		.type = 0xffff,
 	};
+	const struct rte_flow_item_eth ifrm_supp_mask = {
+		.dst.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+	};
 	const uint8_t ig_mask[EFX_MAC_ADDR_LEN] = {
 		0x01, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
+	const struct rte_flow_item_eth *supp_mask_p;
+	const struct rte_flow_item_eth *def_mask_p;
+	uint8_t *loc_mac = NULL;
+	boolean_t is_ifrm = (efx_spec->efs_encap_type !=
+		EFX_TUNNEL_PROTOCOL_NONE);
+
+	if (is_ifrm) {
+		supp_mask_p = &ifrm_supp_mask;
+		def_mask_p = &ifrm_supp_mask;
+		loc_mac = efx_spec->efs_ifrm_loc_mac;
+	} else {
+		supp_mask_p = &supp_mask;
+		def_mask_p = &rte_flow_item_eth_mask;
+		loc_mac = efx_spec->efs_loc_mac;
+	}
 
 	rc = sfc_flow_parse_init(item,
 				 (const void **)&spec,
 				 (const void **)&mask,
-				 &supp_mask,
-				 &rte_flow_item_eth_mask,
+				 supp_mask_p, def_mask_p,
 				 sizeof(struct rte_flow_item_eth),
 				 error);
 	if (rc != 0)
 		return rc;
 
-	/* If "spec" is not set, could be any Ethernet */
-	if (spec == NULL)
-		return 0;
+	/*
+	 * If "spec" is not set, could be any Ethernet, but for the inner frame
+	 * type of destination MAC must be set
+	 */
+	if (spec == NULL) {
+		if (is_ifrm)
+			goto fail_bad_ifrm_dst_mac;
+		else
+			return 0;
+	}
 
 	if (is_same_ether_addr(&mask->dst, &supp_mask.dst)) {
-		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
-		rte_memcpy(efx_spec->efs_loc_mac, spec->dst.addr_bytes,
+		efx_spec->efs_match_flags |= is_ifrm ?
+			EFX_FILTER_MATCH_IFRM_LOC_MAC :
+			EFX_FILTER_MATCH_LOC_MAC;
+		rte_memcpy(loc_mac, spec->dst.addr_bytes,
 			   EFX_MAC_ADDR_LEN);
 	} else if (memcmp(mask->dst.addr_bytes, ig_mask,
 			  EFX_MAC_ADDR_LEN) == 0) {
 		if (is_unicast_ether_addr(&spec->dst))
-			efx_spec->efs_match_flags |=
+			efx_spec->efs_match_flags |= is_ifrm ?
+				EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST :
 				EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
 		else
-			efx_spec->efs_match_flags |=
+			efx_spec->efs_match_flags |= is_ifrm ?
+				EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST :
 				EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
 	} else if (!is_zero_ether_addr(&mask->dst)) {
 		goto fail_bad_mask;
+	} else if (is_ifrm) {
+		goto fail_bad_ifrm_dst_mac;
 	}
 
+	/*
+	 * ifrm_supp_mask ensures that the source address and
+	 * ethertype masks are equal to zero in inner frame,
+	 * so these fields are filled in only for the outer frame
+	 */
 	if (is_same_ether_addr(&mask->src, &supp_mask.src)) {
 		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_MAC;
 		rte_memcpy(efx_spec->efs_rem_mac, spec->src.addr_bytes,
@@ -270,6 +305,13 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 			   RTE_FLOW_ERROR_TYPE_ITEM, item,
 			   "Bad mask in the ETH pattern item");
 	return -rte_errno;
+
+fail_bad_ifrm_dst_mac:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Type of destination MAC address in inner frame "
+			   "must be set");
+	return -rte_errno;
 }
 
 /**
@@ -1112,11 +1154,12 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 		}
 
 		/*
-		 * Allow only VOID pattern item in the inner frame.
+		 * Allow only VOID and ETH pattern items in the inner frame.
 		 * Also check that there is only one tunneling protocol.
 		 */
 		switch (item->type) {
 		case RTE_FLOW_ITEM_TYPE_VOID:
+		case RTE_FLOW_ITEM_TYPE_ETH:
 			break;
 
 		case RTE_FLOW_ITEM_TYPE_VXLAN:
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 09/14] net/sfc: add infrastructure to make many filters from flow
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (7 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 08/14] net/sfc: add inner frame ETH " Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 10/14] net/sfc: multiply of specs with an unknown EtherType Andrew Rybchenko
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Not all flow rules can be expressed in one hardware filter, so some flow
rules have to be expressed in terms of multiple hardware filters. This
patch provides a means to produce a filter spec template from the flow
rule which then can be used to produce a set of fully elaborated specs
to be inserted.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 drivers/net/sfc/sfc_flow.c | 118 ++++++++++++++++++++++++++++++++++++---------
 drivers/net/sfc/sfc_flow.h |  19 +++++++-
 2 files changed, 114 insertions(+), 23 deletions(-)

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index c942a36..a432936 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -25,10 +25,13 @@
 
 /*
  * At now flow API is implemented in such a manner that each
- * flow rule is converted to a hardware filter.
+ * flow rule is converted to one or more hardware filters.
  * All elements of flow rule (attributes, pattern items, actions)
  * correspond to one or more fields in the efx_filter_spec_s structure
  * that is responsible for the hardware filter.
+ * If some required field is unset in the flow rule, then a handful
+ * of filter copies will be created to cover all possible values
+ * of such a field.
  */
 
 enum sfc_flow_item_layers {
@@ -1095,8 +1098,8 @@ sfc_flow_parse_attr(const struct rte_flow_attr *attr,
 		return -rte_errno;
 	}
 
-	flow->spec.efs_flags |= EFX_FILTER_FLAG_RX;
-	flow->spec.efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
+	flow->spec.template.efs_flags |= EFX_FILTER_FLAG_RX;
+	flow->spec.template.efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
 
 	return 0;
 }
@@ -1187,7 +1190,7 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 			break;
 		}
 
-		rc = item->parse(pattern, &flow->spec, error);
+		rc = item->parse(pattern, &flow->spec.template, error);
 		if (rc != 0)
 			return rc;
 
@@ -1209,7 +1212,7 @@ sfc_flow_parse_queue(struct sfc_adapter *sa,
 		return -EINVAL;
 
 	rxq = sa->rxq_info[queue->index].rxq;
-	flow->spec.efs_dmaq_id = (uint16_t)rxq->hw_index;
+	flow->spec.template.efs_dmaq_id = (uint16_t)rxq->hw_index;
 
 	return 0;
 }
@@ -1285,13 +1288,57 @@ sfc_flow_parse_rss(struct sfc_adapter *sa,
 #endif /* EFSYS_OPT_RX_SCALE */
 
 static int
+sfc_flow_spec_flush(struct sfc_adapter *sa, struct sfc_flow_spec *spec,
+		    unsigned int filters_count)
+{
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < filters_count; i++) {
+		int rc;
+
+		rc = efx_filter_remove(sa->nic, &spec->filters[i]);
+		if (ret == 0 && rc != 0) {
+			sfc_err(sa, "failed to remove filter specification "
+				"(rc = %d)", rc);
+			ret = rc;
+		}
+	}
+
+	return ret;
+}
+
+static int
+sfc_flow_spec_insert(struct sfc_adapter *sa, struct sfc_flow_spec *spec)
+{
+	unsigned int i;
+	int rc = 0;
+
+	for (i = 0; i < spec->count; i++) {
+		rc = efx_filter_insert(sa->nic, &spec->filters[i]);
+		if (rc != 0) {
+			sfc_flow_spec_flush(sa, spec, i);
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int
+sfc_flow_spec_remove(struct sfc_adapter *sa, struct sfc_flow_spec *spec)
+{
+	return sfc_flow_spec_flush(sa, spec, spec->count);
+}
+
+static int
 sfc_flow_filter_insert(struct sfc_adapter *sa,
 		       struct rte_flow *flow)
 {
-	efx_filter_spec_t *spec = &flow->spec;
-
 #if EFSYS_OPT_RX_SCALE
 	struct sfc_flow_rss *rss = &flow->rss_conf;
+	uint32_t efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
+	unsigned int i;
 	int rc = 0;
 
 	if (flow->rss) {
@@ -1302,27 +1349,38 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
 		rc = efx_rx_scale_context_alloc(sa->nic,
 						EFX_RX_SCALE_EXCLUSIVE,
 						rss_spread,
-						&spec->efs_rss_context);
+						&efs_rss_context);
 		if (rc != 0)
 			goto fail_scale_context_alloc;
 
-		rc = efx_rx_scale_mode_set(sa->nic, spec->efs_rss_context,
+		rc = efx_rx_scale_mode_set(sa->nic, efs_rss_context,
 					   EFX_RX_HASHALG_TOEPLITZ,
 					   rss->rss_hash_types, B_TRUE);
 		if (rc != 0)
 			goto fail_scale_mode_set;
 
-		rc = efx_rx_scale_key_set(sa->nic, spec->efs_rss_context,
+		rc = efx_rx_scale_key_set(sa->nic, efs_rss_context,
 					  rss->rss_key,
 					  sizeof(sa->rss_key));
 		if (rc != 0)
 			goto fail_scale_key_set;
 
-		spec->efs_dmaq_id = rss->rxq_hw_index_min;
-		spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS;
+		/*
+		 * At this point, fully elaborated filter specifications
+		 * have been produced from the template. To make sure that
+		 * RSS behaviour is consistent between them, set the same
+		 * RSS context value everywhere.
+		 */
+		for (i = 0; i < flow->spec.count; i++) {
+			efx_filter_spec_t *spec = &flow->spec.filters[i];
+
+			spec->efs_rss_context = efs_rss_context;
+			spec->efs_dmaq_id = rss->rxq_hw_index_min;
+			spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS;
+		}
 	}
 
-	rc = efx_filter_insert(sa->nic, spec);
+	rc = sfc_flow_spec_insert(sa, &flow->spec);
 	if (rc != 0)
 		goto fail_filter_insert;
 
@@ -1335,7 +1393,7 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
 		 * the HW knows all the information needed to verify
 		 * the table entries, and the operation will succeed
 		 */
-		rc = efx_rx_scale_tbl_set(sa->nic, spec->efs_rss_context,
+		rc = efx_rx_scale_tbl_set(sa->nic, efs_rss_context,
 					  rss->rss_tbl, RTE_DIM(rss->rss_tbl));
 		if (rc != 0)
 			goto fail_scale_tbl_set;
@@ -1344,18 +1402,18 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
 	return 0;
 
 fail_scale_tbl_set:
-	efx_filter_remove(sa->nic, spec);
+	sfc_flow_spec_remove(sa, &flow->spec);
 
 fail_filter_insert:
 fail_scale_key_set:
 fail_scale_mode_set:
-	if (flow->rss)
-		efx_rx_scale_context_free(sa->nic, spec->efs_rss_context);
+	if (efs_rss_context != EFX_RSS_CONTEXT_DEFAULT)
+		efx_rx_scale_context_free(sa->nic, efs_rss_context);
 
 fail_scale_context_alloc:
 	return rc;
 #else /* !EFSYS_OPT_RX_SCALE */
-	return efx_filter_insert(sa->nic, spec);
+	return sfc_flow_spec_insert(sa, &flow->spec);
 #endif /* EFSYS_OPT_RX_SCALE */
 }
 
@@ -1363,16 +1421,23 @@ static int
 sfc_flow_filter_remove(struct sfc_adapter *sa,
 		       struct rte_flow *flow)
 {
-	efx_filter_spec_t *spec = &flow->spec;
 	int rc = 0;
 
-	rc = efx_filter_remove(sa->nic, spec);
+	rc = sfc_flow_spec_remove(sa, &flow->spec);
 	if (rc != 0)
 		return rc;
 
 #if EFSYS_OPT_RX_SCALE
-	if (flow->rss)
+	if (flow->rss) {
+		/*
+		 * All specifications for a given flow rule have the same RSS
+		 * context, so that RSS context value is taken from the first
+		 * filter specification
+		 */
+		efx_filter_spec_t *spec = &flow->spec.filters[0];
+
 		rc = efx_rx_scale_context_free(sa->nic, spec->efs_rss_context);
+	}
 #endif /* EFSYS_OPT_RX_SCALE */
 
 	return rc;
@@ -1452,6 +1517,8 @@ sfc_flow_parse(struct rte_eth_dev *dev,
 	       struct rte_flow_error *error)
 {
 	struct sfc_adapter *sa = dev->data->dev_private;
+	efx_filter_match_flags_t match_flags =
+		flow->spec.template.efs_match_flags;
 	int rc;
 
 	rc = sfc_flow_parse_attr(attr, flow, error);
@@ -1466,13 +1533,20 @@ sfc_flow_parse(struct rte_eth_dev *dev,
 	if (rc != 0)
 		goto fail_bad_value;
 
-	if (!sfc_filter_is_match_supported(sa, flow->spec.efs_match_flags)) {
+	if (!sfc_filter_is_match_supported(sa, match_flags)) {
 		rte_flow_error_set(error, ENOTSUP,
 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 				   "Flow rule pattern is not supported");
 		return -rte_errno;
 	}
 
+	/*
+	 * At this point, template specification simply becomes the first
+	 * fully elaborated spec
+	 */
+	flow->spec.filters[0] = flow->spec.template;
+	flow->spec.count = 1;
+
 fail_bad_value:
 	return rc;
 }
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 35472ad..634c310 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -19,6 +19,13 @@
 extern "C" {
 #endif
 
+/*
+ * The maximum number of fully elaborated hardware filter specifications
+ * which can be produced from a template by means of multiplication, if
+ * missing match flags are needed to be taken into account
+ */
+#define SF_FLOW_SPEC_NB_FILTERS_MAX 1
+
 #if EFSYS_OPT_RX_SCALE
 /* RSS configuration storage */
 struct sfc_flow_rss {
@@ -30,9 +37,19 @@ struct sfc_flow_rss {
 };
 #endif /* EFSYS_OPT_RX_SCALE */
 
+/* Filter specification storage */
+struct sfc_flow_spec {
+	/* partial specification from flow rule */
+	efx_filter_spec_t template;
+	/* fully elaborated hardware filters specifications */
+	efx_filter_spec_t filters[SF_FLOW_SPEC_NB_FILTERS_MAX];
+	/* number of complete specifications */
+	unsigned int count;
+};
+
 /* PMD-specific definition of the opaque type from rte_flow.h */
 struct rte_flow {
-	efx_filter_spec_t spec;		/* filter specification */
+	struct sfc_flow_spec spec;	/* flow spec for hardware filter(s) */
 #if EFSYS_OPT_RX_SCALE
 	boolean_t rss;			/* RSS toggle */
 	struct sfc_flow_rss rss_conf;	/* RSS configuration */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 10/14] net/sfc: multiply of specs with an unknown EtherType
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (8 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 09/14] net/sfc: add infrastructure to make many filters from flow Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 11/14] net/sfc: multiply of specs w/o inner frame destination MAC Andrew Rybchenko
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Hardware filter specification for encapsulated traffic must contain
EtherType. In terms of RTE flow API, this would require L3 item to be
used in the flow rule. In the simplest case, if the user needs to filter
encapsulated traffic without knowledge of exact EtherType, they will
have to create multiple variants of the flow rule featuring all possible
L3 items (IPv4, IPv6), respectively. In order to hide the gory details
and avoid such a complication, this patch implements a mechanism to
auto-complete the filter specifications if need be.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 drivers/net/sfc/sfc_flow.c | 306 +++++++++++++++++++++++++++++++++++++++------
 drivers/net/sfc/sfc_flow.h |   2 +-
 2 files changed, 266 insertions(+), 42 deletions(-)

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index a432936..244fcdb 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -64,6 +64,21 @@ static sfc_flow_item_parse sfc_flow_parse_vxlan;
 static sfc_flow_item_parse sfc_flow_parse_geneve;
 static sfc_flow_item_parse sfc_flow_parse_nvgre;
 
+typedef int (sfc_flow_spec_set_vals)(struct sfc_flow_spec *spec,
+				     unsigned int filters_count_for_one_val,
+				     struct rte_flow_error *error);
+
+struct sfc_flow_copy_flag {
+	/* EFX filter specification match flag */
+	efx_filter_match_flags_t flag;
+	/* Number of values of corresponding field */
+	unsigned int vals_count;
+	/* Function to set values in specifications */
+	sfc_flow_spec_set_vals *set_vals;
+};
+
+static sfc_flow_spec_set_vals sfc_flow_set_ethertypes;
+
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
 {
@@ -244,16 +259,9 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 	if (rc != 0)
 		return rc;
 
-	/*
-	 * If "spec" is not set, could be any Ethernet, but for the inner frame
-	 * type of destination MAC must be set
-	 */
-	if (spec == NULL) {
-		if (is_ifrm)
-			goto fail_bad_ifrm_dst_mac;
-		else
-			return 0;
-	}
+	/* If "spec" is not set, could be any Ethernet */
+	if (spec == NULL)
+		return 0;
 
 	if (is_same_ether_addr(&mask->dst, &supp_mask.dst)) {
 		efx_spec->efs_match_flags |= is_ifrm ?
@@ -273,8 +281,6 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 				EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
 	} else if (!is_zero_ether_addr(&mask->dst)) {
 		goto fail_bad_mask;
-	} else if (is_ifrm) {
-		goto fail_bad_ifrm_dst_mac;
 	}
 
 	/*
@@ -308,13 +314,6 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 			   RTE_FLOW_ERROR_TYPE_ITEM, item,
 			   "Bad mask in the ETH pattern item");
 	return -rte_errno;
-
-fail_bad_ifrm_dst_mac:
-	rte_flow_error_set(error, EINVAL,
-			   RTE_FLOW_ERROR_TYPE_ITEM, item,
-			   "Type of destination MAC address in inner frame "
-			   "must be set");
-	return -rte_errno;
 }
 
 /**
@@ -782,14 +781,9 @@ sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
 		}
 	}
 
-	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM, item,
-			"Outer frame EtherType in pattern with tunneling "
-			"must be set");
-		return -rte_errno;
-	} else if (efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4 &&
-		   efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV6) {
+	if (efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE &&
+	    efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4 &&
+	    efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV6) {
 		rte_flow_error_set(error, EINVAL,
 			RTE_FLOW_ERROR_TYPE_ITEM, item,
 			"Outer frame EtherType in pattern with tunneling "
@@ -1508,6 +1502,246 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
 	return 0;
 }
 
+/**
+ * Set the EFX_FILTER_MATCH_ETHER_TYPE match flag and EFX_ETHER_TYPE_IPV4 and
+ * EFX_ETHER_TYPE_IPV6 values of the corresponding field in the same
+ * specifications after copying.
+ *
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param filters_count_for_one_val[in]
+ *   How many specifications should have the same EtherType value, what is the
+ *   number of specifications before copying.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_set_ethertypes(struct sfc_flow_spec *spec,
+			unsigned int filters_count_for_one_val,
+			struct rte_flow_error *error)
+{
+	unsigned int i;
+	static const uint16_t vals[] = {
+		EFX_ETHER_TYPE_IPV4, EFX_ETHER_TYPE_IPV6
+	};
+
+	if (filters_count_for_one_val * RTE_DIM(vals) != spec->count) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Number of specifications is incorrect "
+			"while copying by Ethertype");
+		return -rte_errno;
+	}
+
+	for (i = 0; i < spec->count; i++) {
+		spec->filters[i].efs_match_flags |=
+			EFX_FILTER_MATCH_ETHER_TYPE;
+
+		/*
+		 * The check above ensures that
+		 * filters_count_for_one_val is not 0
+		 */
+		spec->filters[i].efs_ether_type =
+			vals[i / filters_count_for_one_val];
+	}
+
+	return 0;
+}
+
+/* Match flags that can be automatically added to filters */
+static const struct sfc_flow_copy_flag sfc_flow_copy_flags[] = {
+	{
+		.flag = EFX_FILTER_MATCH_ETHER_TYPE,
+		.vals_count = 2,
+		.set_vals = sfc_flow_set_ethertypes,
+	},
+};
+
+/* Get item from array sfc_flow_copy_flags */
+static const struct sfc_flow_copy_flag *
+sfc_flow_get_copy_flag(efx_filter_match_flags_t flag)
+{
+	unsigned int i;
+
+	for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
+		if (sfc_flow_copy_flags[i].flag == flag)
+			return &sfc_flow_copy_flags[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * Make copies of the specifications, set match flag and values
+ * of the field that corresponds to it.
+ *
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param flag[in]
+ *   The match flag to add.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_spec_add_match_flag(struct sfc_flow_spec *spec,
+			     efx_filter_match_flags_t flag,
+			     struct rte_flow_error *error)
+{
+	unsigned int i;
+	unsigned int new_filters_count;
+	unsigned int filters_count_for_one_val;
+	const struct sfc_flow_copy_flag *copy_flag;
+	int rc;
+
+	copy_flag = sfc_flow_get_copy_flag(flag);
+	if (copy_flag == NULL) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Unsupported spec field for copying");
+		return -rte_errno;
+	}
+
+	new_filters_count = spec->count * copy_flag->vals_count;
+	if (new_filters_count > SF_FLOW_SPEC_NB_FILTERS_MAX) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Too much EFX specifications in the flow rule");
+		return -rte_errno;
+	}
+
+	/* Copy filters specifications */
+	for (i = spec->count; i < new_filters_count; i++)
+		spec->filters[i] = spec->filters[i - spec->count];
+
+	filters_count_for_one_val = spec->count;
+	spec->count = new_filters_count;
+
+	rc = copy_flag->set_vals(spec, filters_count_for_one_val, error);
+	if (rc != 0)
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Check that the given set of match flags missing in the original filter spec
+ * could be covered by adding spec copies which specify the corresponding
+ * flags and packet field values to match.
+ *
+ * @param miss_flags[in]
+ *   Flags that are missing until the supported filter.
+ *
+ * @return
+ *   Number of specifications after copy or 0, if the flags can not be added.
+ */
+static unsigned int
+sfc_flow_check_missing_flags(efx_filter_match_flags_t miss_flags)
+{
+	unsigned int i;
+	efx_filter_match_flags_t copy_flags = 0;
+	efx_filter_match_flags_t flag;
+	unsigned int multiplier = 1;
+
+	for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
+		flag = sfc_flow_copy_flags[i].flag;
+		if ((flag & miss_flags) == flag) {
+			copy_flags |= flag;
+			multiplier *= sfc_flow_copy_flags[i].vals_count;
+		}
+	}
+
+	if (copy_flags == miss_flags)
+		return multiplier;
+
+	return 0;
+}
+
+/**
+ * Attempt to supplement the specification template to the minimally
+ * supported set of match flags. To do this, it is necessary to copy
+ * the specifications, filling them with the values of fields that
+ * correspond to the missing flags.
+ * The necessary and sufficient filter is built from the fewest number
+ * of copies which could be made to cover the minimally required set
+ * of flags.
+ *
+ * @param sa[in]
+ *   SFC adapter.
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_spec_filters_complete(struct sfc_adapter *sa,
+			       struct sfc_flow_spec *spec,
+			       struct rte_flow_error *error)
+{
+	struct sfc_filter *filter = &sa->filter;
+	efx_filter_match_flags_t miss_flags;
+	efx_filter_match_flags_t min_miss_flags = 0;
+	efx_filter_match_flags_t match;
+	unsigned int min_multiplier = UINT_MAX;
+	unsigned int multiplier;
+	unsigned int i;
+	int rc;
+
+	match = spec->template.efs_match_flags;
+	for (i = 0; i < filter->supported_match_num; i++) {
+		if ((match & filter->supported_match[i]) == match) {
+			miss_flags = filter->supported_match[i] & (~match);
+			multiplier = sfc_flow_check_missing_flags(miss_flags);
+			if (multiplier > 0) {
+				if (multiplier <= min_multiplier) {
+					min_multiplier = multiplier;
+					min_miss_flags = miss_flags;
+				}
+			}
+		}
+	}
+
+	if (min_multiplier == UINT_MAX) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Flow rule pattern is not supported");
+		return -rte_errno;
+	}
+
+	for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
+		efx_filter_match_flags_t flag = sfc_flow_copy_flags[i].flag;
+
+		if ((flag & min_miss_flags) == flag) {
+			rc = sfc_flow_spec_add_match_flag(spec, flag, error);
+			if (rc != 0)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int
+sfc_flow_validate_match_flags(struct sfc_adapter *sa,
+			      struct rte_flow *flow,
+			      struct rte_flow_error *error)
+{
+	efx_filter_spec_t *spec_tmpl = &flow->spec.template;
+	efx_filter_match_flags_t match_flags = spec_tmpl->efs_match_flags;
+	int rc;
+
+	/* Initialize the first filter spec with template */
+	flow->spec.filters[0] = *spec_tmpl;
+	flow->spec.count = 1;
+
+	if (!sfc_filter_is_match_supported(sa, match_flags)) {
+		rc = sfc_flow_spec_filters_complete(sa, &flow->spec, error);
+		if (rc != 0)
+			return rc;
+	}
+
+	return 0;
+}
+
 static int
 sfc_flow_parse(struct rte_eth_dev *dev,
 	       const struct rte_flow_attr *attr,
@@ -1517,8 +1751,6 @@ sfc_flow_parse(struct rte_eth_dev *dev,
 	       struct rte_flow_error *error)
 {
 	struct sfc_adapter *sa = dev->data->dev_private;
-	efx_filter_match_flags_t match_flags =
-		flow->spec.template.efs_match_flags;
 	int rc;
 
 	rc = sfc_flow_parse_attr(attr, flow, error);
@@ -1533,19 +1765,11 @@ sfc_flow_parse(struct rte_eth_dev *dev,
 	if (rc != 0)
 		goto fail_bad_value;
 
-	if (!sfc_filter_is_match_supported(sa, match_flags)) {
-		rte_flow_error_set(error, ENOTSUP,
-				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				   "Flow rule pattern is not supported");
-		return -rte_errno;
-	}
+	rc = sfc_flow_validate_match_flags(sa, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
 
-	/*
-	 * At this point, template specification simply becomes the first
-	 * fully elaborated spec
-	 */
-	flow->spec.filters[0] = flow->spec.template;
-	flow->spec.count = 1;
+	return 0;
 
 fail_bad_value:
 	return rc;
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 634c310..c4302c7 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -24,7 +24,7 @@ extern "C" {
  * which can be produced from a template by means of multiplication, if
  * missing match flags are needed to be taken into account
  */
-#define SF_FLOW_SPEC_NB_FILTERS_MAX 1
+#define SF_FLOW_SPEC_NB_FILTERS_MAX 2
 
 #if EFSYS_OPT_RX_SCALE
 /* RSS configuration storage */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 11/14] net/sfc: multiply of specs w/o inner frame destination MAC
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (9 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 10/14] net/sfc: multiply of specs with an unknown EtherType Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 12/14] net/sfc: multiply of specs with an unknown " Andrew Rybchenko
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Knowledge of a network identifier is not sufficient to construct a
workable hardware filter for encapsulated traffic. It's obligatory to
specify one of the match flags associated with inner frame destination
MAC. If the address is unknown, then one needs to specify either unknown
unicast or unknown multicast destination match flag.

In terms of RTE flow API, this would require adding multiple flow rules
with corresponding ETH items besides the tunnel item. In order to avoid
such a complication, the patch implements a mechanism to auto-complete
an underlying filter representation of a flow rule in order to create
additional filter specififcations featuring the missing match flags.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 drivers/net/sfc/sfc_flow.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/sfc/sfc_flow.h |   2 +-
 2 files changed, 113 insertions(+), 3 deletions(-)

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 244fcdb..2d45827 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -68,6 +68,10 @@ typedef int (sfc_flow_spec_set_vals)(struct sfc_flow_spec *spec,
 				     unsigned int filters_count_for_one_val,
 				     struct rte_flow_error *error);
 
+typedef boolean_t (sfc_flow_spec_check)(efx_filter_match_flags_t match,
+					efx_filter_spec_t *spec,
+					struct sfc_filter *filter);
+
 struct sfc_flow_copy_flag {
 	/* EFX filter specification match flag */
 	efx_filter_match_flags_t flag;
@@ -75,9 +79,16 @@ struct sfc_flow_copy_flag {
 	unsigned int vals_count;
 	/* Function to set values in specifications */
 	sfc_flow_spec_set_vals *set_vals;
+	/*
+	 * Function to check that the specification is suitable
+	 * for adding this match flag
+	 */
+	sfc_flow_spec_check *spec_check;
 };
 
 static sfc_flow_spec_set_vals sfc_flow_set_ethertypes;
+static sfc_flow_spec_set_vals sfc_flow_set_ifrm_unknown_dst_flags;
+static sfc_flow_spec_check sfc_flow_check_ifrm_unknown_dst_flags;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -1548,12 +1559,98 @@ sfc_flow_set_ethertypes(struct sfc_flow_spec *spec,
 	return 0;
 }
 
+/**
+ * Set the EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST and
+ * EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST match flags in the same
+ * specifications after copying.
+ *
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param filters_count_for_one_val[in]
+ *   How many specifications should have the same match flag, what is the
+ *   number of specifications before copying.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_set_ifrm_unknown_dst_flags(struct sfc_flow_spec *spec,
+				    unsigned int filters_count_for_one_val,
+				    struct rte_flow_error *error)
+{
+	unsigned int i;
+	static const efx_filter_match_flags_t vals[] = {
+		EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST,
+		EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST
+	};
+
+	if (filters_count_for_one_val * RTE_DIM(vals) != spec->count) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Number of specifications is incorrect while copying "
+			"by inner frame unknown destination flags");
+		return -rte_errno;
+	}
+
+	for (i = 0; i < spec->count; i++) {
+		/* The check above ensures that divisor can't be zero here */
+		spec->filters[i].efs_match_flags |=
+			vals[i / filters_count_for_one_val];
+	}
+
+	return 0;
+}
+
+/**
+ * Check that the following conditions are met:
+ * - the specification corresponds to a filter for encapsulated traffic
+ * - the list of supported filters has a filter
+ *   with EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST flag instead of
+ *   EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST, since this filter will also
+ *   be inserted.
+ *
+ * @param match[in]
+ *   The match flags of filter.
+ * @param spec[in]
+ *   Specification to be supplemented.
+ * @param filter[in]
+ *   SFC filter with list of supported filters.
+ */
+static boolean_t
+sfc_flow_check_ifrm_unknown_dst_flags(efx_filter_match_flags_t match,
+				      efx_filter_spec_t *spec,
+				      struct sfc_filter *filter)
+{
+	unsigned int i;
+	efx_tunnel_protocol_t encap_type = spec->efs_encap_type;
+	efx_filter_match_flags_t match_mcast_dst;
+
+	if (encap_type == EFX_TUNNEL_PROTOCOL_NONE)
+		return B_FALSE;
+
+	match_mcast_dst =
+		(match & ~EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST) |
+		EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
+	for (i = 0; i < filter->supported_match_num; i++) {
+		if (match_mcast_dst == filter->supported_match[i])
+			return B_TRUE;
+	}
+
+	return B_FALSE;
+}
+
 /* Match flags that can be automatically added to filters */
 static const struct sfc_flow_copy_flag sfc_flow_copy_flags[] = {
 	{
 		.flag = EFX_FILTER_MATCH_ETHER_TYPE,
 		.vals_count = 2,
 		.set_vals = sfc_flow_set_ethertypes,
+		.spec_check = NULL,
+	},
+	{
+		.flag = EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST,
+		.vals_count = 2,
+		.set_vals = sfc_flow_set_ifrm_unknown_dst_flags,
+		.spec_check = sfc_flow_check_ifrm_unknown_dst_flags,
 	},
 };
 
@@ -1630,21 +1727,33 @@ sfc_flow_spec_add_match_flag(struct sfc_flow_spec *spec,
  *
  * @param miss_flags[in]
  *   Flags that are missing until the supported filter.
+ * @param spec[in]
+ *   Specification to be supplemented.
+ * @param filter[in]
+ *   SFC filter.
  *
  * @return
  *   Number of specifications after copy or 0, if the flags can not be added.
  */
 static unsigned int
-sfc_flow_check_missing_flags(efx_filter_match_flags_t miss_flags)
+sfc_flow_check_missing_flags(efx_filter_match_flags_t miss_flags,
+			     efx_filter_spec_t *spec,
+			     struct sfc_filter *filter)
 {
 	unsigned int i;
 	efx_filter_match_flags_t copy_flags = 0;
 	efx_filter_match_flags_t flag;
+	efx_filter_match_flags_t match = spec->efs_match_flags | miss_flags;
+	sfc_flow_spec_check *check;
 	unsigned int multiplier = 1;
 
 	for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
 		flag = sfc_flow_copy_flags[i].flag;
+		check = sfc_flow_copy_flags[i].spec_check;
 		if ((flag & miss_flags) == flag) {
+			if (check != NULL && (!check(match, spec, filter)))
+				continue;
+
 			copy_flags |= flag;
 			multiplier *= sfc_flow_copy_flags[i].vals_count;
 		}
@@ -1690,7 +1799,8 @@ sfc_flow_spec_filters_complete(struct sfc_adapter *sa,
 	for (i = 0; i < filter->supported_match_num; i++) {
 		if ((match & filter->supported_match[i]) == match) {
 			miss_flags = filter->supported_match[i] & (~match);
-			multiplier = sfc_flow_check_missing_flags(miss_flags);
+			multiplier = sfc_flow_check_missing_flags(miss_flags,
+				&spec->template, filter);
 			if (multiplier > 0) {
 				if (multiplier <= min_multiplier) {
 					min_multiplier = multiplier;
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index c4302c7..2b287dd 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -24,7 +24,7 @@ extern "C" {
  * which can be produced from a template by means of multiplication, if
  * missing match flags are needed to be taken into account
  */
-#define SF_FLOW_SPEC_NB_FILTERS_MAX 2
+#define SF_FLOW_SPEC_NB_FILTERS_MAX 4
 
 #if EFSYS_OPT_RX_SCALE
 /* RSS configuration storage */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 12/14] net/sfc: multiply of specs with an unknown destination MAC
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (10 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 11/14] net/sfc: multiply of specs w/o inner frame destination MAC Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 13/14] net/sfc: avoid creation of ineffective flow rules Andrew Rybchenko
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

To filter all traffic, need to create two hardware filter specifications
with both unknown unicast and unknown multicast destination MAC address
match flags.

In terms of RTE flow API, this would require adding multiple flow rules
with corresponding ETH items. In order to avoid such a complication, the
patch implements a mechanism to auto-complete an underlying filter
representation of a flow rule in order to create additional filter
specififcations featuring the missing match flags.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 drivers/net/sfc/sfc_flow.c | 91 +++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/sfc/sfc_flow.h |  2 +-
 2 files changed, 91 insertions(+), 2 deletions(-)

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 2d45827..7b26653 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -86,6 +86,8 @@ struct sfc_flow_copy_flag {
 	sfc_flow_spec_check *spec_check;
 };
 
+static sfc_flow_spec_set_vals sfc_flow_set_unknown_dst_flags;
+static sfc_flow_spec_check sfc_flow_check_unknown_dst_flags;
 static sfc_flow_spec_set_vals sfc_flow_set_ethertypes;
 static sfc_flow_spec_set_vals sfc_flow_set_ifrm_unknown_dst_flags;
 static sfc_flow_spec_check sfc_flow_check_ifrm_unknown_dst_flags;
@@ -1514,6 +1516,80 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
 }
 
 /**
+ * Set the EFX_FILTER_MATCH_UNKNOWN_UCAST_DST
+ * and EFX_FILTER_MATCH_UNKNOWN_MCAST_DST match flags in the same
+ * specifications after copying.
+ *
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param filters_count_for_one_val[in]
+ *   How many specifications should have the same match flag, what is the
+ *   number of specifications before copying.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_set_unknown_dst_flags(struct sfc_flow_spec *spec,
+			       unsigned int filters_count_for_one_val,
+			       struct rte_flow_error *error)
+{
+	unsigned int i;
+	static const efx_filter_match_flags_t vals[] = {
+		EFX_FILTER_MATCH_UNKNOWN_UCAST_DST,
+		EFX_FILTER_MATCH_UNKNOWN_MCAST_DST
+	};
+
+	if (filters_count_for_one_val * RTE_DIM(vals) != spec->count) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Number of specifications is incorrect while copying "
+			"by unknown destination flags");
+		return -rte_errno;
+	}
+
+	for (i = 0; i < spec->count; i++) {
+		/* The check above ensures that divisor can't be zero here */
+		spec->filters[i].efs_match_flags |=
+			vals[i / filters_count_for_one_val];
+	}
+
+	return 0;
+}
+
+/**
+ * Check that the following conditions are met:
+ * - the list of supported filters has a filter
+ *   with EFX_FILTER_MATCH_UNKNOWN_MCAST_DST flag instead of
+ *   EFX_FILTER_MATCH_UNKNOWN_UCAST_DST, since this filter will also
+ *   be inserted.
+ *
+ * @param match[in]
+ *   The match flags of filter.
+ * @param spec[in]
+ *   Specification to be supplemented.
+ * @param filter[in]
+ *   SFC filter with list of supported filters.
+ */
+static boolean_t
+sfc_flow_check_unknown_dst_flags(efx_filter_match_flags_t match,
+				 __rte_unused efx_filter_spec_t *spec,
+				 struct sfc_filter *filter)
+{
+	unsigned int i;
+	efx_filter_match_flags_t match_mcast_dst;
+
+	match_mcast_dst =
+		(match & ~EFX_FILTER_MATCH_UNKNOWN_UCAST_DST) |
+		EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
+	for (i = 0; i < filter->supported_match_num; i++) {
+		if (match_mcast_dst == filter->supported_match[i])
+			return B_TRUE;
+	}
+
+	return B_FALSE;
+}
+
+/**
  * Set the EFX_FILTER_MATCH_ETHER_TYPE match flag and EFX_ETHER_TYPE_IPV4 and
  * EFX_ETHER_TYPE_IPV6 values of the corresponding field in the same
  * specifications after copying.
@@ -1638,9 +1714,22 @@ sfc_flow_check_ifrm_unknown_dst_flags(efx_filter_match_flags_t match,
 	return B_FALSE;
 }
 
-/* Match flags that can be automatically added to filters */
+/*
+ * Match flags that can be automatically added to filters.
+ * Selecting the last minimum when searching for the copy flag ensures that the
+ * EFX_FILTER_MATCH_UNKNOWN_UCAST_DST flag has a higher priority than
+ * EFX_FILTER_MATCH_ETHER_TYPE. This is because the filter
+ * EFX_FILTER_MATCH_UNKNOWN_UCAST_DST is at the end of the list of supported
+ * filters.
+ */
 static const struct sfc_flow_copy_flag sfc_flow_copy_flags[] = {
 	{
+		.flag = EFX_FILTER_MATCH_UNKNOWN_UCAST_DST,
+		.vals_count = 2,
+		.set_vals = sfc_flow_set_unknown_dst_flags,
+		.spec_check = sfc_flow_check_unknown_dst_flags,
+	},
+	{
 		.flag = EFX_FILTER_MATCH_ETHER_TYPE,
 		.vals_count = 2,
 		.set_vals = sfc_flow_set_ethertypes,
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 2b287dd..69dd683 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -24,7 +24,7 @@ extern "C" {
  * which can be produced from a template by means of multiplication, if
  * missing match flags are needed to be taken into account
  */
-#define SF_FLOW_SPEC_NB_FILTERS_MAX 4
+#define SF_FLOW_SPEC_NB_FILTERS_MAX 8
 
 #if EFSYS_OPT_RX_SCALE
 /* RSS configuration storage */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 13/14] net/sfc: avoid creation of ineffective flow rules
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (11 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 12/14] net/sfc: multiply of specs with an unknown " Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 14/14] doc: add net/sfc flow API support for tunnels Andrew Rybchenko
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Despite being versatile, the hardware support for filtering has a number
of special properties which must be taken into account. Namely, there is
a known set of valid filters which don't take any effect despite being
accepted by the hardware.

The combinations of match flags and field values which can describe the
exceptional filters are as follows:
- ETHER_TYPE or ETHER_TYPE | LOC_MAC with IPv4 or IPv6 EtherType
- ETHER_TYPE | IP_PROTO or ETHER_TYPE | IP_PROTO | LOC_MAC with UDP or
TCP IP protocol value
- The same combinations with OUTER_VID and/or INNER_VID

These exceptional filters can be expressed in terms of RTE flow rules.
If the user creates such a flow rule, no traffic will hit the underlying
filter, and no errors will be reported.

This patch adds a means to prevent such ineffective flow rules from
being created.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 doc/guides/nics/sfc_efx.rst | 17 ++++++++++
 drivers/net/sfc/sfc_flow.c  | 78 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 539ce90..f41ccdb 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -193,6 +193,23 @@ in the mask of destination address. If destinaton address in the spec is
 multicast, it matches all multicast (and broadcast) packets, oherwise it
 matches unicast packets that are not filtered by other flow rules.
 
+Exceptions to flow rules
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+There is a list of exceptional flow rule patterns which will not be
+accepted by the PMD. A pattern will be rejected if at least one of the
+conditions is met:
+
+- Filtering by IPv4 or IPv6 EtherType without pattern items of internet
+  layer and above.
+
+- The last item is IPV4 or IPV6, and it's empty.
+
+- Filtering by TCP or UDP IP transport protocol without pattern items of
+  transport layer and above.
+
+- The last item is TCP or UDP, and it's empty.
+
 
 Supported NICs
 --------------
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 7b26653..2b8bef8 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -1919,6 +1919,77 @@ sfc_flow_spec_filters_complete(struct sfc_adapter *sa,
 	return 0;
 }
 
+/**
+ * Check that set of match flags is referred to by a filter. Filter is
+ * described by match flags with the ability to add OUTER_VID and INNER_VID
+ * flags.
+ *
+ * @param match_flags[in]
+ *   Set of match flags.
+ * @param flags_pattern[in]
+ *   Pattern of filter match flags.
+ */
+static boolean_t
+sfc_flow_is_match_with_vids(efx_filter_match_flags_t match_flags,
+			    efx_filter_match_flags_t flags_pattern)
+{
+	if ((match_flags & flags_pattern) != flags_pattern)
+		return B_FALSE;
+
+	switch (match_flags & ~flags_pattern) {
+	case 0:
+	case EFX_FILTER_MATCH_OUTER_VID:
+	case EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_INNER_VID:
+		return B_TRUE;
+	default:
+		return B_FALSE;
+	}
+}
+
+/**
+ * Check whether the spec maps to a hardware filter which is known to be
+ * ineffective despite being valid.
+ *
+ * @param spec[in]
+ *   SFC flow specification.
+ */
+static boolean_t
+sfc_flow_is_match_flags_exception(struct sfc_flow_spec *spec)
+{
+	unsigned int i;
+	uint16_t ether_type;
+	uint8_t ip_proto;
+	efx_filter_match_flags_t match_flags;
+
+	for (i = 0; i < spec->count; i++) {
+		match_flags = spec->filters[i].efs_match_flags;
+
+		if (sfc_flow_is_match_with_vids(match_flags,
+						EFX_FILTER_MATCH_ETHER_TYPE) ||
+		    sfc_flow_is_match_with_vids(match_flags,
+						EFX_FILTER_MATCH_ETHER_TYPE |
+						EFX_FILTER_MATCH_LOC_MAC)) {
+			ether_type = spec->filters[i].efs_ether_type;
+			if (ether_type == EFX_ETHER_TYPE_IPV4 ||
+			    ether_type == EFX_ETHER_TYPE_IPV6)
+				return B_TRUE;
+		} else if (sfc_flow_is_match_with_vids(match_flags,
+				EFX_FILTER_MATCH_ETHER_TYPE |
+				EFX_FILTER_MATCH_IP_PROTO) ||
+			   sfc_flow_is_match_with_vids(match_flags,
+				EFX_FILTER_MATCH_ETHER_TYPE |
+				EFX_FILTER_MATCH_IP_PROTO |
+				EFX_FILTER_MATCH_LOC_MAC)) {
+			ip_proto = spec->filters[i].efs_ip_proto;
+			if (ip_proto == EFX_IPPROTO_TCP ||
+			    ip_proto == EFX_IPPROTO_UDP)
+				return B_TRUE;
+		}
+	}
+
+	return B_FALSE;
+}
+
 static int
 sfc_flow_validate_match_flags(struct sfc_adapter *sa,
 			      struct rte_flow *flow,
@@ -1938,6 +2009,13 @@ sfc_flow_validate_match_flags(struct sfc_adapter *sa,
 			return rc;
 	}
 
+	if (sfc_flow_is_match_flags_exception(&flow->spec)) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"The flow rule pattern is unsupported");
+		return -rte_errno;
+	}
+
 	return 0;
 }
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH 14/14] doc: add net/sfc flow API support for tunnels
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (12 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 13/14] net/sfc: avoid creation of ineffective flow rules Andrew Rybchenko
@ 2018-02-27 12:45 ` Andrew Rybchenko
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-02-27 12:45 UTC (permalink / raw)
  To: dev

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 doc/guides/rel_notes/release_18_05.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst
index 3923dc2..894f636 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -41,6 +41,12 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Updated Solarflare network PMD.**
+
+  Updated the sfc_efx driver including the following changes:
+
+  * Added support for NVGRE, VXLAN and GENEVE filters in flow API.
+
 
 API Changes
 -----------
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [dpdk-dev] [PATCH 01/14] net/sfc/base: support filters for encapsulated packets
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 01/14] net/sfc/base: support filters for encapsulated packets Andrew Rybchenko
@ 2018-03-06 15:13   ` Andrew Rybchenko
  0 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:13 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

On 02/27/2018 03:45 PM, Andrew Rybchenko wrote:
> From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
>
> This adds filters for encapsulated packets to the list
> returned by ef10_filter_supported_filters().
>
> Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
> Reviewed-by: Andy Moreton <amoreton@solarflare.com>
> ---
>   drivers/net/sfc/base/ef10_filter.c | 65 ++++++++++++++++++++++++++++++++------
>   1 file changed, 55 insertions(+), 10 deletions(-)

<...>

> -	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length,
> -					    &mcdi_list_length);
> +	/*
> +	 * Two calls to MC_CMD_GET_PARSER_DISP_INFO are needed: one to get the
> +	 * list of supported filters for ordinary packets, and then another to
> +	 * get the list of supported filters for encapsulated packets.
> +	 */
> +	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, B_FALSE,
> +	    &mcdi_list_length);
>   	if (rc != 0) {
> -		if (rc == ENOSPC) {
> -			/* Pass through mcdi_list_length for the list length */
> -			*list_lengthp = mcdi_list_length;
> +		if (rc == ENOSPC)
> +			no_space = B_TRUE;
> +		else
> +			goto fail1;
> +	}
> +
> +	if (no_space) {
> +		next_buf_idx = 0;
> +		next_buf_length = 0;
> +	} else {
> +		EFSYS_ASSERT(mcdi_list_length < buffer_length);

In fact <= must be here since above call may return 0 if return array
fits exactly in provided buffer. I'll send v2.

> +		next_buf_idx = mcdi_list_length;
> +		next_buf_length = buffer_length - mcdi_list_length;
> +	}

<snip>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API for tunnels
  2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
                   ` (13 preceding siblings ...)
  2018-02-27 12:45 ` [dpdk-dev] [PATCH 14/14] doc: add net/sfc flow API support for tunnels Andrew Rybchenko
@ 2018-03-06 15:24 ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 01/14] net/sfc/base: support filters for encapsulated packets Andrew Rybchenko
                     ` (14 more replies)
  14 siblings, 15 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev

Update base driver and the PMD itself to support flow API
patterns for tunnels: VXLAN, NVGRE and Geneve.

Applicable to SFN8xxx NICs with full-feature firmware variant running.

Andrew Rybchenko (1):
  doc: add net/sfc flow API support for tunnels

Roman Zhukov (12):
  net/sfc/base: support filters for encapsulated packets
  net/sfc/base: support VNI/VSID and inner frame local MAC
  net/sfc/base: distinguish filters for encapsulated packets
  net/sfc: add VXLAN in flow API filters support
  net/sfc: add NVGRE in flow API filters support
  net/sfc: add GENEVE in flow API filters support
  net/sfc: add inner frame ETH in flow API filters support
  net/sfc: add infrastructure to make many filters from flow
  net/sfc: multiply of specs with an unknown EtherType
  net/sfc: multiply of specs w/o inner frame destination MAC
  net/sfc: multiply of specs with an unknown destination MAC
  net/sfc: avoid creation of ineffective flow rules

Vijay Srivastava (1):
  net/sfc/base: support VXLAN filter creation

 doc/guides/nics/sfc_efx.rst            |   28 +-
 doc/guides/rel_notes/release_18_05.rst |    6 +
 drivers/net/sfc/base/ef10_filter.c     |  100 +++-
 drivers/net/sfc/base/efx.h             |   20 +
 drivers/net/sfc/base/efx_filter.c      |   39 +-
 drivers/net/sfc/sfc_flow.c             | 1001 ++++++++++++++++++++++++++++++--
 drivers/net/sfc/sfc_flow.h             |   19 +-
 7 files changed, 1161 insertions(+), 52 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 01/14] net/sfc/base: support filters for encapsulated packets
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 02/14] net/sfc/base: support VNI/VSID and inner frame local MAC Andrew Rybchenko
                     ` (13 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

This adds filters for encapsulated packets to the list
returned by ef10_filter_supported_filters().

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
v2:
 - fix assertion

 drivers/net/sfc/base/ef10_filter.c | 65 ++++++++++++++++++++++++++++++++------
 1 file changed, 55 insertions(+), 10 deletions(-)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index 2b7a09c..8a6bc61 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -895,6 +895,7 @@ efx_mcdi_get_parser_disp_info(
 	__in				efx_nic_t *enp,
 	__out_ecount(buffer_length)	uint32_t *buffer,
 	__in				size_t buffer_length,
+	__in				boolean_t encap,
 	__out				size_t *list_lengthp)
 {
 	efx_mcdi_req_t req;
@@ -911,7 +912,8 @@ efx_mcdi_get_parser_disp_info(
 	req.emr_out_buf = payload;
 	req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX;
 
-	MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP,
+	MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, encap ?
+	    MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_ENCAP_RX_MATCHES :
 	    MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);
 
 	efx_mcdi_execute(enp, &req);
@@ -971,28 +973,66 @@ ef10_filter_supported_filters(
 	__in				size_t buffer_length,
 	__out				size_t *list_lengthp)
 {
-
+	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 	size_t mcdi_list_length;
+	size_t mcdi_encap_list_length;
 	size_t list_length;
 	uint32_t i;
+	uint32_t next_buf_idx;
+	size_t next_buf_length;
 	efx_rc_t rc;
+	boolean_t no_space = B_FALSE;
 	efx_filter_match_flags_t all_filter_flags =
 	    (EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST |
 	    EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT |
 	    EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
 	    EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID |
 	    EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO |
+	    EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
+	    EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
 	    EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
 	    EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
 
-	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length,
-					    &mcdi_list_length);
+	/*
+	 * Two calls to MC_CMD_GET_PARSER_DISP_INFO are needed: one to get the
+	 * list of supported filters for ordinary packets, and then another to
+	 * get the list of supported filters for encapsulated packets.
+	 */
+	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, B_FALSE,
+	    &mcdi_list_length);
 	if (rc != 0) {
-		if (rc == ENOSPC) {
-			/* Pass through mcdi_list_length for the list length */
-			*list_lengthp = mcdi_list_length;
+		if (rc == ENOSPC)
+			no_space = B_TRUE;
+		else
+			goto fail1;
+	}
+
+	if (no_space) {
+		next_buf_idx = 0;
+		next_buf_length = 0;
+	} else {
+		EFSYS_ASSERT(mcdi_list_length <= buffer_length);
+		next_buf_idx = mcdi_list_length;
+		next_buf_length = buffer_length - mcdi_list_length;
+	}
+
+	if (encp->enc_tunnel_encapsulations_supported != 0) {
+		rc = efx_mcdi_get_parser_disp_info(enp, &buffer[next_buf_idx],
+		    next_buf_length, B_TRUE, &mcdi_encap_list_length);
+		if (rc != 0) {
+			if (rc == ENOSPC)
+				no_space = B_TRUE;
+			else
+				goto fail2;
 		}
-		goto fail1;
+	} else {
+		mcdi_encap_list_length = 0;
+	}
+
+	if (no_space) {
+		*list_lengthp = mcdi_list_length + mcdi_encap_list_length;
+		rc = ENOSPC;
+		goto fail3;
 	}
 
 	/*
@@ -1005,9 +1045,10 @@ ef10_filter_supported_filters(
 	 * of the matches is preserved as they are ordered from highest to
 	 * lowest priority.
 	 */
-	EFSYS_ASSERT(mcdi_list_length <= buffer_length);
+	EFSYS_ASSERT(mcdi_list_length + mcdi_encap_list_length <=
+	    buffer_length);
 	list_length = 0;
-	for (i = 0; i < mcdi_list_length; i++) {
+	for (i = 0; i < mcdi_list_length + mcdi_encap_list_length; i++) {
 		if ((buffer[i] & ~all_filter_flags) == 0) {
 			buffer[list_length] = buffer[i];
 			list_length++;
@@ -1018,6 +1059,10 @@ ef10_filter_supported_filters(
 
 	return (0);
 
+fail3:
+	EFSYS_PROBE(fail3);
+fail2:
+	EFSYS_PROBE(fail2);
 fail1:
 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 02/14] net/sfc/base: support VNI/VSID and inner frame local MAC
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 01/14] net/sfc/base: support filters for encapsulated packets Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 03/14] net/sfc/base: support VXLAN filter creation Andrew Rybchenko
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

This supports VNI/VSID and inner frame local MAC fields to
match in VXLAN, GENEVE, or NVGRE packets.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 drivers/net/sfc/base/ef10_filter.c | 18 ++++++++++++++++++
 drivers/net/sfc/base/efx.h         |  8 ++++++++
 2 files changed, 26 insertions(+)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index 8a6bc61..e93dc13 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -119,6 +119,10 @@ ef10_filter_init(
 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN));
 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO));
+	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_VNI_OR_VSID ==
+	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID));
+	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_LOC_MAC ==
+	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC));
 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST ==
 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST));
 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST ==
@@ -292,6 +296,12 @@ efx_mcdi_filter_op_add(
 			rc = EINVAL;
 			goto fail2;
 		}
+
+		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_VNI_OR_VSID),
+		    spec->efs_vni_or_vsid, EFX_VNI_OR_VSID_LEN);
+
+		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_IFRM_DST_MAC),
+		    spec->efs_ifrm_loc_mac, EFX_MAC_ADDR_LEN);
 	}
 
 	efx_mcdi_execute(enp, &req);
@@ -415,6 +425,12 @@ ef10_filter_equal(
 		return (B_FALSE);
 	if (left->efs_encap_type != right->efs_encap_type)
 		return (B_FALSE);
+	if (memcmp(left->efs_vni_or_vsid, right->efs_vni_or_vsid,
+	    EFX_VNI_OR_VSID_LEN))
+		return (B_FALSE);
+	if (memcmp(left->efs_ifrm_loc_mac, right->efs_ifrm_loc_mac,
+	    EFX_MAC_ADDR_LEN))
+		return (B_FALSE);
 
 	return (B_TRUE);
 
@@ -988,6 +1004,8 @@ ef10_filter_supported_filters(
 	    EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
 	    EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID |
 	    EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO |
+	    EFX_FILTER_MATCH_VNI_OR_VSID |
+	    EFX_FILTER_MATCH_IFRM_LOC_MAC |
 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
 	    EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index 088a896..8380d0a 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -454,6 +454,8 @@ typedef enum efx_link_mode_e {
 
 #define	EFX_MAC_ADDR_LEN 6
 
+#define	EFX_VNI_OR_VSID_LEN 3
+
 #define	EFX_MAC_ADDR_IS_MULTICAST(_address) (((uint8_t *)_address)[0] & 0x01)
 
 #define	EFX_MAC_MULTICAST_LIST_MAX	256
@@ -2475,6 +2477,10 @@ typedef uint8_t efx_filter_flags_t;
 #define	EFX_FILTER_MATCH_OUTER_VID		0x00000100
 /* Match by IP transport protocol */
 #define	EFX_FILTER_MATCH_IP_PROTO		0x00000200
+/* Match by VNI or VSID */
+#define	EFX_FILTER_MATCH_VNI_OR_VSID		0x00000800
+/* For encapsulated packets, match by inner frame local MAC address */
+#define	EFX_FILTER_MATCH_IFRM_LOC_MAC		0x00010000
 /* For encapsulated packets, match all multicast inner frames */
 #define	EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST	0x01000000
 /* For encapsulated packets, match all unicast inner frames */
@@ -2521,6 +2527,8 @@ typedef struct efx_filter_spec_s {
 	uint16_t			efs_rem_port;
 	efx_oword_t			efs_rem_host;
 	efx_oword_t			efs_loc_host;
+	uint8_t				efs_vni_or_vsid[EFX_VNI_OR_VSID_LEN];
+	uint8_t				efs_ifrm_loc_mac[EFX_MAC_ADDR_LEN];
 } efx_filter_spec_t;
 
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 03/14] net/sfc/base: support VXLAN filter creation
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 01/14] net/sfc/base: support filters for encapsulated packets Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 02/14] net/sfc/base: support VNI/VSID and inner frame local MAC Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 04/14] net/sfc/base: distinguish filters for encapsulated packets Andrew Rybchenko
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Vijay Srivastava

From: Vijay Srivastava <vijays@solarflare.com>

Signed-off-by: Vijay Srivastava <vijays@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 drivers/net/sfc/base/efx.h        |  7 +++++++
 drivers/net/sfc/base/efx_filter.c | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index 8380d0a..e2f49ec 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -2624,6 +2624,13 @@ efx_filter_spec_set_encap_type(
 	__in		efx_tunnel_protocol_t encap_type,
 	__in		efx_filter_inner_frame_match_t inner_frame_match);
 
+extern	__checkReturn	efx_rc_t
+efx_filter_spec_set_vxlan_full(
+	__inout		efx_filter_spec_t *spec,
+	__in		const uint8_t *vxlan_id,
+	__in		const uint8_t *inner_addr,
+	__in		const uint8_t *outer_addr);
+
 #if EFSYS_OPT_RX_SCALE
 extern	__checkReturn	efx_rc_t
 efx_filter_spec_set_rss_context(
diff --git a/drivers/net/sfc/base/efx_filter.c b/drivers/net/sfc/base/efx_filter.c
index 8705369..2e6628b 100644
--- a/drivers/net/sfc/base/efx_filter.c
+++ b/drivers/net/sfc/base/efx_filter.c
@@ -468,6 +468,42 @@ efx_filter_spec_set_encap_type(
 	return (rc);
 }
 
+/*
+ * Specify inner and outer Ethernet address and VXLAN ID in filter
+ * specification.
+ */
+	__checkReturn	efx_rc_t
+efx_filter_spec_set_vxlan_full(
+	__inout		efx_filter_spec_t *spec,
+	__in		const uint8_t *vxlan_id,
+	__in		const uint8_t *inner_addr,
+	__in		const uint8_t *outer_addr)
+{
+	EFSYS_ASSERT3P(spec, !=, NULL);
+	EFSYS_ASSERT3P(vxlan_id, !=, NULL);
+	EFSYS_ASSERT3P(inner_addr, !=, NULL);
+	EFSYS_ASSERT3P(outer_addr, !=, NULL);
+
+	if ((inner_addr == NULL) && (outer_addr == NULL))
+		return (EINVAL);
+
+	if (vxlan_id != NULL) {
+		spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
+		memcpy(spec->efs_vni_or_vsid, vxlan_id, EFX_VNI_OR_VSID_LEN);
+	}
+	if (outer_addr != NULL) {
+		spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
+		memcpy(spec->efs_loc_mac, outer_addr, EFX_MAC_ADDR_LEN);
+	}
+	if (inner_addr != NULL) {
+		spec->efs_match_flags |= EFX_FILTER_MATCH_IFRM_LOC_MAC;
+		memcpy(spec->efs_ifrm_loc_mac, inner_addr, EFX_MAC_ADDR_LEN);
+	}
+	spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
+
+	return (0);
+}
+
 #if EFSYS_OPT_RX_SCALE
 	__checkReturn	efx_rc_t
 efx_filter_spec_set_rss_context(
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 04/14] net/sfc/base: distinguish filters for encapsulated packets
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (2 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 03/14] net/sfc/base: support VXLAN filter creation Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 05/14] net/sfc: add VXLAN in flow API filters support Andrew Rybchenko
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Add filter match flag to distinguish filters applied only to
encapsulated packets.

Match flags set should allow to determine whether a filter
is supported or not. The problem is that if specification
has supported set outer match flags and specified
encapsulation without any inner flags, check says that it
is supported, and filter insertion is performed. However,
there is no filtering of the encapsulated traffic. A new
flag is added to solve this problem and separate the
filters for the encapsulated packets.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
Reviewed-by: Mark Spender <mspender@solarflare.com>
---
 drivers/net/sfc/base/ef10_filter.c | 19 +++++++++++++++++--
 drivers/net/sfc/base/efx.h         |  5 +++++
 drivers/net/sfc/base/efx_filter.c  |  3 ++-
 3 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index e93dc13..a627cce 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -174,6 +174,7 @@ efx_mcdi_filter_op_add(
 	efx_mcdi_req_t req;
 	uint8_t payload[MAX(MC_CMD_FILTER_OP_EXT_IN_LEN,
 			    MC_CMD_FILTER_OP_EXT_OUT_LEN)];
+	efx_filter_match_flags_t match_flags;
 	efx_rc_t rc;
 
 	memset(payload, 0, sizeof (payload));
@@ -183,6 +184,12 @@ efx_mcdi_filter_op_add(
 	req.emr_out_buf = payload;
 	req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN;
 
+	/*
+	 * Remove match flag for encapsulated filters that does not correspond
+	 * to the MCDI match flags
+	 */
+	match_flags = spec->efs_match_flags & ~EFX_FILTER_MATCH_ENCAP_TYPE;
+
 	switch (filter_op) {
 	case MC_CMD_FILTER_OP_IN_OP_REPLACE:
 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO,
@@ -203,7 +210,7 @@ efx_mcdi_filter_op_add(
 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_PORT_ID,
 	    EVB_PORT_ID_ASSIGNED);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_MATCH_FIELDS,
-	    spec->efs_match_flags);
+	    match_flags);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
 	    MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE,
@@ -1008,13 +1015,17 @@ ef10_filter_supported_filters(
 	    EFX_FILTER_MATCH_IFRM_LOC_MAC |
 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
+	    EFX_FILTER_MATCH_ENCAP_TYPE |
 	    EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
 	    EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
 
 	/*
 	 * Two calls to MC_CMD_GET_PARSER_DISP_INFO are needed: one to get the
 	 * list of supported filters for ordinary packets, and then another to
-	 * get the list of supported filters for encapsulated packets.
+	 * get the list of supported filters for encapsulated packets. To
+	 * distinguish the second list from the first, the
+	 * EFX_FILTER_MATCH_ENCAP_TYPE flag is added to each filter for
+	 * encapsulated packets.
 	 */
 	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, B_FALSE,
 	    &mcdi_list_length);
@@ -1042,6 +1053,10 @@ ef10_filter_supported_filters(
 				no_space = B_TRUE;
 			else
 				goto fail2;
+		} else {
+			for (i = next_buf_idx;
+			    i < next_buf_idx + mcdi_encap_list_length; i++)
+				buffer[i] |= EFX_FILTER_MATCH_ENCAP_TYPE;
 		}
 	} else {
 		mcdi_encap_list_length = 0;
diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index e2f49ec..bb903e5 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -2485,6 +2485,11 @@ typedef uint8_t efx_filter_flags_t;
 #define	EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST	0x01000000
 /* For encapsulated packets, match all unicast inner frames */
 #define	EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST	0x02000000
+/*
+ * Match by encap type, this flag does not correspond to
+ * the MCDI match flags and any unoccupied value may be used
+ */
+#define	EFX_FILTER_MATCH_ENCAP_TYPE		0x20000000
 /* Match otherwise-unmatched multicast and broadcast packets */
 #define	EFX_FILTER_MATCH_UNKNOWN_MCAST_DST	0x40000000
 /* Match otherwise-unmatched unicast packets */
diff --git a/drivers/net/sfc/base/efx_filter.c b/drivers/net/sfc/base/efx_filter.c
index 2e6628b..97c972c 100644
--- a/drivers/net/sfc/base/efx_filter.c
+++ b/drivers/net/sfc/base/efx_filter.c
@@ -418,7 +418,7 @@ efx_filter_spec_set_encap_type(
 	__in		efx_tunnel_protocol_t encap_type,
 	__in		efx_filter_inner_frame_match_t inner_frame_match)
 {
-	uint32_t match_flags = 0;
+	uint32_t match_flags = EFX_FILTER_MATCH_ENCAP_TYPE;
 	uint8_t ip_proto;
 	efx_rc_t rc;
 
@@ -499,6 +499,7 @@ efx_filter_spec_set_vxlan_full(
 		spec->efs_match_flags |= EFX_FILTER_MATCH_IFRM_LOC_MAC;
 		memcpy(spec->efs_ifrm_loc_mac, inner_addr, EFX_MAC_ADDR_LEN);
 	}
+	spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
 	spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
 
 	return (0);
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 05/14] net/sfc: add VXLAN in flow API filters support
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (3 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 04/14] net/sfc/base: distinguish filters for encapsulated packets Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 06/14] net/sfc: add NVGRE " Andrew Rybchenko
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Exact match of VXLAN network identifier is supported by parser.
IP protocol match are enforced to UDP.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |   2 +
 drivers/net/sfc/sfc_flow.c  | 165 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 167 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index ccdf5ff..5a4b2a6 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -166,6 +166,8 @@ Supported pattern items:
 
 - UDP (exact match of source/destination ports)
 
+- VXLAN (exact match of VXLAN network identifier)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 93cdf8f..20ba69d 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -57,6 +57,7 @@ static sfc_flow_item_parse sfc_flow_parse_ipv4;
 static sfc_flow_item_parse sfc_flow_parse_ipv6;
 static sfc_flow_item_parse sfc_flow_parse_tcp;
 static sfc_flow_item_parse sfc_flow_parse_udp;
+static sfc_flow_item_parse sfc_flow_parse_vxlan;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -696,6 +697,132 @@ sfc_flow_parse_udp(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+/*
+ * Filters for encapsulated packets match based on the EtherType and IP
+ * protocol in the outer frame.
+ */
+static int
+sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
+					efx_filter_spec_t *efx_spec,
+					uint8_t ip_proto,
+					struct rte_flow_error *error)
+{
+	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_IP_PROTO)) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
+		efx_spec->efs_ip_proto = ip_proto;
+	} else if (efx_spec->efs_ip_proto != ip_proto) {
+		switch (ip_proto) {
+		case EFX_IPPROTO_UDP:
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Outer IP header protocol must be UDP "
+				"in VxLAN pattern");
+			return -rte_errno;
+
+		default:
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Only VxLAN tunneling patterns "
+				"are supported");
+			return -rte_errno;
+		}
+	}
+
+	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Outer frame EtherType in pattern with tunneling "
+			"must be set");
+		return -rte_errno;
+	} else if (efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4 &&
+		   efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV6) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Outer frame EtherType in pattern with tunneling "
+			"must be IPv4 or IPv6");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
+static int
+sfc_flow_set_efx_spec_vni_or_vsid(efx_filter_spec_t *efx_spec,
+				  const uint8_t *vni_or_vsid_val,
+				  const uint8_t *vni_or_vsid_mask,
+				  const struct rte_flow_item *item,
+				  struct rte_flow_error *error)
+{
+	const uint8_t vni_or_vsid_full_mask[EFX_VNI_OR_VSID_LEN] = {
+		0xff, 0xff, 0xff
+	};
+
+	if (memcmp(vni_or_vsid_mask, vni_or_vsid_full_mask,
+		   EFX_VNI_OR_VSID_LEN) == 0) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
+		rte_memcpy(efx_spec->efs_vni_or_vsid, vni_or_vsid_val,
+			   EFX_VNI_OR_VSID_LEN);
+	} else if (!sfc_flow_is_zero(vni_or_vsid_mask, EFX_VNI_OR_VSID_LEN)) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "Unsupported VNI/VSID mask");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
+/**
+ * Convert VXLAN item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only VXLAN network identifier field is supported.
+ *   If the mask is NULL, default mask will be used.
+ *   Ranging is not supported.
+ * @param efx_spec[in, out]
+ *   EFX filter specification to update.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_parse_vxlan(const struct rte_flow_item *item,
+		     efx_filter_spec_t *efx_spec,
+		     struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_vxlan *spec = NULL;
+	const struct rte_flow_item_vxlan *mask = NULL;
+	const struct rte_flow_item_vxlan supp_mask = {
+		.vni = { 0xff, 0xff, 0xff }
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_vxlan_mask,
+				 sizeof(struct rte_flow_item_vxlan),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	rc = sfc_flow_set_match_flags_for_encap_pkts(item, efx_spec,
+						     EFX_IPPROTO_UDP, error);
+	if (rc != 0)
+		return rc;
+
+	efx_spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
+	efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
+
+	if (spec == NULL)
+		return 0;
+
+	rc = sfc_flow_set_efx_spec_vni_or_vsid(efx_spec, spec->vni,
+					       mask->vni, item, error);
+
+	return rc;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -739,6 +866,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L4,
 		.parse = sfc_flow_parse_udp,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_VXLAN,
+		.prev_layer = SFC_FLOW_ITEM_L4,
+		.layer = SFC_FLOW_ITEM_START_LAYER,
+		.parse = sfc_flow_parse_vxlan,
+	},
 };
 
 /*
@@ -806,6 +939,7 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 {
 	int rc;
 	unsigned int prev_layer = SFC_FLOW_ITEM_ANY_LAYER;
+	boolean_t is_ifrm = B_FALSE;
 	const struct sfc_flow_item *item;
 
 	if (pattern == NULL) {
@@ -837,6 +971,37 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 			return -rte_errno;
 		}
 
+		/*
+		 * Allow only VOID pattern item in the inner frame.
+		 * Also check that there is only one tunneling protocol.
+		 */
+		switch (item->type) {
+		case RTE_FLOW_ITEM_TYPE_VOID:
+			break;
+
+		case RTE_FLOW_ITEM_TYPE_VXLAN:
+			if (is_ifrm) {
+				rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					pattern,
+					"More than one tunneling protocol");
+				return -rte_errno;
+			}
+			is_ifrm = B_TRUE;
+			break;
+
+		default:
+			if (is_ifrm) {
+				rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					pattern,
+					"There is an unsupported pattern item "
+					"in the inner frame");
+				return -rte_errno;
+			}
+			break;
+		}
+
 		rc = item->parse(pattern, &flow->spec, error);
 		if (rc != 0)
 			return rc;
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 06/14] net/sfc: add NVGRE in flow API filters support
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (4 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 05/14] net/sfc: add VXLAN in flow API filters support Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 07/14] net/sfc: add GENEVE " Andrew Rybchenko
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Exact match of virtual subnet ID is supported by parser.
IP protocol match are enforced to GRE.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  2 ++
 drivers/net/sfc/sfc_flow.c  | 68 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 5a4b2a6..05dacb3 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -168,6 +168,8 @@ Supported pattern items:
 
 - VXLAN (exact match of VXLAN network identifier)
 
+- NVGRE (exact match of virtual subnet ID)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 20ba69d..126ec9b 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -58,6 +58,7 @@ static sfc_flow_item_parse sfc_flow_parse_ipv6;
 static sfc_flow_item_parse sfc_flow_parse_tcp;
 static sfc_flow_item_parse sfc_flow_parse_udp;
 static sfc_flow_item_parse sfc_flow_parse_vxlan;
+static sfc_flow_item_parse sfc_flow_parse_nvgre;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -719,10 +720,17 @@ sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
 				"in VxLAN pattern");
 			return -rte_errno;
 
+		case EFX_IPPROTO_GRE:
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Outer IP header protocol must be GRE "
+				"in NVGRE pattern");
+			return -rte_errno;
+
 		default:
 			rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_ITEM, item,
-				"Only VxLAN tunneling patterns "
+				"Only VxLAN/NVGRE tunneling patterns "
 				"are supported");
 			return -rte_errno;
 		}
@@ -823,6 +831,57 @@ sfc_flow_parse_vxlan(const struct rte_flow_item *item,
 	return rc;
 }
 
+/**
+ * Convert NVGRE item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only virtual subnet ID field is supported.
+ *   If the mask is NULL, default mask will be used.
+ *   Ranging is not supported.
+ * @param efx_spec[in, out]
+ *   EFX filter specification to update.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_parse_nvgre(const struct rte_flow_item *item,
+		     efx_filter_spec_t *efx_spec,
+		     struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_nvgre *spec = NULL;
+	const struct rte_flow_item_nvgre *mask = NULL;
+	const struct rte_flow_item_nvgre supp_mask = {
+		.tni = { 0xff, 0xff, 0xff }
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_nvgre_mask,
+				 sizeof(struct rte_flow_item_nvgre),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	rc = sfc_flow_set_match_flags_for_encap_pkts(item, efx_spec,
+						     EFX_IPPROTO_GRE, error);
+	if (rc != 0)
+		return rc;
+
+	efx_spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_NVGRE;
+	efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
+
+	if (spec == NULL)
+		return 0;
+
+	rc = sfc_flow_set_efx_spec_vni_or_vsid(efx_spec, spec->tni,
+					       mask->tni, item, error);
+
+	return rc;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -872,6 +931,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_START_LAYER,
 		.parse = sfc_flow_parse_vxlan,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_NVGRE,
+		.prev_layer = SFC_FLOW_ITEM_L3,
+		.layer = SFC_FLOW_ITEM_START_LAYER,
+		.parse = sfc_flow_parse_nvgre,
+	},
 };
 
 /*
@@ -980,6 +1045,7 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 			break;
 
 		case RTE_FLOW_ITEM_TYPE_VXLAN:
+		case RTE_FLOW_ITEM_TYPE_NVGRE:
 			if (is_ifrm) {
 				rte_flow_error_set(error, EINVAL,
 					RTE_FLOW_ERROR_TYPE_ITEM,
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 07/14] net/sfc: add GENEVE in flow API filters support
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (5 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 06/14] net/sfc: add NVGRE " Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 08/14] net/sfc: add inner frame ETH " Andrew Rybchenko
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Exact match of virtual network identifier is supported by parser.
IP protocol match are enforced to UDP.
Only Ethernet protocol type is supported.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  3 ++
 drivers/net/sfc/sfc_flow.c  | 80 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 05dacb3..943fe55 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -168,6 +168,9 @@ Supported pattern items:
 
 - VXLAN (exact match of VXLAN network identifier)
 
+- GENEVE (exact match of virtual network identifier, only Ethernet (0x6558)
+  protocol type is supported)
+
 - NVGRE (exact match of virtual subnet ID)
 
 Supported actions:
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 126ec9b..efdc664 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -58,6 +58,7 @@ static sfc_flow_item_parse sfc_flow_parse_ipv6;
 static sfc_flow_item_parse sfc_flow_parse_tcp;
 static sfc_flow_item_parse sfc_flow_parse_udp;
 static sfc_flow_item_parse sfc_flow_parse_vxlan;
+static sfc_flow_item_parse sfc_flow_parse_geneve;
 static sfc_flow_item_parse sfc_flow_parse_nvgre;
 
 static boolean_t
@@ -717,7 +718,7 @@ sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
 			rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_ITEM, item,
 				"Outer IP header protocol must be UDP "
-				"in VxLAN pattern");
+				"in VxLAN/GENEVE pattern");
 			return -rte_errno;
 
 		case EFX_IPPROTO_GRE:
@@ -730,7 +731,7 @@ sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
 		default:
 			rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_ITEM, item,
-				"Only VxLAN/NVGRE tunneling patterns "
+				"Only VxLAN/GENEVE/NVGRE tunneling patterns "
 				"are supported");
 			return -rte_errno;
 		}
@@ -832,6 +833,74 @@ sfc_flow_parse_vxlan(const struct rte_flow_item *item,
 }
 
 /**
+ * Convert GENEVE item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only Virtual Network Identifier and protocol type
+ *   fields are supported. But protocol type can be only Ethernet (0x6558).
+ *   If the mask is NULL, default mask will be used.
+ *   Ranging is not supported.
+ * @param efx_spec[in, out]
+ *   EFX filter specification to update.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_parse_geneve(const struct rte_flow_item *item,
+		      efx_filter_spec_t *efx_spec,
+		      struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_geneve *spec = NULL;
+	const struct rte_flow_item_geneve *mask = NULL;
+	const struct rte_flow_item_geneve supp_mask = {
+		.protocol = RTE_BE16(0xffff),
+		.vni = { 0xff, 0xff, 0xff }
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_geneve_mask,
+				 sizeof(struct rte_flow_item_geneve),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	rc = sfc_flow_set_match_flags_for_encap_pkts(item, efx_spec,
+						     EFX_IPPROTO_UDP, error);
+	if (rc != 0)
+		return rc;
+
+	efx_spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_GENEVE;
+	efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
+
+	if (spec == NULL)
+		return 0;
+
+	if (mask->protocol == supp_mask.protocol) {
+		if (spec->protocol != rte_cpu_to_be_16(ETHER_TYPE_TEB)) {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"GENEVE encap. protocol must be Ethernet "
+				"(0x6558) in the GENEVE pattern item");
+			return -rte_errno;
+		}
+	} else if (mask->protocol != 0) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Unsupported mask for GENEVE encap. protocol");
+		return -rte_errno;
+	}
+
+	rc = sfc_flow_set_efx_spec_vni_or_vsid(efx_spec, spec->vni,
+					       mask->vni, item, error);
+
+	return rc;
+}
+
+/**
  * Convert NVGRE item to EFX filter specification.
  *
  * @param item[in]
@@ -932,6 +1001,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.parse = sfc_flow_parse_vxlan,
 	},
 	{
+		.type = RTE_FLOW_ITEM_TYPE_GENEVE,
+		.prev_layer = SFC_FLOW_ITEM_L4,
+		.layer = SFC_FLOW_ITEM_START_LAYER,
+		.parse = sfc_flow_parse_geneve,
+	},
+	{
 		.type = RTE_FLOW_ITEM_TYPE_NVGRE,
 		.prev_layer = SFC_FLOW_ITEM_L3,
 		.layer = SFC_FLOW_ITEM_START_LAYER,
@@ -1045,6 +1120,7 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 			break;
 
 		case RTE_FLOW_ITEM_TYPE_VXLAN:
+		case RTE_FLOW_ITEM_TYPE_GENEVE:
 		case RTE_FLOW_ITEM_TYPE_NVGRE:
 			if (is_ifrm) {
 				rte_flow_error_set(error, EINVAL,
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 08/14] net/sfc: add inner frame ETH in flow API filters support
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (6 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 07/14] net/sfc: add GENEVE " Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 09/14] net/sfc: add infrastructure to make many filters from flow Andrew Rybchenko
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Support destination MAC address match in inner frames.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  4 ++-
 drivers/net/sfc/sfc_flow.c  | 73 +++++++++++++++++++++++++++++++++++----------
 2 files changed, 61 insertions(+), 16 deletions(-)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 943fe55..539ce90 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -152,7 +152,9 @@ Supported pattern items:
 - VOID
 
 - ETH (exact match of source/destination addresses, individual/group match
-  of destination address, EtherType)
+  of destination address, EtherType in the outer frame and exact match of
+  destination addresses, individual/group match of destination address in
+  the inner frame)
 
 - VLAN (exact match of VID, double-tagging is supported)
 
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index efdc664..c942a36 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -187,11 +187,11 @@ sfc_flow_parse_void(__rte_unused const struct rte_flow_item *item,
  * Convert Ethernet item to EFX filter specification.
  *
  * @param item[in]
- *   Item specification. Only source and destination addresses and
- *   Ethernet type fields are supported. In addition to full and
- *   empty masks of destination address, individual/group mask is
- *   also supported. If the mask is NULL, default mask will be used.
- *   Ranging is not supported.
+ *   Item specification. Outer frame specification may only comprise
+ *   source/destination addresses and Ethertype field.
+ *   Inner frame specification may contain destination address only.
+ *   There is support for individual/group mask as well as for empty and full.
+ *   If the mask is NULL, default mask will be used. Ranging is not supported.
  * @param efx_spec[in, out]
  *   EFX filter specification to update.
  * @param[out] error
@@ -210,40 +210,75 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 		.src.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
 		.type = 0xffff,
 	};
+	const struct rte_flow_item_eth ifrm_supp_mask = {
+		.dst.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+	};
 	const uint8_t ig_mask[EFX_MAC_ADDR_LEN] = {
 		0x01, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
+	const struct rte_flow_item_eth *supp_mask_p;
+	const struct rte_flow_item_eth *def_mask_p;
+	uint8_t *loc_mac = NULL;
+	boolean_t is_ifrm = (efx_spec->efs_encap_type !=
+		EFX_TUNNEL_PROTOCOL_NONE);
+
+	if (is_ifrm) {
+		supp_mask_p = &ifrm_supp_mask;
+		def_mask_p = &ifrm_supp_mask;
+		loc_mac = efx_spec->efs_ifrm_loc_mac;
+	} else {
+		supp_mask_p = &supp_mask;
+		def_mask_p = &rte_flow_item_eth_mask;
+		loc_mac = efx_spec->efs_loc_mac;
+	}
 
 	rc = sfc_flow_parse_init(item,
 				 (const void **)&spec,
 				 (const void **)&mask,
-				 &supp_mask,
-				 &rte_flow_item_eth_mask,
+				 supp_mask_p, def_mask_p,
 				 sizeof(struct rte_flow_item_eth),
 				 error);
 	if (rc != 0)
 		return rc;
 
-	/* If "spec" is not set, could be any Ethernet */
-	if (spec == NULL)
-		return 0;
+	/*
+	 * If "spec" is not set, could be any Ethernet, but for the inner frame
+	 * type of destination MAC must be set
+	 */
+	if (spec == NULL) {
+		if (is_ifrm)
+			goto fail_bad_ifrm_dst_mac;
+		else
+			return 0;
+	}
 
 	if (is_same_ether_addr(&mask->dst, &supp_mask.dst)) {
-		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
-		rte_memcpy(efx_spec->efs_loc_mac, spec->dst.addr_bytes,
+		efx_spec->efs_match_flags |= is_ifrm ?
+			EFX_FILTER_MATCH_IFRM_LOC_MAC :
+			EFX_FILTER_MATCH_LOC_MAC;
+		rte_memcpy(loc_mac, spec->dst.addr_bytes,
 			   EFX_MAC_ADDR_LEN);
 	} else if (memcmp(mask->dst.addr_bytes, ig_mask,
 			  EFX_MAC_ADDR_LEN) == 0) {
 		if (is_unicast_ether_addr(&spec->dst))
-			efx_spec->efs_match_flags |=
+			efx_spec->efs_match_flags |= is_ifrm ?
+				EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST :
 				EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
 		else
-			efx_spec->efs_match_flags |=
+			efx_spec->efs_match_flags |= is_ifrm ?
+				EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST :
 				EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
 	} else if (!is_zero_ether_addr(&mask->dst)) {
 		goto fail_bad_mask;
+	} else if (is_ifrm) {
+		goto fail_bad_ifrm_dst_mac;
 	}
 
+	/*
+	 * ifrm_supp_mask ensures that the source address and
+	 * ethertype masks are equal to zero in inner frame,
+	 * so these fields are filled in only for the outer frame
+	 */
 	if (is_same_ether_addr(&mask->src, &supp_mask.src)) {
 		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_MAC;
 		rte_memcpy(efx_spec->efs_rem_mac, spec->src.addr_bytes,
@@ -270,6 +305,13 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 			   RTE_FLOW_ERROR_TYPE_ITEM, item,
 			   "Bad mask in the ETH pattern item");
 	return -rte_errno;
+
+fail_bad_ifrm_dst_mac:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Type of destination MAC address in inner frame "
+			   "must be set");
+	return -rte_errno;
 }
 
 /**
@@ -1112,11 +1154,12 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 		}
 
 		/*
-		 * Allow only VOID pattern item in the inner frame.
+		 * Allow only VOID and ETH pattern items in the inner frame.
 		 * Also check that there is only one tunneling protocol.
 		 */
 		switch (item->type) {
 		case RTE_FLOW_ITEM_TYPE_VOID:
+		case RTE_FLOW_ITEM_TYPE_ETH:
 			break;
 
 		case RTE_FLOW_ITEM_TYPE_VXLAN:
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 09/14] net/sfc: add infrastructure to make many filters from flow
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (7 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 08/14] net/sfc: add inner frame ETH " Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 10/14] net/sfc: multiply of specs with an unknown EtherType Andrew Rybchenko
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Not all flow rules can be expressed in one hardware filter, so some flow
rules have to be expressed in terms of multiple hardware filters. This
patch provides a means to produce a filter spec template from the flow
rule which then can be used to produce a set of fully elaborated specs
to be inserted.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 drivers/net/sfc/sfc_flow.c | 118 ++++++++++++++++++++++++++++++++++++---------
 drivers/net/sfc/sfc_flow.h |  19 +++++++-
 2 files changed, 114 insertions(+), 23 deletions(-)

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index c942a36..a432936 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -25,10 +25,13 @@
 
 /*
  * At now flow API is implemented in such a manner that each
- * flow rule is converted to a hardware filter.
+ * flow rule is converted to one or more hardware filters.
  * All elements of flow rule (attributes, pattern items, actions)
  * correspond to one or more fields in the efx_filter_spec_s structure
  * that is responsible for the hardware filter.
+ * If some required field is unset in the flow rule, then a handful
+ * of filter copies will be created to cover all possible values
+ * of such a field.
  */
 
 enum sfc_flow_item_layers {
@@ -1095,8 +1098,8 @@ sfc_flow_parse_attr(const struct rte_flow_attr *attr,
 		return -rte_errno;
 	}
 
-	flow->spec.efs_flags |= EFX_FILTER_FLAG_RX;
-	flow->spec.efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
+	flow->spec.template.efs_flags |= EFX_FILTER_FLAG_RX;
+	flow->spec.template.efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
 
 	return 0;
 }
@@ -1187,7 +1190,7 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 			break;
 		}
 
-		rc = item->parse(pattern, &flow->spec, error);
+		rc = item->parse(pattern, &flow->spec.template, error);
 		if (rc != 0)
 			return rc;
 
@@ -1209,7 +1212,7 @@ sfc_flow_parse_queue(struct sfc_adapter *sa,
 		return -EINVAL;
 
 	rxq = sa->rxq_info[queue->index].rxq;
-	flow->spec.efs_dmaq_id = (uint16_t)rxq->hw_index;
+	flow->spec.template.efs_dmaq_id = (uint16_t)rxq->hw_index;
 
 	return 0;
 }
@@ -1285,13 +1288,57 @@ sfc_flow_parse_rss(struct sfc_adapter *sa,
 #endif /* EFSYS_OPT_RX_SCALE */
 
 static int
+sfc_flow_spec_flush(struct sfc_adapter *sa, struct sfc_flow_spec *spec,
+		    unsigned int filters_count)
+{
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < filters_count; i++) {
+		int rc;
+
+		rc = efx_filter_remove(sa->nic, &spec->filters[i]);
+		if (ret == 0 && rc != 0) {
+			sfc_err(sa, "failed to remove filter specification "
+				"(rc = %d)", rc);
+			ret = rc;
+		}
+	}
+
+	return ret;
+}
+
+static int
+sfc_flow_spec_insert(struct sfc_adapter *sa, struct sfc_flow_spec *spec)
+{
+	unsigned int i;
+	int rc = 0;
+
+	for (i = 0; i < spec->count; i++) {
+		rc = efx_filter_insert(sa->nic, &spec->filters[i]);
+		if (rc != 0) {
+			sfc_flow_spec_flush(sa, spec, i);
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int
+sfc_flow_spec_remove(struct sfc_adapter *sa, struct sfc_flow_spec *spec)
+{
+	return sfc_flow_spec_flush(sa, spec, spec->count);
+}
+
+static int
 sfc_flow_filter_insert(struct sfc_adapter *sa,
 		       struct rte_flow *flow)
 {
-	efx_filter_spec_t *spec = &flow->spec;
-
 #if EFSYS_OPT_RX_SCALE
 	struct sfc_flow_rss *rss = &flow->rss_conf;
+	uint32_t efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
+	unsigned int i;
 	int rc = 0;
 
 	if (flow->rss) {
@@ -1302,27 +1349,38 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
 		rc = efx_rx_scale_context_alloc(sa->nic,
 						EFX_RX_SCALE_EXCLUSIVE,
 						rss_spread,
-						&spec->efs_rss_context);
+						&efs_rss_context);
 		if (rc != 0)
 			goto fail_scale_context_alloc;
 
-		rc = efx_rx_scale_mode_set(sa->nic, spec->efs_rss_context,
+		rc = efx_rx_scale_mode_set(sa->nic, efs_rss_context,
 					   EFX_RX_HASHALG_TOEPLITZ,
 					   rss->rss_hash_types, B_TRUE);
 		if (rc != 0)
 			goto fail_scale_mode_set;
 
-		rc = efx_rx_scale_key_set(sa->nic, spec->efs_rss_context,
+		rc = efx_rx_scale_key_set(sa->nic, efs_rss_context,
 					  rss->rss_key,
 					  sizeof(sa->rss_key));
 		if (rc != 0)
 			goto fail_scale_key_set;
 
-		spec->efs_dmaq_id = rss->rxq_hw_index_min;
-		spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS;
+		/*
+		 * At this point, fully elaborated filter specifications
+		 * have been produced from the template. To make sure that
+		 * RSS behaviour is consistent between them, set the same
+		 * RSS context value everywhere.
+		 */
+		for (i = 0; i < flow->spec.count; i++) {
+			efx_filter_spec_t *spec = &flow->spec.filters[i];
+
+			spec->efs_rss_context = efs_rss_context;
+			spec->efs_dmaq_id = rss->rxq_hw_index_min;
+			spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS;
+		}
 	}
 
-	rc = efx_filter_insert(sa->nic, spec);
+	rc = sfc_flow_spec_insert(sa, &flow->spec);
 	if (rc != 0)
 		goto fail_filter_insert;
 
@@ -1335,7 +1393,7 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
 		 * the HW knows all the information needed to verify
 		 * the table entries, and the operation will succeed
 		 */
-		rc = efx_rx_scale_tbl_set(sa->nic, spec->efs_rss_context,
+		rc = efx_rx_scale_tbl_set(sa->nic, efs_rss_context,
 					  rss->rss_tbl, RTE_DIM(rss->rss_tbl));
 		if (rc != 0)
 			goto fail_scale_tbl_set;
@@ -1344,18 +1402,18 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
 	return 0;
 
 fail_scale_tbl_set:
-	efx_filter_remove(sa->nic, spec);
+	sfc_flow_spec_remove(sa, &flow->spec);
 
 fail_filter_insert:
 fail_scale_key_set:
 fail_scale_mode_set:
-	if (flow->rss)
-		efx_rx_scale_context_free(sa->nic, spec->efs_rss_context);
+	if (efs_rss_context != EFX_RSS_CONTEXT_DEFAULT)
+		efx_rx_scale_context_free(sa->nic, efs_rss_context);
 
 fail_scale_context_alloc:
 	return rc;
 #else /* !EFSYS_OPT_RX_SCALE */
-	return efx_filter_insert(sa->nic, spec);
+	return sfc_flow_spec_insert(sa, &flow->spec);
 #endif /* EFSYS_OPT_RX_SCALE */
 }
 
@@ -1363,16 +1421,23 @@ static int
 sfc_flow_filter_remove(struct sfc_adapter *sa,
 		       struct rte_flow *flow)
 {
-	efx_filter_spec_t *spec = &flow->spec;
 	int rc = 0;
 
-	rc = efx_filter_remove(sa->nic, spec);
+	rc = sfc_flow_spec_remove(sa, &flow->spec);
 	if (rc != 0)
 		return rc;
 
 #if EFSYS_OPT_RX_SCALE
-	if (flow->rss)
+	if (flow->rss) {
+		/*
+		 * All specifications for a given flow rule have the same RSS
+		 * context, so that RSS context value is taken from the first
+		 * filter specification
+		 */
+		efx_filter_spec_t *spec = &flow->spec.filters[0];
+
 		rc = efx_rx_scale_context_free(sa->nic, spec->efs_rss_context);
+	}
 #endif /* EFSYS_OPT_RX_SCALE */
 
 	return rc;
@@ -1452,6 +1517,8 @@ sfc_flow_parse(struct rte_eth_dev *dev,
 	       struct rte_flow_error *error)
 {
 	struct sfc_adapter *sa = dev->data->dev_private;
+	efx_filter_match_flags_t match_flags =
+		flow->spec.template.efs_match_flags;
 	int rc;
 
 	rc = sfc_flow_parse_attr(attr, flow, error);
@@ -1466,13 +1533,20 @@ sfc_flow_parse(struct rte_eth_dev *dev,
 	if (rc != 0)
 		goto fail_bad_value;
 
-	if (!sfc_filter_is_match_supported(sa, flow->spec.efs_match_flags)) {
+	if (!sfc_filter_is_match_supported(sa, match_flags)) {
 		rte_flow_error_set(error, ENOTSUP,
 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 				   "Flow rule pattern is not supported");
 		return -rte_errno;
 	}
 
+	/*
+	 * At this point, template specification simply becomes the first
+	 * fully elaborated spec
+	 */
+	flow->spec.filters[0] = flow->spec.template;
+	flow->spec.count = 1;
+
 fail_bad_value:
 	return rc;
 }
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 35472ad..634c310 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -19,6 +19,13 @@
 extern "C" {
 #endif
 
+/*
+ * The maximum number of fully elaborated hardware filter specifications
+ * which can be produced from a template by means of multiplication, if
+ * missing match flags are needed to be taken into account
+ */
+#define SF_FLOW_SPEC_NB_FILTERS_MAX 1
+
 #if EFSYS_OPT_RX_SCALE
 /* RSS configuration storage */
 struct sfc_flow_rss {
@@ -30,9 +37,19 @@ struct sfc_flow_rss {
 };
 #endif /* EFSYS_OPT_RX_SCALE */
 
+/* Filter specification storage */
+struct sfc_flow_spec {
+	/* partial specification from flow rule */
+	efx_filter_spec_t template;
+	/* fully elaborated hardware filters specifications */
+	efx_filter_spec_t filters[SF_FLOW_SPEC_NB_FILTERS_MAX];
+	/* number of complete specifications */
+	unsigned int count;
+};
+
 /* PMD-specific definition of the opaque type from rte_flow.h */
 struct rte_flow {
-	efx_filter_spec_t spec;		/* filter specification */
+	struct sfc_flow_spec spec;	/* flow spec for hardware filter(s) */
 #if EFSYS_OPT_RX_SCALE
 	boolean_t rss;			/* RSS toggle */
 	struct sfc_flow_rss rss_conf;	/* RSS configuration */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 10/14] net/sfc: multiply of specs with an unknown EtherType
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (8 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 09/14] net/sfc: add infrastructure to make many filters from flow Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 11/14] net/sfc: multiply of specs w/o inner frame destination MAC Andrew Rybchenko
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Hardware filter specification for encapsulated traffic must contain
EtherType. In terms of RTE flow API, this would require L3 item to be
used in the flow rule. In the simplest case, if the user needs to filter
encapsulated traffic without knowledge of exact EtherType, they will
have to create multiple variants of the flow rule featuring all possible
L3 items (IPv4, IPv6), respectively. In order to hide the gory details
and avoid such a complication, this patch implements a mechanism to
auto-complete the filter specifications if need be.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 drivers/net/sfc/sfc_flow.c | 306 +++++++++++++++++++++++++++++++++++++++------
 drivers/net/sfc/sfc_flow.h |   2 +-
 2 files changed, 266 insertions(+), 42 deletions(-)

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index a432936..244fcdb 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -64,6 +64,21 @@ static sfc_flow_item_parse sfc_flow_parse_vxlan;
 static sfc_flow_item_parse sfc_flow_parse_geneve;
 static sfc_flow_item_parse sfc_flow_parse_nvgre;
 
+typedef int (sfc_flow_spec_set_vals)(struct sfc_flow_spec *spec,
+				     unsigned int filters_count_for_one_val,
+				     struct rte_flow_error *error);
+
+struct sfc_flow_copy_flag {
+	/* EFX filter specification match flag */
+	efx_filter_match_flags_t flag;
+	/* Number of values of corresponding field */
+	unsigned int vals_count;
+	/* Function to set values in specifications */
+	sfc_flow_spec_set_vals *set_vals;
+};
+
+static sfc_flow_spec_set_vals sfc_flow_set_ethertypes;
+
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
 {
@@ -244,16 +259,9 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 	if (rc != 0)
 		return rc;
 
-	/*
-	 * If "spec" is not set, could be any Ethernet, but for the inner frame
-	 * type of destination MAC must be set
-	 */
-	if (spec == NULL) {
-		if (is_ifrm)
-			goto fail_bad_ifrm_dst_mac;
-		else
-			return 0;
-	}
+	/* If "spec" is not set, could be any Ethernet */
+	if (spec == NULL)
+		return 0;
 
 	if (is_same_ether_addr(&mask->dst, &supp_mask.dst)) {
 		efx_spec->efs_match_flags |= is_ifrm ?
@@ -273,8 +281,6 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 				EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
 	} else if (!is_zero_ether_addr(&mask->dst)) {
 		goto fail_bad_mask;
-	} else if (is_ifrm) {
-		goto fail_bad_ifrm_dst_mac;
 	}
 
 	/*
@@ -308,13 +314,6 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 			   RTE_FLOW_ERROR_TYPE_ITEM, item,
 			   "Bad mask in the ETH pattern item");
 	return -rte_errno;
-
-fail_bad_ifrm_dst_mac:
-	rte_flow_error_set(error, EINVAL,
-			   RTE_FLOW_ERROR_TYPE_ITEM, item,
-			   "Type of destination MAC address in inner frame "
-			   "must be set");
-	return -rte_errno;
 }
 
 /**
@@ -782,14 +781,9 @@ sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
 		}
 	}
 
-	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM, item,
-			"Outer frame EtherType in pattern with tunneling "
-			"must be set");
-		return -rte_errno;
-	} else if (efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4 &&
-		   efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV6) {
+	if (efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE &&
+	    efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4 &&
+	    efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV6) {
 		rte_flow_error_set(error, EINVAL,
 			RTE_FLOW_ERROR_TYPE_ITEM, item,
 			"Outer frame EtherType in pattern with tunneling "
@@ -1508,6 +1502,246 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
 	return 0;
 }
 
+/**
+ * Set the EFX_FILTER_MATCH_ETHER_TYPE match flag and EFX_ETHER_TYPE_IPV4 and
+ * EFX_ETHER_TYPE_IPV6 values of the corresponding field in the same
+ * specifications after copying.
+ *
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param filters_count_for_one_val[in]
+ *   How many specifications should have the same EtherType value, what is the
+ *   number of specifications before copying.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_set_ethertypes(struct sfc_flow_spec *spec,
+			unsigned int filters_count_for_one_val,
+			struct rte_flow_error *error)
+{
+	unsigned int i;
+	static const uint16_t vals[] = {
+		EFX_ETHER_TYPE_IPV4, EFX_ETHER_TYPE_IPV6
+	};
+
+	if (filters_count_for_one_val * RTE_DIM(vals) != spec->count) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Number of specifications is incorrect "
+			"while copying by Ethertype");
+		return -rte_errno;
+	}
+
+	for (i = 0; i < spec->count; i++) {
+		spec->filters[i].efs_match_flags |=
+			EFX_FILTER_MATCH_ETHER_TYPE;
+
+		/*
+		 * The check above ensures that
+		 * filters_count_for_one_val is not 0
+		 */
+		spec->filters[i].efs_ether_type =
+			vals[i / filters_count_for_one_val];
+	}
+
+	return 0;
+}
+
+/* Match flags that can be automatically added to filters */
+static const struct sfc_flow_copy_flag sfc_flow_copy_flags[] = {
+	{
+		.flag = EFX_FILTER_MATCH_ETHER_TYPE,
+		.vals_count = 2,
+		.set_vals = sfc_flow_set_ethertypes,
+	},
+};
+
+/* Get item from array sfc_flow_copy_flags */
+static const struct sfc_flow_copy_flag *
+sfc_flow_get_copy_flag(efx_filter_match_flags_t flag)
+{
+	unsigned int i;
+
+	for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
+		if (sfc_flow_copy_flags[i].flag == flag)
+			return &sfc_flow_copy_flags[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * Make copies of the specifications, set match flag and values
+ * of the field that corresponds to it.
+ *
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param flag[in]
+ *   The match flag to add.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_spec_add_match_flag(struct sfc_flow_spec *spec,
+			     efx_filter_match_flags_t flag,
+			     struct rte_flow_error *error)
+{
+	unsigned int i;
+	unsigned int new_filters_count;
+	unsigned int filters_count_for_one_val;
+	const struct sfc_flow_copy_flag *copy_flag;
+	int rc;
+
+	copy_flag = sfc_flow_get_copy_flag(flag);
+	if (copy_flag == NULL) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Unsupported spec field for copying");
+		return -rte_errno;
+	}
+
+	new_filters_count = spec->count * copy_flag->vals_count;
+	if (new_filters_count > SF_FLOW_SPEC_NB_FILTERS_MAX) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Too much EFX specifications in the flow rule");
+		return -rte_errno;
+	}
+
+	/* Copy filters specifications */
+	for (i = spec->count; i < new_filters_count; i++)
+		spec->filters[i] = spec->filters[i - spec->count];
+
+	filters_count_for_one_val = spec->count;
+	spec->count = new_filters_count;
+
+	rc = copy_flag->set_vals(spec, filters_count_for_one_val, error);
+	if (rc != 0)
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Check that the given set of match flags missing in the original filter spec
+ * could be covered by adding spec copies which specify the corresponding
+ * flags and packet field values to match.
+ *
+ * @param miss_flags[in]
+ *   Flags that are missing until the supported filter.
+ *
+ * @return
+ *   Number of specifications after copy or 0, if the flags can not be added.
+ */
+static unsigned int
+sfc_flow_check_missing_flags(efx_filter_match_flags_t miss_flags)
+{
+	unsigned int i;
+	efx_filter_match_flags_t copy_flags = 0;
+	efx_filter_match_flags_t flag;
+	unsigned int multiplier = 1;
+
+	for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
+		flag = sfc_flow_copy_flags[i].flag;
+		if ((flag & miss_flags) == flag) {
+			copy_flags |= flag;
+			multiplier *= sfc_flow_copy_flags[i].vals_count;
+		}
+	}
+
+	if (copy_flags == miss_flags)
+		return multiplier;
+
+	return 0;
+}
+
+/**
+ * Attempt to supplement the specification template to the minimally
+ * supported set of match flags. To do this, it is necessary to copy
+ * the specifications, filling them with the values of fields that
+ * correspond to the missing flags.
+ * The necessary and sufficient filter is built from the fewest number
+ * of copies which could be made to cover the minimally required set
+ * of flags.
+ *
+ * @param sa[in]
+ *   SFC adapter.
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_spec_filters_complete(struct sfc_adapter *sa,
+			       struct sfc_flow_spec *spec,
+			       struct rte_flow_error *error)
+{
+	struct sfc_filter *filter = &sa->filter;
+	efx_filter_match_flags_t miss_flags;
+	efx_filter_match_flags_t min_miss_flags = 0;
+	efx_filter_match_flags_t match;
+	unsigned int min_multiplier = UINT_MAX;
+	unsigned int multiplier;
+	unsigned int i;
+	int rc;
+
+	match = spec->template.efs_match_flags;
+	for (i = 0; i < filter->supported_match_num; i++) {
+		if ((match & filter->supported_match[i]) == match) {
+			miss_flags = filter->supported_match[i] & (~match);
+			multiplier = sfc_flow_check_missing_flags(miss_flags);
+			if (multiplier > 0) {
+				if (multiplier <= min_multiplier) {
+					min_multiplier = multiplier;
+					min_miss_flags = miss_flags;
+				}
+			}
+		}
+	}
+
+	if (min_multiplier == UINT_MAX) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Flow rule pattern is not supported");
+		return -rte_errno;
+	}
+
+	for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
+		efx_filter_match_flags_t flag = sfc_flow_copy_flags[i].flag;
+
+		if ((flag & min_miss_flags) == flag) {
+			rc = sfc_flow_spec_add_match_flag(spec, flag, error);
+			if (rc != 0)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int
+sfc_flow_validate_match_flags(struct sfc_adapter *sa,
+			      struct rte_flow *flow,
+			      struct rte_flow_error *error)
+{
+	efx_filter_spec_t *spec_tmpl = &flow->spec.template;
+	efx_filter_match_flags_t match_flags = spec_tmpl->efs_match_flags;
+	int rc;
+
+	/* Initialize the first filter spec with template */
+	flow->spec.filters[0] = *spec_tmpl;
+	flow->spec.count = 1;
+
+	if (!sfc_filter_is_match_supported(sa, match_flags)) {
+		rc = sfc_flow_spec_filters_complete(sa, &flow->spec, error);
+		if (rc != 0)
+			return rc;
+	}
+
+	return 0;
+}
+
 static int
 sfc_flow_parse(struct rte_eth_dev *dev,
 	       const struct rte_flow_attr *attr,
@@ -1517,8 +1751,6 @@ sfc_flow_parse(struct rte_eth_dev *dev,
 	       struct rte_flow_error *error)
 {
 	struct sfc_adapter *sa = dev->data->dev_private;
-	efx_filter_match_flags_t match_flags =
-		flow->spec.template.efs_match_flags;
 	int rc;
 
 	rc = sfc_flow_parse_attr(attr, flow, error);
@@ -1533,19 +1765,11 @@ sfc_flow_parse(struct rte_eth_dev *dev,
 	if (rc != 0)
 		goto fail_bad_value;
 
-	if (!sfc_filter_is_match_supported(sa, match_flags)) {
-		rte_flow_error_set(error, ENOTSUP,
-				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				   "Flow rule pattern is not supported");
-		return -rte_errno;
-	}
+	rc = sfc_flow_validate_match_flags(sa, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
 
-	/*
-	 * At this point, template specification simply becomes the first
-	 * fully elaborated spec
-	 */
-	flow->spec.filters[0] = flow->spec.template;
-	flow->spec.count = 1;
+	return 0;
 
 fail_bad_value:
 	return rc;
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 634c310..c4302c7 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -24,7 +24,7 @@ extern "C" {
  * which can be produced from a template by means of multiplication, if
  * missing match flags are needed to be taken into account
  */
-#define SF_FLOW_SPEC_NB_FILTERS_MAX 1
+#define SF_FLOW_SPEC_NB_FILTERS_MAX 2
 
 #if EFSYS_OPT_RX_SCALE
 /* RSS configuration storage */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 11/14] net/sfc: multiply of specs w/o inner frame destination MAC
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (9 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 10/14] net/sfc: multiply of specs with an unknown EtherType Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 12/14] net/sfc: multiply of specs with an unknown " Andrew Rybchenko
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Knowledge of a network identifier is not sufficient to construct a
workable hardware filter for encapsulated traffic. It's obligatory to
specify one of the match flags associated with inner frame destination
MAC. If the address is unknown, then one needs to specify either unknown
unicast or unknown multicast destination match flag.

In terms of RTE flow API, this would require adding multiple flow rules
with corresponding ETH items besides the tunnel item. In order to avoid
such a complication, the patch implements a mechanism to auto-complete
an underlying filter representation of a flow rule in order to create
additional filter specififcations featuring the missing match flags.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 drivers/net/sfc/sfc_flow.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/sfc/sfc_flow.h |   2 +-
 2 files changed, 113 insertions(+), 3 deletions(-)

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 244fcdb..2d45827 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -68,6 +68,10 @@ typedef int (sfc_flow_spec_set_vals)(struct sfc_flow_spec *spec,
 				     unsigned int filters_count_for_one_val,
 				     struct rte_flow_error *error);
 
+typedef boolean_t (sfc_flow_spec_check)(efx_filter_match_flags_t match,
+					efx_filter_spec_t *spec,
+					struct sfc_filter *filter);
+
 struct sfc_flow_copy_flag {
 	/* EFX filter specification match flag */
 	efx_filter_match_flags_t flag;
@@ -75,9 +79,16 @@ struct sfc_flow_copy_flag {
 	unsigned int vals_count;
 	/* Function to set values in specifications */
 	sfc_flow_spec_set_vals *set_vals;
+	/*
+	 * Function to check that the specification is suitable
+	 * for adding this match flag
+	 */
+	sfc_flow_spec_check *spec_check;
 };
 
 static sfc_flow_spec_set_vals sfc_flow_set_ethertypes;
+static sfc_flow_spec_set_vals sfc_flow_set_ifrm_unknown_dst_flags;
+static sfc_flow_spec_check sfc_flow_check_ifrm_unknown_dst_flags;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -1548,12 +1559,98 @@ sfc_flow_set_ethertypes(struct sfc_flow_spec *spec,
 	return 0;
 }
 
+/**
+ * Set the EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST and
+ * EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST match flags in the same
+ * specifications after copying.
+ *
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param filters_count_for_one_val[in]
+ *   How many specifications should have the same match flag, what is the
+ *   number of specifications before copying.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_set_ifrm_unknown_dst_flags(struct sfc_flow_spec *spec,
+				    unsigned int filters_count_for_one_val,
+				    struct rte_flow_error *error)
+{
+	unsigned int i;
+	static const efx_filter_match_flags_t vals[] = {
+		EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST,
+		EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST
+	};
+
+	if (filters_count_for_one_val * RTE_DIM(vals) != spec->count) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Number of specifications is incorrect while copying "
+			"by inner frame unknown destination flags");
+		return -rte_errno;
+	}
+
+	for (i = 0; i < spec->count; i++) {
+		/* The check above ensures that divisor can't be zero here */
+		spec->filters[i].efs_match_flags |=
+			vals[i / filters_count_for_one_val];
+	}
+
+	return 0;
+}
+
+/**
+ * Check that the following conditions are met:
+ * - the specification corresponds to a filter for encapsulated traffic
+ * - the list of supported filters has a filter
+ *   with EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST flag instead of
+ *   EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST, since this filter will also
+ *   be inserted.
+ *
+ * @param match[in]
+ *   The match flags of filter.
+ * @param spec[in]
+ *   Specification to be supplemented.
+ * @param filter[in]
+ *   SFC filter with list of supported filters.
+ */
+static boolean_t
+sfc_flow_check_ifrm_unknown_dst_flags(efx_filter_match_flags_t match,
+				      efx_filter_spec_t *spec,
+				      struct sfc_filter *filter)
+{
+	unsigned int i;
+	efx_tunnel_protocol_t encap_type = spec->efs_encap_type;
+	efx_filter_match_flags_t match_mcast_dst;
+
+	if (encap_type == EFX_TUNNEL_PROTOCOL_NONE)
+		return B_FALSE;
+
+	match_mcast_dst =
+		(match & ~EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST) |
+		EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
+	for (i = 0; i < filter->supported_match_num; i++) {
+		if (match_mcast_dst == filter->supported_match[i])
+			return B_TRUE;
+	}
+
+	return B_FALSE;
+}
+
 /* Match flags that can be automatically added to filters */
 static const struct sfc_flow_copy_flag sfc_flow_copy_flags[] = {
 	{
 		.flag = EFX_FILTER_MATCH_ETHER_TYPE,
 		.vals_count = 2,
 		.set_vals = sfc_flow_set_ethertypes,
+		.spec_check = NULL,
+	},
+	{
+		.flag = EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST,
+		.vals_count = 2,
+		.set_vals = sfc_flow_set_ifrm_unknown_dst_flags,
+		.spec_check = sfc_flow_check_ifrm_unknown_dst_flags,
 	},
 };
 
@@ -1630,21 +1727,33 @@ sfc_flow_spec_add_match_flag(struct sfc_flow_spec *spec,
  *
  * @param miss_flags[in]
  *   Flags that are missing until the supported filter.
+ * @param spec[in]
+ *   Specification to be supplemented.
+ * @param filter[in]
+ *   SFC filter.
  *
  * @return
  *   Number of specifications after copy or 0, if the flags can not be added.
  */
 static unsigned int
-sfc_flow_check_missing_flags(efx_filter_match_flags_t miss_flags)
+sfc_flow_check_missing_flags(efx_filter_match_flags_t miss_flags,
+			     efx_filter_spec_t *spec,
+			     struct sfc_filter *filter)
 {
 	unsigned int i;
 	efx_filter_match_flags_t copy_flags = 0;
 	efx_filter_match_flags_t flag;
+	efx_filter_match_flags_t match = spec->efs_match_flags | miss_flags;
+	sfc_flow_spec_check *check;
 	unsigned int multiplier = 1;
 
 	for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
 		flag = sfc_flow_copy_flags[i].flag;
+		check = sfc_flow_copy_flags[i].spec_check;
 		if ((flag & miss_flags) == flag) {
+			if (check != NULL && (!check(match, spec, filter)))
+				continue;
+
 			copy_flags |= flag;
 			multiplier *= sfc_flow_copy_flags[i].vals_count;
 		}
@@ -1690,7 +1799,8 @@ sfc_flow_spec_filters_complete(struct sfc_adapter *sa,
 	for (i = 0; i < filter->supported_match_num; i++) {
 		if ((match & filter->supported_match[i]) == match) {
 			miss_flags = filter->supported_match[i] & (~match);
-			multiplier = sfc_flow_check_missing_flags(miss_flags);
+			multiplier = sfc_flow_check_missing_flags(miss_flags,
+				&spec->template, filter);
 			if (multiplier > 0) {
 				if (multiplier <= min_multiplier) {
 					min_multiplier = multiplier;
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index c4302c7..2b287dd 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -24,7 +24,7 @@ extern "C" {
  * which can be produced from a template by means of multiplication, if
  * missing match flags are needed to be taken into account
  */
-#define SF_FLOW_SPEC_NB_FILTERS_MAX 2
+#define SF_FLOW_SPEC_NB_FILTERS_MAX 4
 
 #if EFSYS_OPT_RX_SCALE
 /* RSS configuration storage */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 12/14] net/sfc: multiply of specs with an unknown destination MAC
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (10 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 11/14] net/sfc: multiply of specs w/o inner frame destination MAC Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 13/14] net/sfc: avoid creation of ineffective flow rules Andrew Rybchenko
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

To filter all traffic, need to create two hardware filter specifications
with both unknown unicast and unknown multicast destination MAC address
match flags.

In terms of RTE flow API, this would require adding multiple flow rules
with corresponding ETH items. In order to avoid such a complication, the
patch implements a mechanism to auto-complete an underlying filter
representation of a flow rule in order to create additional filter
specififcations featuring the missing match flags.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 drivers/net/sfc/sfc_flow.c | 91 +++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/sfc/sfc_flow.h |  2 +-
 2 files changed, 91 insertions(+), 2 deletions(-)

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 2d45827..7b26653 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -86,6 +86,8 @@ struct sfc_flow_copy_flag {
 	sfc_flow_spec_check *spec_check;
 };
 
+static sfc_flow_spec_set_vals sfc_flow_set_unknown_dst_flags;
+static sfc_flow_spec_check sfc_flow_check_unknown_dst_flags;
 static sfc_flow_spec_set_vals sfc_flow_set_ethertypes;
 static sfc_flow_spec_set_vals sfc_flow_set_ifrm_unknown_dst_flags;
 static sfc_flow_spec_check sfc_flow_check_ifrm_unknown_dst_flags;
@@ -1514,6 +1516,80 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
 }
 
 /**
+ * Set the EFX_FILTER_MATCH_UNKNOWN_UCAST_DST
+ * and EFX_FILTER_MATCH_UNKNOWN_MCAST_DST match flags in the same
+ * specifications after copying.
+ *
+ * @param spec[in, out]
+ *   SFC flow specification to update.
+ * @param filters_count_for_one_val[in]
+ *   How many specifications should have the same match flag, what is the
+ *   number of specifications before copying.
+ * @param error[out]
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_set_unknown_dst_flags(struct sfc_flow_spec *spec,
+			       unsigned int filters_count_for_one_val,
+			       struct rte_flow_error *error)
+{
+	unsigned int i;
+	static const efx_filter_match_flags_t vals[] = {
+		EFX_FILTER_MATCH_UNKNOWN_UCAST_DST,
+		EFX_FILTER_MATCH_UNKNOWN_MCAST_DST
+	};
+
+	if (filters_count_for_one_val * RTE_DIM(vals) != spec->count) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Number of specifications is incorrect while copying "
+			"by unknown destination flags");
+		return -rte_errno;
+	}
+
+	for (i = 0; i < spec->count; i++) {
+		/* The check above ensures that divisor can't be zero here */
+		spec->filters[i].efs_match_flags |=
+			vals[i / filters_count_for_one_val];
+	}
+
+	return 0;
+}
+
+/**
+ * Check that the following conditions are met:
+ * - the list of supported filters has a filter
+ *   with EFX_FILTER_MATCH_UNKNOWN_MCAST_DST flag instead of
+ *   EFX_FILTER_MATCH_UNKNOWN_UCAST_DST, since this filter will also
+ *   be inserted.
+ *
+ * @param match[in]
+ *   The match flags of filter.
+ * @param spec[in]
+ *   Specification to be supplemented.
+ * @param filter[in]
+ *   SFC filter with list of supported filters.
+ */
+static boolean_t
+sfc_flow_check_unknown_dst_flags(efx_filter_match_flags_t match,
+				 __rte_unused efx_filter_spec_t *spec,
+				 struct sfc_filter *filter)
+{
+	unsigned int i;
+	efx_filter_match_flags_t match_mcast_dst;
+
+	match_mcast_dst =
+		(match & ~EFX_FILTER_MATCH_UNKNOWN_UCAST_DST) |
+		EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
+	for (i = 0; i < filter->supported_match_num; i++) {
+		if (match_mcast_dst == filter->supported_match[i])
+			return B_TRUE;
+	}
+
+	return B_FALSE;
+}
+
+/**
  * Set the EFX_FILTER_MATCH_ETHER_TYPE match flag and EFX_ETHER_TYPE_IPV4 and
  * EFX_ETHER_TYPE_IPV6 values of the corresponding field in the same
  * specifications after copying.
@@ -1638,9 +1714,22 @@ sfc_flow_check_ifrm_unknown_dst_flags(efx_filter_match_flags_t match,
 	return B_FALSE;
 }
 
-/* Match flags that can be automatically added to filters */
+/*
+ * Match flags that can be automatically added to filters.
+ * Selecting the last minimum when searching for the copy flag ensures that the
+ * EFX_FILTER_MATCH_UNKNOWN_UCAST_DST flag has a higher priority than
+ * EFX_FILTER_MATCH_ETHER_TYPE. This is because the filter
+ * EFX_FILTER_MATCH_UNKNOWN_UCAST_DST is at the end of the list of supported
+ * filters.
+ */
 static const struct sfc_flow_copy_flag sfc_flow_copy_flags[] = {
 	{
+		.flag = EFX_FILTER_MATCH_UNKNOWN_UCAST_DST,
+		.vals_count = 2,
+		.set_vals = sfc_flow_set_unknown_dst_flags,
+		.spec_check = sfc_flow_check_unknown_dst_flags,
+	},
+	{
 		.flag = EFX_FILTER_MATCH_ETHER_TYPE,
 		.vals_count = 2,
 		.set_vals = sfc_flow_set_ethertypes,
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 2b287dd..69dd683 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -24,7 +24,7 @@ extern "C" {
  * which can be produced from a template by means of multiplication, if
  * missing match flags are needed to be taken into account
  */
-#define SF_FLOW_SPEC_NB_FILTERS_MAX 4
+#define SF_FLOW_SPEC_NB_FILTERS_MAX 8
 
 #if EFSYS_OPT_RX_SCALE
 /* RSS configuration storage */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 13/14] net/sfc: avoid creation of ineffective flow rules
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (11 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 12/14] net/sfc: multiply of specs with an unknown " Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 14/14] doc: add net/sfc flow API support for tunnels Andrew Rybchenko
  2018-03-09 10:37   ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Ferruh Yigit
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>

Despite being versatile, the hardware support for filtering has a number
of special properties which must be taken into account. Namely, there is
a known set of valid filters which don't take any effect despite being
accepted by the hardware.

The combinations of match flags and field values which can describe the
exceptional filters are as follows:
- ETHER_TYPE or ETHER_TYPE | LOC_MAC with IPv4 or IPv6 EtherType
- ETHER_TYPE | IP_PROTO or ETHER_TYPE | IP_PROTO | LOC_MAC with UDP or
TCP IP protocol value
- The same combinations with OUTER_VID and/or INNER_VID

These exceptional filters can be expressed in terms of RTE flow rules.
If the user creates such a flow rule, no traffic will hit the underlying
filter, and no errors will be reported.

This patch adds a means to prevent such ineffective flow rules from
being created.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
---
 doc/guides/nics/sfc_efx.rst | 17 ++++++++++
 drivers/net/sfc/sfc_flow.c  | 78 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 539ce90..f41ccdb 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -193,6 +193,23 @@ in the mask of destination address. If destinaton address in the spec is
 multicast, it matches all multicast (and broadcast) packets, oherwise it
 matches unicast packets that are not filtered by other flow rules.
 
+Exceptions to flow rules
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+There is a list of exceptional flow rule patterns which will not be
+accepted by the PMD. A pattern will be rejected if at least one of the
+conditions is met:
+
+- Filtering by IPv4 or IPv6 EtherType without pattern items of internet
+  layer and above.
+
+- The last item is IPV4 or IPV6, and it's empty.
+
+- Filtering by TCP or UDP IP transport protocol without pattern items of
+  transport layer and above.
+
+- The last item is TCP or UDP, and it's empty.
+
 
 Supported NICs
 --------------
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 7b26653..2b8bef8 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -1919,6 +1919,77 @@ sfc_flow_spec_filters_complete(struct sfc_adapter *sa,
 	return 0;
 }
 
+/**
+ * Check that set of match flags is referred to by a filter. Filter is
+ * described by match flags with the ability to add OUTER_VID and INNER_VID
+ * flags.
+ *
+ * @param match_flags[in]
+ *   Set of match flags.
+ * @param flags_pattern[in]
+ *   Pattern of filter match flags.
+ */
+static boolean_t
+sfc_flow_is_match_with_vids(efx_filter_match_flags_t match_flags,
+			    efx_filter_match_flags_t flags_pattern)
+{
+	if ((match_flags & flags_pattern) != flags_pattern)
+		return B_FALSE;
+
+	switch (match_flags & ~flags_pattern) {
+	case 0:
+	case EFX_FILTER_MATCH_OUTER_VID:
+	case EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_INNER_VID:
+		return B_TRUE;
+	default:
+		return B_FALSE;
+	}
+}
+
+/**
+ * Check whether the spec maps to a hardware filter which is known to be
+ * ineffective despite being valid.
+ *
+ * @param spec[in]
+ *   SFC flow specification.
+ */
+static boolean_t
+sfc_flow_is_match_flags_exception(struct sfc_flow_spec *spec)
+{
+	unsigned int i;
+	uint16_t ether_type;
+	uint8_t ip_proto;
+	efx_filter_match_flags_t match_flags;
+
+	for (i = 0; i < spec->count; i++) {
+		match_flags = spec->filters[i].efs_match_flags;
+
+		if (sfc_flow_is_match_with_vids(match_flags,
+						EFX_FILTER_MATCH_ETHER_TYPE) ||
+		    sfc_flow_is_match_with_vids(match_flags,
+						EFX_FILTER_MATCH_ETHER_TYPE |
+						EFX_FILTER_MATCH_LOC_MAC)) {
+			ether_type = spec->filters[i].efs_ether_type;
+			if (ether_type == EFX_ETHER_TYPE_IPV4 ||
+			    ether_type == EFX_ETHER_TYPE_IPV6)
+				return B_TRUE;
+		} else if (sfc_flow_is_match_with_vids(match_flags,
+				EFX_FILTER_MATCH_ETHER_TYPE |
+				EFX_FILTER_MATCH_IP_PROTO) ||
+			   sfc_flow_is_match_with_vids(match_flags,
+				EFX_FILTER_MATCH_ETHER_TYPE |
+				EFX_FILTER_MATCH_IP_PROTO |
+				EFX_FILTER_MATCH_LOC_MAC)) {
+			ip_proto = spec->filters[i].efs_ip_proto;
+			if (ip_proto == EFX_IPPROTO_TCP ||
+			    ip_proto == EFX_IPPROTO_UDP)
+				return B_TRUE;
+		}
+	}
+
+	return B_FALSE;
+}
+
 static int
 sfc_flow_validate_match_flags(struct sfc_adapter *sa,
 			      struct rte_flow *flow,
@@ -1938,6 +2009,13 @@ sfc_flow_validate_match_flags(struct sfc_adapter *sa,
 			return rc;
 	}
 
+	if (sfc_flow_is_match_flags_exception(&flow->spec)) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"The flow rule pattern is unsupported");
+		return -rte_errno;
+	}
+
 	return 0;
 }
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [dpdk-dev] [PATCH v2 14/14] doc: add net/sfc flow API support for tunnels
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (12 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 13/14] net/sfc: avoid creation of ineffective flow rules Andrew Rybchenko
@ 2018-03-06 15:24   ` Andrew Rybchenko
  2018-03-09 10:37   ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Ferruh Yigit
  14 siblings, 0 replies; 32+ messages in thread
From: Andrew Rybchenko @ 2018-03-06 15:24 UTC (permalink / raw)
  To: dev

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 doc/guides/rel_notes/release_18_05.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst
index 3923dc2..894f636 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -41,6 +41,12 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Updated Solarflare network PMD.**
+
+  Updated the sfc_efx driver including the following changes:
+
+  * Added support for NVGRE, VXLAN and GENEVE filters in flow API.
+
 
 API Changes
 -----------
-- 
2.7.4

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API for tunnels
  2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
                     ` (13 preceding siblings ...)
  2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 14/14] doc: add net/sfc flow API support for tunnels Andrew Rybchenko
@ 2018-03-09 10:37   ` Ferruh Yigit
  14 siblings, 0 replies; 32+ messages in thread
From: Ferruh Yigit @ 2018-03-09 10:37 UTC (permalink / raw)
  To: Andrew Rybchenko, dev

On 3/6/2018 3:24 PM, Andrew Rybchenko wrote:
> Update base driver and the PMD itself to support flow API
> patterns for tunnels: VXLAN, NVGRE and Geneve.
> 
> Applicable to SFN8xxx NICs with full-feature firmware variant running.
> 
> Andrew Rybchenko (1):
>   doc: add net/sfc flow API support for tunnels
> 
> Roman Zhukov (12):
>   net/sfc/base: support filters for encapsulated packets
>   net/sfc/base: support VNI/VSID and inner frame local MAC
>   net/sfc/base: distinguish filters for encapsulated packets
>   net/sfc: add VXLAN in flow API filters support
>   net/sfc: add NVGRE in flow API filters support
>   net/sfc: add GENEVE in flow API filters support
>   net/sfc: add inner frame ETH in flow API filters support
>   net/sfc: add infrastructure to make many filters from flow
>   net/sfc: multiply of specs with an unknown EtherType
>   net/sfc: multiply of specs w/o inner frame destination MAC
>   net/sfc: multiply of specs with an unknown destination MAC
>   net/sfc: avoid creation of ineffective flow rules
> 
> Vijay Srivastava (1):
>   net/sfc/base: support VXLAN filter creation

Series applied to dpdk-next-net/master, thanks.

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2018-03-09 10:37 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-27 12:45 [dpdk-dev] [PATCH 00/14] net/sfc: support flow API for tunnels Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 01/14] net/sfc/base: support filters for encapsulated packets Andrew Rybchenko
2018-03-06 15:13   ` Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 02/14] net/sfc/base: support VNI/VSID and inner frame local MAC Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 03/14] net/sfc/base: support VXLAN filter creation Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 04/14] net/sfc/base: distinguish filters for encapsulated packets Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 05/14] net/sfc: add VXLAN in flow API filters support Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 06/14] net/sfc: add NVGRE " Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 07/14] net/sfc: add GENEVE " Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 08/14] net/sfc: add inner frame ETH " Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 09/14] net/sfc: add infrastructure to make many filters from flow Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 10/14] net/sfc: multiply of specs with an unknown EtherType Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 11/14] net/sfc: multiply of specs w/o inner frame destination MAC Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 12/14] net/sfc: multiply of specs with an unknown " Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 13/14] net/sfc: avoid creation of ineffective flow rules Andrew Rybchenko
2018-02-27 12:45 ` [dpdk-dev] [PATCH 14/14] doc: add net/sfc flow API support for tunnels Andrew Rybchenko
2018-03-06 15:24 ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 01/14] net/sfc/base: support filters for encapsulated packets Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 02/14] net/sfc/base: support VNI/VSID and inner frame local MAC Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 03/14] net/sfc/base: support VXLAN filter creation Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 04/14] net/sfc/base: distinguish filters for encapsulated packets Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 05/14] net/sfc: add VXLAN in flow API filters support Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 06/14] net/sfc: add NVGRE " Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 07/14] net/sfc: add GENEVE " Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 08/14] net/sfc: add inner frame ETH " Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 09/14] net/sfc: add infrastructure to make many filters from flow Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 10/14] net/sfc: multiply of specs with an unknown EtherType Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 11/14] net/sfc: multiply of specs w/o inner frame destination MAC Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 12/14] net/sfc: multiply of specs with an unknown " Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 13/14] net/sfc: avoid creation of ineffective flow rules Andrew Rybchenko
2018-03-06 15:24   ` [dpdk-dev] [PATCH v2 14/14] doc: add net/sfc flow API support for tunnels Andrew Rybchenko
2018-03-09 10:37   ` [dpdk-dev] [PATCH v2 00/14] net/sfc: support flow API " Ferruh Yigit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).