All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] Support flow API in Solarflare PMD
@ 2017-03-02 16:03 Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 01/11] net/sfc/base: split local MAC I/G back into separate flags Andrew Rybchenko
                   ` (12 more replies)
  0 siblings, 13 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev

Support simple queue destination flow API filters in Solarflare
libefx-based PMD including:
 - Ethernet source/destination, EtherType exact matching
 - VLAN ID exact matching including double-tagging
 - IPv4/6 source/destination and IP protocol exact matching
 - TCP/UDP source/destination exact matching

Supported combinations of fields mentioned above depend on
firmware (including running variant) and correctly processed by
validate callback.


Andrew Rybchenko (2):
  net/sfc: implement dummy filter control callback
  net/sfc: provide a way to check if filter is supported

Mark Spender (2):
  net/sfc/base: split local MAC I/G back into separate flags
  net/sfc/base: improve API to get supported filter matches

Roman Zhukov (7):
  net/sfc: add flow API filters support
  net/sfc: add VLAN in flow API filters support
  net/sfc: add IPV4 in flow API filters support
  net/sfc: add IPV6 in flow API filters support
  net/sfc: add TCP in flow API filters support
  net/sfc: add UDP in flow API filters support
  net/sfc: add unknown unicast/multicast match in flow API

 doc/guides/nics/features/sfc_efx.ini |    1 +
 doc/guides/nics/sfc_efx.rst          |   45 ++
 drivers/net/sfc/Makefile             |    2 +
 drivers/net/sfc/base/ef10_filter.c   |  134 +++--
 drivers/net/sfc/base/ef10_impl.h     |    7 +-
 drivers/net/sfc/base/efx.h           |   17 +-
 drivers/net/sfc/base/efx_filter.c    |   76 ++-
 drivers/net/sfc/base/efx_impl.h      |    3 +-
 drivers/net/sfc/sfc.c                |   18 +
 drivers/net/sfc/sfc.h                |    3 +
 drivers/net/sfc/sfc_ethdev.c         |   59 +-
 drivers/net/sfc/sfc_filter.c         |  135 +++++
 drivers/net/sfc/sfc_filter.h         |   60 ++
 drivers/net/sfc/sfc_flow.c           | 1104 ++++++++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_flow.h           |   62 ++
 15 files changed, 1630 insertions(+), 96 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_filter.c
 create mode 100644 drivers/net/sfc/sfc_filter.h
 create mode 100644 drivers/net/sfc/sfc_flow.c
 create mode 100644 drivers/net/sfc/sfc_flow.h

-- 
2.9.3

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

* [PATCH 01/11] net/sfc/base: split local MAC I/G back into separate flags
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 02/11] net/sfc/base: improve API to get supported filter matches Andrew Rybchenko
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev; +Cc: Mark Spender

From: Mark Spender <mspender@solarflare.com>

The flag EFX_FILTER_MATCH_LOC_MAC_IG to represent filtering on the
individual/group bit of the MAC address (with the two cases being
distingusished by the MAC address in the filter specification) was
introduced to mirror the Linux driver filtering code, but the
implementations are different enough anyway that it isn't of much
value.

Having separate flags for unknown unicast and multicast simplifies
the code and allows the set of flags to match those used by MCDI.

It will also makes it easier to report whether these filters are
supported.

In the MCDI definitions, the unknown multicast and unicast flags
have the values 0x40000000 and 0x80000000 respectively, and so using
the same values for simplicity requires 32 bits in the filter
specification to store the flags. This means the structure is now
a little bigger than 64 bytes, but filters are not often used on
critical paths so this shouldn't have much impact - on Linux they
are also bigger than they used to be.

Signed-off-by: Mark Spender <mspender@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 drivers/net/sfc/base/ef10_filter.c | 48 ++++----------------------------------
 drivers/net/sfc/base/efx.h         | 10 ++++----
 drivers/net/sfc/base/efx_filter.c  |  8 ++-----
 3 files changed, 12 insertions(+), 54 deletions(-)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index c161977..f520147 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -142,6 +142,10 @@ ef10_filter_init(
 	    MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_OUTER_VLAN));
 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
 	    MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_IP_PROTO));
+	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST ==
+	    MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST));
+	EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST ==
+	    MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST));
 #undef MATCH_MASK
 
 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp);
@@ -184,7 +188,6 @@ efx_mcdi_filter_op_add(
 	efx_mcdi_req_t req;
 	uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN,
 			    MC_CMD_FILTER_OP_OUT_LEN)];
-	uint32_t match_fields = 0;
 	efx_rc_t rc;
 
 	memset(payload, 0, sizeof (payload));
@@ -211,26 +214,10 @@ efx_mcdi_filter_op_add(
 		goto fail1;
 	}
 
-	if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) {
-		/*
-		 * The LOC_MAC_IG match flag can represent unknown unicast
-		 *  or multicast filters - use the MAC address to distinguish
-		 *  them.
-		 */
-		if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac))
-			match_fields |= 1U <<
-				MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN;
-		else
-			match_fields |= 1U <<
-				MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN;
-	}
-
-	match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG);
-
 	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID,
 	    EVB_PORT_ID_ASSIGNED);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS,
-	    match_fields);
+	    spec->efs_match_flags);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST,
 	    MC_CMD_FILTER_OP_IN_RX_DEST_HOST);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE,
@@ -889,9 +876,6 @@ efx_mcdi_get_parser_disp_info(
 	uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
 			    MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)];
 	efx_rc_t rc;
-	uint32_t i;
-	boolean_t support_unknown_ucast = B_FALSE;
-	boolean_t support_unknown_mcast = B_FALSE;
 
 	(void) memset(payload, 0, sizeof (payload));
 	req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO;
@@ -927,28 +911,6 @@ efx_mcdi_get_parser_disp_info(
 	EFX_STATIC_ASSERT(sizeof (uint32_t) ==
 	    MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);
 
-	/*
-	 * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change
-	 * the lower priority one to LOC_MAC_IG.
-	 */
-	for (i = 0; i < *length; i++) {
-		if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) {
-			list[i] &=
-			(~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN);
-			support_unknown_ucast = B_TRUE;
-		}
-		if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) {
-			list[i] &=
-			(~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN);
-			support_unknown_mcast = B_TRUE;
-		}
-
-		if (support_unknown_ucast && support_unknown_mcast) {
-			list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG;
-			break;
-		}
-	}
-
 	return (0);
 
 fail2:
diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index 0815d7a..3c26f70 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -2217,10 +2217,10 @@ typedef enum efx_filter_match_flags_e {
 	EFX_FILTER_MATCH_OUTER_VID = 0x0100,	/* Match by outer VLAN ID */
 	EFX_FILTER_MATCH_IP_PROTO = 0x0200,	/* Match by IP transport
 						 * protocol */
-	EFX_FILTER_MATCH_LOC_MAC_IG = 0x0400,	/* Match by local MAC address
-						 * I/G bit. Used for RX default
-						 * unicast and multicast/
-						 * broadcast filters. */
+	/* Match otherwise-unmatched multicast and broadcast packets */
+	EFX_FILTER_MATCH_UNKNOWN_MCAST_DST = 0x40000000,
+	/* Match otherwise-unmatched unicast packets */
+	EFX_FILTER_MATCH_UNKNOWN_UCAST_DST = 0x80000000,
 } efx_filter_match_flags_t;
 
 typedef enum efx_filter_priority_s {
@@ -2242,7 +2242,7 @@ typedef enum efx_filter_priority_s {
  */
 
 typedef struct efx_filter_spec_s {
-	uint32_t	efs_match_flags:12;
+	uint32_t	efs_match_flags;
 	uint32_t	efs_priority:2;
 	uint32_t	efs_flags:6;
 	uint32_t	efs_dmaq_id:12;
diff --git a/drivers/net/sfc/base/efx_filter.c b/drivers/net/sfc/base/efx_filter.c
index a20efaf..4f58a7d 100644
--- a/drivers/net/sfc/base/efx_filter.c
+++ b/drivers/net/sfc/base/efx_filter.c
@@ -149,9 +149,6 @@ efx_filter_init(
 	const efx_filter_ops_t *efop;
 	efx_rc_t rc;
 
-	/* Check that efx_filter_spec_t is 64 bytes. */
-	EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64);
-
 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
@@ -387,7 +384,7 @@ efx_filter_spec_set_uc_def(
 {
 	EFSYS_ASSERT3P(spec, !=, NULL);
 
-	spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
+	spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
 	return (0);
 }
 
@@ -400,8 +397,7 @@ efx_filter_spec_set_mc_def(
 {
 	EFSYS_ASSERT3P(spec, !=, NULL);
 
-	spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
-	spec->efs_loc_mac[0] = 1;
+	spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
 	return (0);
 }
 
-- 
2.9.3

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

* [PATCH 02/11] net/sfc/base: improve API to get supported filter matches
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 01/11] net/sfc/base: split local MAC I/G back into separate flags Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-07 13:25   ` Ferruh Yigit
  2017-03-02 16:03 ` [PATCH 03/11] net/sfc: implement dummy filter control callback Andrew Rybchenko
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev; +Cc: Mark Spender

From: Mark Spender <mspender@solarflare.com>

The previous API had various problems, including the length of the
caller provided buffer not being specified, no means being available
to discover how big the buffer needs to be, and a lack of clarity of
what the resulting list contains.

To improve it:
- add the buffer length as a parameter
- if the provided buffer is too short, fail with ENOSPC and return
  the required length
- ensure that the list contents are valid and add comments describing it

It is safe to change this API as, unsuprisingly, it has no users.

Signed-off-by: Mark Spender <mspender@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 drivers/net/sfc/base/ef10_filter.c | 90 +++++++++++++++++++++++++++++++-------
 drivers/net/sfc/base/ef10_impl.h   |  7 +--
 drivers/net/sfc/base/efx.h         |  7 +--
 drivers/net/sfc/base/efx_filter.c  | 68 +++++++++++++++++++---------
 drivers/net/sfc/base/efx_impl.h    |  3 +-
 5 files changed, 132 insertions(+), 43 deletions(-)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index f520147..695bb84 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -868,13 +868,16 @@ ef10_filter_delete(
 
 static	__checkReturn	efx_rc_t
 efx_mcdi_get_parser_disp_info(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length)
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp)
 {
 	efx_mcdi_req_t req;
 	uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
 			    MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)];
+	size_t matches_count;
+	size_t list_size;
 	efx_rc_t rc;
 
 	(void) memset(payload, 0, sizeof (payload));
@@ -894,25 +897,41 @@ efx_mcdi_get_parser_disp_info(
 		goto fail1;
 	}
 
-	*length = MCDI_OUT_DWORD(req,
+	matches_count = MCDI_OUT_DWORD(req,
 	    GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES);
 
 	if (req.emr_out_length_used <
-	    MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) {
+	    MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(matches_count)) {
 		rc = EMSGSIZE;
 		goto fail2;
 	}
 
-	memcpy(list,
-	    MCDI_OUT2(req,
-	    uint32_t,
-	    GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
-	    (*length) * sizeof (uint32_t));
+	*list_lengthp = matches_count;
+
+	if (buffer_length < matches_count) {
+		rc = ENOSPC;
+		goto fail3;
+	}
+
+	/*
+	 * Check that the elements in the list in the MCDI response are the size
+	 * we expect, so we can just copy them directly. Any conversion of the
+	 * flags is handled by the caller.
+	 */
 	EFX_STATIC_ASSERT(sizeof (uint32_t) ==
 	    MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);
 
+	list_size = matches_count *
+		MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN;
+	memcpy(buffer,
+	    MCDI_OUT2(req, uint32_t,
+		    GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
+	    list_size);
+
 	return (0);
 
+fail3:
+	EFSYS_PROBE(fail3);
 fail2:
 	EFSYS_PROBE(fail2);
 fail1:
@@ -923,14 +942,55 @@ efx_mcdi_get_parser_disp_info(
 
 	__checkReturn	efx_rc_t
 ef10_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length)
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp)
 {
-	efx_rc_t rc;
 
-	if ((rc = efx_mcdi_get_parser_disp_info(enp, list, length)) != 0)
+	size_t mcdi_list_length;
+	size_t list_length;
+	uint32_t i;
+	efx_rc_t rc;
+	uint32_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_UNKNOWN_MCAST_DST |
+	    EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
+
+	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length,
+					    &mcdi_list_length);
+	if (rc != 0) {
+		if (rc == ENOSPC) {
+			/* Pass through mcdi_list_length for the list length */
+			*list_lengthp = mcdi_list_length;
+		}
 		goto fail1;
+	}
+
+	/*
+	 * The static assertions in ef10_filter_init() ensure that the values of
+	 * the EFX_FILTER_MATCH flags match those used by MCDI, so they don't
+	 * need to be converted.
+	 *
+	 * In case support is added to MCDI for additional flags, remove any
+	 * matches from the list which include flags we don't support. The order
+	 * of the matches is preserved as they are ordered from highest to
+	 * lowest priority.
+	 */
+	EFSYS_ASSERT(mcdi_list_length <= buffer_length);
+	list_length = 0;
+	for (i = 0; i < mcdi_list_length; i++) {
+		if ((buffer[i] & ~all_filter_flags) == 0) {
+			buffer[list_length] = buffer[i];
+			list_length++;
+		}
+	}
+
+	*list_lengthp = list_length;
 
 	return (0);
 
diff --git a/drivers/net/sfc/base/ef10_impl.h b/drivers/net/sfc/base/ef10_impl.h
index 192be5d..8c3dffe 100644
--- a/drivers/net/sfc/base/ef10_impl.h
+++ b/drivers/net/sfc/base/ef10_impl.h
@@ -1043,9 +1043,10 @@ ef10_filter_delete(
 
 extern	__checkReturn	efx_rc_t
 ef10_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length);
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp);
 
 extern	__checkReturn	efx_rc_t
 ef10_filter_reconfigure(
diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index 3c26f70..e67bf37 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -2289,9 +2289,10 @@ efx_filter_restore(
 
 extern	__checkReturn	efx_rc_t
 efx_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length);
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp);
 
 extern			void
 efx_filter_spec_init_rx(
diff --git a/drivers/net/sfc/base/efx_filter.c b/drivers/net/sfc/base/efx_filter.c
index 4f58a7d..ba31026 100644
--- a/drivers/net/sfc/base/efx_filter.c
+++ b/drivers/net/sfc/base/efx_filter.c
@@ -61,9 +61,10 @@ siena_filter_delete(
 
 static	__checkReturn	efx_rc_t
 siena_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length);
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp);
 
 #endif /* EFSYS_OPT_SIENA */
 
@@ -209,11 +210,22 @@ efx_filter_fini(
 	enp->en_mod_flags &= ~EFX_MOD_FILTER;
 }
 
+/*
+ * Query the possible combinations of match flags which can be filtered on.
+ * These are returned as a list, of which each 32 bit element is a bitmask
+ * formed of EFX_FILTER_MATCH flags.
+ *
+ * The combinations are ordered in priority from highest to lowest.
+ *
+ * If the provided buffer is too short to hold the list, the call with fail with
+ * ENOSPC and *list_lengthp will be set to the buffer length required.
+ */
 	__checkReturn	efx_rc_t
 efx_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length)
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp)
 {
 	efx_rc_t rc;
 
@@ -222,11 +234,20 @@ efx_filter_supported_filters(
 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
 	EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
 
-	if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0)
+	if (buffer == NULL) {
+		rc = EINVAL;
 		goto fail1;
+	}
+
+	rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
+						    list_lengthp);
+	if (rc != 0)
+		goto fail2;
 
 	return (0);
 
+fail2:
+	EFSYS_PROBE(fail2);
 fail1:
 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
 
@@ -1346,23 +1367,20 @@ siena_filter_delete(
 	return (rc);
 }
 
-#define	MAX_SUPPORTED 4
+#define	SIENA_MAX_SUPPORTED_MATCHES 4
 
 static	__checkReturn	efx_rc_t
 siena_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length)
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp)
 {
-	int index = 0;
-	uint32_t rx_matches[MAX_SUPPORTED];
+	uint32_t index = 0;
+	uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
+	size_t list_length;
 	efx_rc_t rc;
 
-	if (list == NULL) {
-		rc = EINVAL;
-		goto fail1;
-	}
-
 	rx_matches[index++] =
 	    EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
 	    EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
@@ -1379,14 +1397,22 @@ siena_filter_supported_filters(
 		rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
 	}
 
-	EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED);
+	EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
+	list_length = index;
+
+	*list_lengthp = list_length;
+
+	if (buffer_length < list_length) {
+		rc = ENOSPC;
+		goto fail1;
+	}
 
-	*length = index;
-	memcpy(list, rx_matches, *length);
+	memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
 
 	return (0);
 
 fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
 
 	return (rc);
 }
diff --git a/drivers/net/sfc/base/efx_impl.h b/drivers/net/sfc/base/efx_impl.h
index 3a520a8..01304f2 100644
--- a/drivers/net/sfc/base/efx_impl.h
+++ b/drivers/net/sfc/base/efx_impl.h
@@ -234,7 +234,8 @@ typedef struct efx_filter_ops_s {
 	efx_rc_t	(*efo_add)(efx_nic_t *, efx_filter_spec_t *,
 				   boolean_t may_replace);
 	efx_rc_t	(*efo_delete)(efx_nic_t *, efx_filter_spec_t *);
-	efx_rc_t	(*efo_supported_filters)(efx_nic_t *, uint32_t *, size_t *);
+	efx_rc_t	(*efo_supported_filters)(efx_nic_t *, uint32_t *,
+				   size_t, size_t *);
 	efx_rc_t	(*efo_reconfigure)(efx_nic_t *, uint8_t const *, boolean_t,
 				   boolean_t, boolean_t, boolean_t,
 				   uint8_t const *, uint32_t);
-- 
2.9.3

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

* [PATCH 03/11] net/sfc: implement dummy filter control callback
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 01/11] net/sfc/base: split local MAC I/G back into separate flags Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 02/11] net/sfc/base: improve API to get supported filter matches Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 04/11] net/sfc: provide a way to check if filter is supported Andrew Rybchenko
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev

Just log error for all filter types and return no support indication.

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
Reviewed-by: Robert Stonehouse <rstonehouse@solarflare.com>
---
 drivers/net/sfc/sfc_ethdev.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 71587fb..91ac0ff 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -1187,6 +1187,54 @@ sfc_dev_rss_reta_update(struct rte_eth_dev *dev,
 }
 #endif
 
+static int
+sfc_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,
+		    __rte_unused enum rte_filter_op filter_op,
+		    __rte_unused void *arg)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	int rc = ENOTSUP;
+
+	sfc_log_init(sa, "entry");
+
+	switch (filter_type) {
+	case RTE_ETH_FILTER_NONE:
+		sfc_err(sa, "Global filters configuration not supported");
+		break;
+	case RTE_ETH_FILTER_MACVLAN:
+		sfc_err(sa, "MACVLAN filters not supported");
+		break;
+	case RTE_ETH_FILTER_ETHERTYPE:
+		sfc_err(sa, "EtherType filters not supported");
+		break;
+	case RTE_ETH_FILTER_FLEXIBLE:
+		sfc_err(sa, "Flexible filters not supported");
+		break;
+	case RTE_ETH_FILTER_SYN:
+		sfc_err(sa, "SYN filters not supported");
+		break;
+	case RTE_ETH_FILTER_NTUPLE:
+		sfc_err(sa, "NTUPLE filters not supported");
+		break;
+	case RTE_ETH_FILTER_TUNNEL:
+		sfc_err(sa, "Tunnel filters not supported");
+		break;
+	case RTE_ETH_FILTER_FDIR:
+		sfc_err(sa, "Flow Director filters not supported");
+		break;
+	case RTE_ETH_FILTER_HASH:
+		sfc_err(sa, "Hash filters not supported");
+		break;
+	default:
+		sfc_err(sa, "Unknown filter type %u", filter_type);
+		break;
+	}
+
+	sfc_log_init(sa, "exit: %d", -rc);
+	SFC_ASSERT(rc >= 0);
+	return -rc;
+}
+
 static const struct eth_dev_ops sfc_eth_dev_ops = {
 	.dev_configure			= sfc_dev_configure,
 	.dev_start			= sfc_dev_start,
@@ -1224,6 +1272,7 @@ static const struct eth_dev_ops sfc_eth_dev_ops = {
 	.rss_hash_update		= sfc_dev_rss_hash_update,
 	.rss_hash_conf_get		= sfc_dev_rss_hash_conf_get,
 #endif
+	.filter_ctrl			= sfc_dev_filter_ctrl,
 	.set_mc_addr_list		= sfc_set_mc_addr_list,
 	.rxq_info_get			= sfc_rx_queue_info_get,
 	.txq_info_get			= sfc_tx_queue_info_get,
-- 
2.9.3

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

* [PATCH 04/11] net/sfc: provide a way to check if filter is supported
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (2 preceding siblings ...)
  2017-03-02 16:03 ` [PATCH 03/11] net/sfc: implement dummy filter control callback Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 05/11] net/sfc: add flow API filters support Andrew Rybchenko
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev

The information is obtained from firmware on attach. It may
change after MC reboot (firmware version or variant change).
Cache should be refreshed after MC reboot when it is handled
properly (not yet).

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
Reviewed-by: Robert Stonehouse <rstonehouse@solarflare.com>
---
 drivers/net/sfc/Makefile     |   1 +
 drivers/net/sfc/sfc.c        |   7 +++
 drivers/net/sfc/sfc.h        |   3 +
 drivers/net/sfc/sfc_filter.c | 135 +++++++++++++++++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_filter.h |  56 ++++++++++++++++++
 5 files changed, 202 insertions(+)
 create mode 100644 drivers/net/sfc/sfc_filter.c
 create mode 100644 drivers/net/sfc/sfc_filter.h

diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index 619a0ed..2b7ede8 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/sfc/Makefile
@@ -90,6 +90,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_port.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_rx.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_tx.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_tso.c
+SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_filter.c
 
 VPATH += $(SRCDIR)/base
 
diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c
index 03ecec2..6fd8bf1 100644
--- a/drivers/net/sfc/sfc.c
+++ b/drivers/net/sfc/sfc.c
@@ -633,6 +633,10 @@ sfc_attach(struct sfc_adapter *sa)
 	if (rc != 0)
 		goto fail_set_rss_defaults;
 
+	rc = sfc_filter_attach(sa);
+	if (rc != 0)
+		goto fail_filter_attach;
+
 	sfc_log_init(sa, "fini nic");
 	efx_nic_fini(enp);
 
@@ -641,6 +645,7 @@ sfc_attach(struct sfc_adapter *sa)
 	sfc_log_init(sa, "done");
 	return 0;
 
+fail_filter_attach:
 fail_set_rss_defaults:
 	sfc_intr_detach(sa);
 
@@ -678,6 +683,8 @@ sfc_detach(struct sfc_adapter *sa)
 
 	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
+	sfc_filter_detach(sa);
+
 	sfc_intr_detach(sa);
 
 	sfc_log_init(sa, "unprobe nic");
diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 8c6c02f..2b105aa 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -38,6 +38,8 @@
 
 #include "efx.h"
 
+#include "sfc_filter.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -179,6 +181,7 @@ struct sfc_adapter {
 	struct sfc_mcdi			mcdi;
 	struct sfc_intr			intr;
 	struct sfc_port			port;
+	struct sfc_filter		filter;
 
 	unsigned int			rxq_max;
 	unsigned int			txq_max;
diff --git a/drivers/net/sfc/sfc_filter.c b/drivers/net/sfc/sfc_filter.c
new file mode 100644
index 0000000..98435e9
--- /dev/null
+++ b/drivers/net/sfc/sfc_filter.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2017 Solarflare Communications Inc.
+ * All rights reserved.
+ *
+ * This software was jointly developed between OKTET Labs (under contract
+ * for Solarflare) and Solarflare Communications, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_common.h>
+
+#include "efx.h"
+
+#include "sfc.h"
+#include "sfc_log.h"
+
+boolean_t
+sfc_filter_is_match_supported(struct sfc_adapter *sa, uint32_t match)
+{
+	struct sfc_filter *filter = &sa->filter;
+	size_t i;
+
+	for (i = 0; i < filter->supported_match_num; ++i) {
+		if (match == filter->supported_match[i])
+			return B_TRUE;
+	}
+
+	return B_FALSE;
+}
+
+static int
+sfc_filter_cache_match_supported(struct sfc_adapter *sa)
+{
+	struct sfc_filter *filter = &sa->filter;
+	size_t num = filter->supported_match_num;
+	uint32_t *buf = filter->supported_match;
+	unsigned int retry;
+	int rc;
+
+	/* Just a guess of possibly sufficient entries */
+	if (num == 0)
+		num = 16;
+
+	for (retry = 0; retry < 2; ++retry) {
+		if (num != filter->supported_match_num) {
+			rc = ENOMEM;
+			buf = rte_realloc(buf, num * sizeof(*buf), 0);
+			if (buf == NULL)
+				goto fail_realloc;
+		}
+
+		rc = efx_filter_supported_filters(sa->nic, buf, num, &num);
+		if (rc == 0) {
+			filter->supported_match_num = num;
+			filter->supported_match = buf;
+
+			return 0;
+		} else if (rc != ENOSPC) {
+			goto fail_efx_filter_supported_filters;
+		}
+	}
+
+	SFC_ASSERT(rc == ENOSPC);
+
+fail_efx_filter_supported_filters:
+fail_realloc:
+	/* Original pointer is not freed by rte_realloc() on failure */
+	rte_free(buf);
+	filter->supported_match = NULL;
+	filter->supported_match_num = 0;
+	return rc;
+}
+
+int
+sfc_filter_attach(struct sfc_adapter *sa)
+{
+	int rc;
+
+	sfc_log_init(sa, "entry");
+
+	rc = efx_filter_init(sa->nic);
+	if (rc != 0)
+		goto fail_filter_init;
+
+	rc = sfc_filter_cache_match_supported(sa);
+	if (rc != 0)
+		goto fail_cache_match_supported;
+
+	efx_filter_fini(sa->nic);
+
+	sfc_log_init(sa, "done");
+
+	return 0;
+
+fail_cache_match_supported:
+	efx_filter_fini(sa->nic);
+
+fail_filter_init:
+	sfc_log_init(sa, "failed %d", rc);
+	return rc;
+}
+
+void
+sfc_filter_detach(struct sfc_adapter *sa)
+{
+	struct sfc_filter *filter = &sa->filter;
+
+	sfc_log_init(sa, "entry");
+
+	rte_free(filter->supported_match);
+	filter->supported_match = NULL;
+	filter->supported_match_num = 0;
+
+	sfc_log_init(sa, "done");
+}
diff --git a/drivers/net/sfc/sfc_filter.h b/drivers/net/sfc/sfc_filter.h
new file mode 100644
index 0000000..5ba1617
--- /dev/null
+++ b/drivers/net/sfc/sfc_filter.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2017 Solarflare Communications Inc.
+ * All rights reserved.
+ *
+ * This software was jointly developed between OKTET Labs (under contract
+ * for Solarflare) and Solarflare Communications, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SFC_FILTER_H
+#define _SFC_FILTER_H
+
+#include "efx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct sfc_filter {
+	/** Number of elements in match_supported array */
+	size_t				supported_match_num;
+	/** Driver cache of supported filter match masks */
+	uint32_t			*supported_match;
+};
+
+struct sfc_adapter;
+
+int sfc_filter_attach(struct sfc_adapter *sa);
+void sfc_filter_detach(struct sfc_adapter *sa);
+
+boolean_t sfc_filter_is_match_supported(struct sfc_adapter *sa, uint32_t match);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SFC_FILTER_H */
-- 
2.9.3

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

* [PATCH 05/11] net/sfc: add flow API filters support
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (3 preceding siblings ...)
  2017-03-02 16:03 ` [PATCH 04/11] net/sfc: provide a way to check if filter is supported Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-07 13:21   ` Ferruh Yigit
  2017-03-02 16:03 ` [PATCH 06/11] net/sfc: add VLAN in " Andrew Rybchenko
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

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

Only pattern items VOID, ETH and actions VOID, QUEUE is now
supported.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 doc/guides/nics/features/sfc_efx.ini |   1 +
 doc/guides/nics/sfc_efx.rst          |  24 ++
 drivers/net/sfc/Makefile             |   1 +
 drivers/net/sfc/sfc.c                |  11 +
 drivers/net/sfc/sfc_ethdev.c         |  14 +-
 drivers/net/sfc/sfc_filter.h         |   4 +
 drivers/net/sfc/sfc_flow.c           | 693 +++++++++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_flow.h           |  62 ++++
 8 files changed, 807 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_flow.c
 create mode 100644 drivers/net/sfc/sfc_flow.h

diff --git a/doc/guides/nics/features/sfc_efx.ini b/doc/guides/nics/features/sfc_efx.ini
index 3a15baa..bb60ad6 100644
--- a/doc/guides/nics/features/sfc_efx.ini
+++ b/doc/guides/nics/features/sfc_efx.ini
@@ -19,6 +19,7 @@ RSS hash             = Y
 RSS key update       = Y
 RSS reta update      = Y
 Flow control         = Y
+Flow API             = Y
 VLAN offload         = P
 L3 checksum offload  = Y
 L4 checksum offload  = Y
diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 0a05a0a..f2e410f 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -81,6 +81,8 @@ SFC EFX PMD has support for:
 
 - Transmit VLAN insertion (if running firmware variant supports it)
 
+- Flow API
+
 
 Non-supported Features
 ----------------------
@@ -114,6 +116,28 @@ required in the receive buffer.
 It should be taken into account when mbuf pool for receive is created.
 
 
+Flow API support
+----------------
+
+Supported attributes:
+
+- Ingress
+
+Supported pattern items:
+
+- VOID
+
+- ETH (exact match of source/destination addresses, EtherType)
+
+Supported actions:
+
+- VOID
+
+- QUEUE
+
+Validating flow rules depends on the firmware variant.
+
+
 Supported NICs
 --------------
 
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index 2b7ede8..e1ee04c 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/sfc/Makefile
@@ -91,6 +91,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_rx.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_tx.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_tso.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_filter.c
+SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_flow.c
 
 VPATH += $(SRCDIR)/base
 
diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c
index 6fd8bf1..3e419b6 100644
--- a/drivers/net/sfc/sfc.c
+++ b/drivers/net/sfc/sfc.c
@@ -320,10 +320,17 @@ sfc_start(struct sfc_adapter *sa)
 	if (rc != 0)
 		goto fail_tx_start;
 
+	rc = sfc_flow_start(sa);
+	if (rc != 0)
+		goto fail_flows_insert;
+
 	sa->state = SFC_ADAPTER_STARTED;
 	sfc_log_init(sa, "done");
 	return 0;
 
+fail_flows_insert:
+	sfc_tx_stop(sa);
+
 fail_tx_start:
 	sfc_rx_stop(sa);
 
@@ -368,6 +375,7 @@ sfc_stop(struct sfc_adapter *sa)
 
 	sa->state = SFC_ADAPTER_STOPPING;
 
+	sfc_flow_stop(sa);
 	sfc_tx_stop(sa);
 	sfc_rx_stop(sa);
 	sfc_port_stop(sa);
@@ -640,6 +648,8 @@ sfc_attach(struct sfc_adapter *sa)
 	sfc_log_init(sa, "fini nic");
 	efx_nic_fini(enp);
 
+	sfc_flow_init(sa);
+
 	sa->state = SFC_ADAPTER_INITIALIZED;
 
 	sfc_log_init(sa, "done");
@@ -698,5 +708,6 @@ sfc_detach(struct sfc_adapter *sa)
 
 	sfc_mem_bar_fini(sa);
 
+	sfc_flow_fini(sa);
 	sa->state = SFC_ADAPTER_UNINITIALIZED;
 }
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 91ac0ff..0abdb4e 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -40,7 +40,7 @@
 #include "sfc_ev.h"
 #include "sfc_rx.h"
 #include "sfc_tx.h"
-
+#include "sfc_flow.h"
 
 static void
 sfc_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
@@ -1189,8 +1189,8 @@ sfc_dev_rss_reta_update(struct rte_eth_dev *dev,
 
 static int
 sfc_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,
-		    __rte_unused enum rte_filter_op filter_op,
-		    __rte_unused void *arg)
+		    enum rte_filter_op filter_op,
+		    void *arg)
 {
 	struct sfc_adapter *sa = dev->data->dev_private;
 	int rc = ENOTSUP;
@@ -1225,6 +1225,14 @@ sfc_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,
 	case RTE_ETH_FILTER_HASH:
 		sfc_err(sa, "Hash filters not supported");
 		break;
+	case RTE_ETH_FILTER_GENERIC:
+		if (filter_op != RTE_ETH_FILTER_GET) {
+			rc = EINVAL;
+		} else {
+			*(const void **)arg = &sfc_flow_ops;
+			rc = 0;
+		}
+		break;
 	default:
 		sfc_err(sa, "Unknown filter type %u", filter_type);
 		break;
diff --git a/drivers/net/sfc/sfc_filter.h b/drivers/net/sfc/sfc_filter.h
index 5ba1617..fe23eee 100644
--- a/drivers/net/sfc/sfc_filter.h
+++ b/drivers/net/sfc/sfc_filter.h
@@ -32,6 +32,8 @@
 
 #include "efx.h"
 
+#include "sfc_flow.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -41,6 +43,8 @@ struct sfc_filter {
 	size_t				supported_match_num;
 	/** Driver cache of supported filter match masks */
 	uint32_t			*supported_match;
+	/** List of flow rules */
+	struct sfc_flow_list		flow_list;
 };
 
 struct sfc_adapter;
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
new file mode 100644
index 0000000..0590756
--- /dev/null
+++ b/drivers/net/sfc/sfc_flow.c
@@ -0,0 +1,693 @@
+/*-
+ * Copyright (c) 2017 Solarflare Communications Inc.
+ * All rights reserved.
+ *
+ * This software was jointly developed between OKTET Labs (under contract
+ * for Solarflare) and Solarflare Communications, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_tailq.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_eth_ctrl.h>
+#include <rte_ether.h>
+#include <rte_flow.h>
+#include <rte_flow_driver.h>
+
+#include "efx.h"
+
+#include "sfc.h"
+#include "sfc_rx.h"
+#include "sfc_filter.h"
+#include "sfc_flow.h"
+#include "sfc_log.h"
+
+/*
+ * At now flow API is implemented in such a manner that each
+ * flow rule is converted to a hardware filter.
+ * 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.
+ */
+
+enum sfc_flow_item_layers {
+	SFC_FLOW_ITEM_ANY_LAYER = 0,
+	SFC_FLOW_ITEM_START_LAYER = 1,
+	SFC_FLOW_ITEM_L2 = 2,
+	SFC_FLOW_ITEM_L3 = 3,
+	SFC_FLOW_ITEM_L4 = 4,
+};
+
+typedef int (sfc_flow_item_parse)(const struct rte_flow_item *item,
+				  efx_filter_spec_t *spec,
+				  struct rte_flow_error *error);
+
+struct sfc_flow_item {
+	enum rte_flow_item_type type;		/* Type of item */
+	enum sfc_flow_item_layers layer;	/* Layer of item */
+	enum sfc_flow_item_layers prev_layer;	/* Previous layer of item */
+	sfc_flow_item_parse *parse;		/* Parsing function */
+};
+
+static sfc_flow_item_parse sfc_flow_parse_void;
+static sfc_flow_item_parse sfc_flow_parse_eth;
+
+static boolean_t
+sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
+{
+	uint8_t sum = 0;
+	unsigned int i;
+
+	for (i = 0; i < size; i++)
+		sum |= buf[i];
+
+	return (sum == 0) ? B_TRUE : B_FALSE;
+}
+
+/*
+ * Validate item and prepare structures spec and mask for parsing
+ */
+static int
+sfc_flow_parse_init(const struct rte_flow_item *item,
+		    const void **spec_ptr,
+		    const void **mask_ptr,
+		    const void *supp_mask,
+		    const void *def_mask,
+		    unsigned int size,
+		    struct rte_flow_error *error)
+{
+	const uint8_t *spec;
+	const uint8_t *mask;
+	const uint8_t *last;
+	uint8_t match;
+	uint8_t supp;
+	unsigned int i;
+
+	if (item == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				   "NULL item");
+		return -rte_errno;
+	}
+
+	if ((item->last != NULL || item->mask != NULL) && item->spec == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "Mask or last is set without spec");
+		return -rte_errno;
+	}
+
+	/*
+	 * If "mask" is not set, default mask is used,
+	 * but if default mask is NULL, "mask" should be set
+	 */
+	if (item->mask == NULL) {
+		if (def_mask == NULL) {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				"Mask should be specified");
+			return -rte_errno;
+		}
+
+		mask = (const uint8_t *)def_mask;
+	} else {
+		mask = (const uint8_t *)item->mask;
+	}
+
+	spec = (const uint8_t *)item->spec;
+	last = (const uint8_t *)item->last;
+
+	if (spec == NULL)
+		goto exit;
+
+	/*
+	 * If field values in "last" are either 0 or equal to the corresponding
+	 * values in "spec" then they are ignored
+	 */
+	if (last != NULL &&
+	    !sfc_flow_is_zero(last, size) &&
+	    memcmp(last, spec, size) != 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "Ranging is not supported");
+		return -rte_errno;
+	}
+
+	if (supp_mask == NULL) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Supported mask for item should be specified");
+		return -rte_errno;
+	}
+
+	/* Check that mask and spec not asks for more match than supp_mask */
+	for (i = 0; i < size; i++) {
+		match = spec[i] | mask[i];
+		supp = ((const uint8_t *)supp_mask)[i];
+
+		if ((match | supp) != supp) {
+			rte_flow_error_set(error, ENOTSUP,
+					   RTE_FLOW_ERROR_TYPE_ITEM, item,
+					   "Item's field is not supported");
+			return -rte_errno;
+		}
+	}
+
+exit:
+	*spec_ptr = spec;
+	*mask_ptr = mask;
+	return 0;
+}
+
+static int
+sfc_flow_parse_void(__rte_unused const struct rte_flow_item *item,
+		    __rte_unused efx_filter_spec_t *efx_spec,
+		    __rte_unused struct rte_flow_error *error)
+{
+	return 0;
+}
+
+/*
+ * Protocol parsers.
+ * Masking is not supported, so masks in items should be either
+ * full or empty (zeroed) and set only for supported fields which
+ * are specified in the supp_mask.
+ */
+static int
+sfc_flow_parse_eth(const struct rte_flow_item *item,
+		   efx_filter_spec_t *efx_spec,
+		   struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_eth *spec = NULL;
+	const struct rte_flow_item_eth *mask = NULL;
+	const struct rte_flow_item_eth supp_mask = {
+		.dst.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+		.src.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+		.type = 0xffff,
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_eth_mask,
+				 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 (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_MAC_ADDR_LEN);
+	} else if (!is_zero_ether_addr(&mask->dst)) {
+		goto fail_bad_mask;
+	}
+
+	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,
+			   EFX_MAC_ADDR_LEN);
+	} else if (!is_zero_ether_addr(&mask->src)) {
+		goto fail_bad_mask;
+	}
+
+	/*
+	 * Ether type is in big-endian byte order in item and
+	 * in little-endian in efx_spec, so byte swap is used
+	 */
+	if (mask->type == supp_mask.type) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
+		efx_spec->efs_ether_type = rte_bswap16(spec->type);
+	} else if (mask->type != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the ETH pattern item");
+	return -rte_errno;
+}
+
+static const struct sfc_flow_item sfc_flow_items[] = {
+	{
+		.type = RTE_FLOW_ITEM_TYPE_VOID,
+		.prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
+		.layer = SFC_FLOW_ITEM_ANY_LAYER,
+		.parse = sfc_flow_parse_void,
+	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_ETH,
+		.prev_layer = SFC_FLOW_ITEM_START_LAYER,
+		.layer = SFC_FLOW_ITEM_L2,
+		.parse = sfc_flow_parse_eth,
+	},
+};
+
+/*
+ * Protocol-independent flow API support
+ */
+static int
+sfc_flow_parse_attr(const struct rte_flow_attr *attr,
+		    struct rte_flow *flow,
+		    struct rte_flow_error *error)
+{
+	if (attr == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ATTR, NULL,
+				   "NULL attribute");
+		return -rte_errno;
+	}
+	if (attr->group != 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr,
+				   "Groups are not supported");
+		return -rte_errno;
+	}
+	if (attr->priority != 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, attr,
+				   "Priorities are not supported");
+		return -rte_errno;
+	}
+	if (attr->egress != 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attr,
+				   "Egress is not supported");
+		return -rte_errno;
+	}
+	if (attr->ingress == 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, attr,
+				   "Only ingress is supported");
+		return -rte_errno;
+	}
+
+	flow->spec.efs_flags |= EFX_FILTER_FLAG_RX;
+	flow->spec.efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
+
+	return 0;
+}
+
+/* Get item from array sfc_flow_items */
+static const struct sfc_flow_item *
+sfc_flow_get_item(enum rte_flow_item_type type)
+{
+	unsigned int i;
+
+	for (i = 0; i < RTE_DIM(sfc_flow_items); i++)
+		if (sfc_flow_items[i].type == type)
+			return &sfc_flow_items[i];
+
+	return NULL;
+}
+
+static int
+sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
+		       struct rte_flow *flow,
+		       struct rte_flow_error *error)
+{
+	int rc;
+	unsigned int prev_layer = SFC_FLOW_ITEM_ANY_LAYER;
+	const struct sfc_flow_item *item;
+
+	if (pattern == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM_NUM, NULL,
+				   "NULL pattern");
+		return -rte_errno;
+	}
+
+	for (; pattern != NULL &&
+	       pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+		item = sfc_flow_get_item(pattern->type);
+		if (item == NULL) {
+			rte_flow_error_set(error, ENOTSUP,
+					   RTE_FLOW_ERROR_TYPE_ITEM, pattern,
+					   "Unsupported pattern item");
+			return -rte_errno;
+		}
+
+		/*
+		 * Omitting one or several protocol layers at the beginning
+		 * of pattern is supported
+		 */
+		if (item->prev_layer != SFC_FLOW_ITEM_ANY_LAYER &&
+		    prev_layer != SFC_FLOW_ITEM_ANY_LAYER &&
+		    item->prev_layer != prev_layer) {
+			rte_flow_error_set(error, ENOTSUP,
+					   RTE_FLOW_ERROR_TYPE_ITEM, pattern,
+					   "Unexpected sequence of pattern items");
+			return -rte_errno;
+		}
+
+		rc = item->parse(pattern, &flow->spec, error);
+		if (rc != 0)
+			return rc;
+
+		if (item->layer != SFC_FLOW_ITEM_ANY_LAYER)
+			prev_layer = item->layer;
+	}
+
+	if (pattern == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				   "NULL item");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
+static int
+sfc_flow_parse_queue(struct sfc_adapter *sa,
+		     const struct rte_flow_action_queue *queue,
+		     struct rte_flow *flow)
+{
+	struct sfc_rxq *rxq;
+
+	if (queue->index >= sa->rxq_count)
+		return -EINVAL;
+
+	rxq = sa->rxq_info[queue->index].rxq;
+	flow->spec.efs_dmaq_id = (uint16_t)rxq->hw_index;
+
+	return 0;
+}
+
+static int
+sfc_flow_parse_actions(struct sfc_adapter *sa,
+		       const struct rte_flow_action actions[],
+		       struct rte_flow *flow,
+		       struct rte_flow_error *error)
+{
+	int rc;
+	boolean_t is_specified = B_FALSE;
+
+	if (actions == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ACTION_NUM, NULL,
+				   "NULL actions");
+		return -rte_errno;
+	}
+
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		switch (actions->type) {
+		case RTE_FLOW_ACTION_TYPE_VOID:
+			break;
+
+		case RTE_FLOW_ACTION_TYPE_QUEUE:
+			rc = sfc_flow_parse_queue(sa, actions->conf, flow);
+			if (rc != 0) {
+				rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ACTION, actions,
+					"Bad QUEUE action");
+				return -rte_errno;
+			}
+
+			is_specified = B_TRUE;
+			break;
+
+		default:
+			rte_flow_error_set(error, ENOTSUP,
+					   RTE_FLOW_ERROR_TYPE_ACTION, actions,
+					   "Action is not supported");
+			return -rte_errno;
+		}
+	}
+
+	if (!is_specified) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ACTION_NUM, actions,
+				   "Action is unspecified");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
+static int
+sfc_flow_parse(struct rte_eth_dev *dev,
+	       const struct rte_flow_attr *attr,
+	       const struct rte_flow_item pattern[],
+	       const struct rte_flow_action actions[],
+	       struct rte_flow *flow,
+	       struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	int rc;
+
+	memset(&flow->spec, 0, sizeof(flow->spec));
+
+	rc = sfc_flow_parse_attr(attr, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
+
+	rc = sfc_flow_parse_pattern(pattern, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
+
+	rc = sfc_flow_parse_actions(sa, actions, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
+
+	if (!sfc_filter_is_match_supported(sa, flow->spec.efs_match_flags)) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Flow rule pattern is not supported");
+		return -rte_errno;
+	}
+
+fail_bad_value:
+	return rc;
+}
+
+static int
+sfc_flow_validate(struct rte_eth_dev *dev,
+		  const struct rte_flow_attr *attr,
+		  const struct rte_flow_item pattern[],
+		  const struct rte_flow_action actions[],
+		  struct rte_flow_error *error)
+{
+	struct rte_flow flow;
+
+	return sfc_flow_parse(dev, attr, pattern, actions, &flow, error);
+}
+
+static struct rte_flow *
+sfc_flow_create(struct rte_eth_dev *dev,
+		const struct rte_flow_attr *attr,
+		const struct rte_flow_item pattern[],
+		const struct rte_flow_action actions[],
+		struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	struct rte_flow *flow = NULL;
+	int rc;
+
+	flow = rte_zmalloc("sfc_rte_flow", sizeof(*flow), 0);
+	if (flow == NULL) {
+		rte_flow_error_set(error, ENOMEM,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Failed to allocate memory");
+		goto fail_no_mem;
+	}
+
+	rc = sfc_flow_parse(dev, attr, pattern, actions, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
+
+	TAILQ_INSERT_TAIL(&sa->filter.flow_list, flow, entries);
+
+	sfc_adapter_lock(sa);
+
+	if (sa->state == SFC_ADAPTER_STARTED) {
+		rc = efx_filter_insert(sa->nic, &flow->spec);
+		if (rc != 0) {
+			rte_flow_error_set(error, rc,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Failed to insert filter");
+			goto fail_filter_insert;
+		}
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return flow;
+
+fail_filter_insert:
+	TAILQ_REMOVE(&sa->filter.flow_list, flow, entries);
+
+fail_bad_value:
+	rte_free(flow);
+	sfc_adapter_unlock(sa);
+
+fail_no_mem:
+	return NULL;
+}
+
+static int
+sfc_flow_remove(struct sfc_adapter *sa,
+		struct rte_flow *flow,
+		struct rte_flow_error *error)
+{
+	int rc = 0;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	if (sa->state == SFC_ADAPTER_STARTED) {
+		rc = efx_filter_remove(sa->nic, &flow->spec);
+		if (rc != 0)
+			rte_flow_error_set(error, rc,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Failed to destroy flow rule");
+	}
+
+	TAILQ_REMOVE(&sa->filter.flow_list, flow, entries);
+	rte_free(flow);
+
+	return rc;
+}
+
+static int
+sfc_flow_destroy(struct rte_eth_dev *dev,
+		 struct rte_flow *flow,
+		 struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	struct rte_flow *flow_ptr;
+	int rc = EINVAL;
+
+	sfc_adapter_lock(sa);
+
+	TAILQ_FOREACH(flow_ptr, &sa->filter.flow_list, entries) {
+		if (flow_ptr == flow)
+			rc = 0;
+	}
+	if (rc != 0) {
+		rte_flow_error_set(error, rc,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to find flow rule to destroy");
+		goto fail_bad_value;
+	}
+
+	rc = sfc_flow_remove(sa, flow, error);
+
+fail_bad_value:
+	sfc_adapter_unlock(sa);
+
+	return -rc;
+}
+
+static int
+sfc_flow_flush(struct rte_eth_dev *dev,
+	       struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	struct rte_flow *flow;
+	int rc = 0;
+	int ret = 0;
+
+	sfc_adapter_lock(sa);
+
+	while ((flow = TAILQ_FIRST(&sa->filter.flow_list)) != NULL) {
+		rc = sfc_flow_remove(sa, flow, error);
+		if (rc != 0)
+			ret = rc;
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return -ret;
+}
+
+const struct rte_flow_ops sfc_flow_ops = {
+	.validate = sfc_flow_validate,
+	.create = sfc_flow_create,
+	.destroy = sfc_flow_destroy,
+	.flush = sfc_flow_flush,
+	.query = NULL,
+};
+
+void
+sfc_flow_init(struct sfc_adapter *sa)
+{
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	TAILQ_INIT(&sa->filter.flow_list);
+}
+
+void
+sfc_flow_fini(struct sfc_adapter *sa)
+{
+	struct rte_flow *flow;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	while ((flow = TAILQ_FIRST(&sa->filter.flow_list)) != NULL) {
+		TAILQ_REMOVE(&sa->filter.flow_list, flow, entries);
+		rte_free(flow);
+	}
+}
+
+void
+sfc_flow_stop(struct sfc_adapter *sa)
+{
+	struct rte_flow *flow;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	TAILQ_FOREACH(flow, &sa->filter.flow_list, entries)
+		efx_filter_remove(sa->nic, &flow->spec);
+}
+
+int
+sfc_flow_start(struct sfc_adapter *sa)
+{
+	struct rte_flow *flow;
+	int rc = 0;
+
+	sfc_log_init(sa, "entry");
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	TAILQ_FOREACH(flow, &sa->filter.flow_list, entries) {
+		rc = efx_filter_insert(sa->nic, &flow->spec);
+		if (rc != 0)
+			goto fail_bad_flow;
+	}
+
+	sfc_log_init(sa, "done");
+
+fail_bad_flow:
+	return rc;
+}
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
new file mode 100644
index 0000000..d38ac35
--- /dev/null
+++ b/drivers/net/sfc/sfc_flow.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2017 Solarflare Communications Inc.
+ * All rights reserved.
+ *
+ * This software was jointly developed between OKTET Labs (under contract
+ * for Solarflare) and Solarflare Communications, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SFC_FLOW_H
+#define _SFC_FLOW_H
+
+#include <rte_tailq.h>
+#include <rte_flow_driver.h>
+
+#include "efx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* PMD-specific definition of the opaque type from rte_flow.h */
+struct rte_flow {
+	efx_filter_spec_t spec;		/* filter specification */
+	TAILQ_ENTRY(rte_flow) entries;	/* flow list entries */
+};
+
+TAILQ_HEAD(sfc_flow_list, rte_flow);
+
+extern const struct rte_flow_ops sfc_flow_ops;
+
+struct sfc_adapter;
+
+void sfc_flow_init(struct sfc_adapter *sa);
+void sfc_flow_fini(struct sfc_adapter *sa);
+int sfc_flow_start(struct sfc_adapter *sa);
+void sfc_flow_stop(struct sfc_adapter *sa);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SFC_FLOW_H */
-- 
2.9.3

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

* [PATCH 06/11] net/sfc: add VLAN in flow API filters support
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (4 preceding siblings ...)
  2017-03-02 16:03 ` [PATCH 05/11] net/sfc: add flow API filters support Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 07/11] net/sfc: add IPV4 " Andrew Rybchenko
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

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

Exact match of VLAN ID bits is supported only and required in VLAN item.
Mask to match VLAN ID bits only is required, default mask to match entire
TCI is not supported.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  2 ++
 drivers/net/sfc/sfc_flow.c  | 63 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index f2e410f..71dc99f 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -129,6 +129,8 @@ Supported pattern items:
 
 - ETH (exact match of source/destination addresses, EtherType)
 
+- VLAN (exact match of VID, double-tagging is supported)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 0590756..ff55631 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -72,6 +72,7 @@ struct sfc_flow_item {
 
 static sfc_flow_item_parse sfc_flow_parse_void;
 static sfc_flow_item_parse sfc_flow_parse_eth;
+static sfc_flow_item_parse sfc_flow_parse_vlan;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -258,6 +259,62 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+static int
+sfc_flow_parse_vlan(const struct rte_flow_item *item,
+		    efx_filter_spec_t *efx_spec,
+		    struct rte_flow_error *error)
+{
+	int rc;
+	uint16_t vid;
+	const struct rte_flow_item_vlan *spec = NULL;
+	const struct rte_flow_item_vlan *mask = NULL;
+	const struct rte_flow_item_vlan supp_mask = {
+		.tci = rte_cpu_to_be_16(ETH_VLAN_ID_MAX),
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 NULL,
+				 sizeof(struct rte_flow_item_vlan),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * VID is in big-endian byte order in item and
+	 * in little-endian in efx_spec, so byte swap is used.
+	 * If two VLAN items are included, the first matches
+	 * the outer tag and the next matches the inner tag.
+	 */
+	if (mask->tci == supp_mask.tci) {
+		vid = rte_bswap16(spec->tci);
+
+		if (!(efx_spec->efs_match_flags &
+		      EFX_FILTER_MATCH_OUTER_VID)) {
+			efx_spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
+			efx_spec->efs_outer_vid = vid;
+		} else if (!(efx_spec->efs_match_flags &
+			     EFX_FILTER_MATCH_INNER_VID)) {
+			efx_spec->efs_match_flags |= EFX_FILTER_MATCH_INNER_VID;
+			efx_spec->efs_inner_vid = vid;
+		} else {
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ITEM, item,
+					   "More than two VLAN items");
+			return -rte_errno;
+		}
+	} else {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "VLAN ID in TCI match is required");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -271,6 +328,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L2,
 		.parse = sfc_flow_parse_eth,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_VLAN,
+		.prev_layer = SFC_FLOW_ITEM_L2,
+		.layer = SFC_FLOW_ITEM_L2,
+		.parse = sfc_flow_parse_vlan,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH 07/11] net/sfc: add IPV4 in flow API filters support
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (5 preceding siblings ...)
  2017-03-02 16:03 ` [PATCH 06/11] net/sfc: add VLAN in " Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-07 13:21   ` Ferruh Yigit
  2017-03-02 16:03 ` [PATCH 08/11] net/sfc: add IPV6 " Andrew Rybchenko
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

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

Exact match of IP protocol, source and destination
addresses is supported by parser.
EtherType match is enforced to IPv4 EtherType.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  3 ++
 drivers/net/sfc/sfc_flow.c  | 82 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 71dc99f..12ac308 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -131,6 +131,9 @@ Supported pattern items:
 
 - VLAN (exact match of VID, double-tagging is supported)
 
+- IPV4 (exact match of source/destination addresses,
+  IP transport protocol)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index ff55631..ed71ec0 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -73,6 +73,7 @@ struct sfc_flow_item {
 static sfc_flow_item_parse sfc_flow_parse_void;
 static sfc_flow_item_parse sfc_flow_parse_eth;
 static sfc_flow_item_parse sfc_flow_parse_vlan;
+static sfc_flow_item_parse sfc_flow_parse_ipv4;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -315,6 +316,81 @@ sfc_flow_parse_vlan(const struct rte_flow_item *item,
 	return 0;
 }
 
+static int
+sfc_flow_parse_ipv4(const struct rte_flow_item *item,
+		    efx_filter_spec_t *efx_spec,
+		    struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_ipv4 *spec = NULL;
+	const struct rte_flow_item_ipv4 *mask = NULL;
+	const uint16_t ether_type_ipv4 = rte_cpu_to_le_16(EFX_ETHER_TYPE_IPV4);
+	const struct rte_flow_item_ipv4 supp_mask = {
+		.hdr = {
+			.src_addr = 0xffffffff,
+			.dst_addr = 0xffffffff,
+			.next_proto_id = 0xff,
+		}
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_ipv4_mask,
+				 sizeof(struct rte_flow_item_ipv4),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * Filtering by IPv4 source and destination addresses requires
+	 * the appropriate ETHER_TYPE in hardware filters
+	 */
+	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
+		efx_spec->efs_ether_type = ether_type_ipv4;
+	} else if (efx_spec->efs_ether_type != ether_type_ipv4) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Ethertype in pattern with IPV4 item should be appropriate");
+		return -rte_errno;
+	}
+
+	if (spec == NULL)
+		return 0;
+
+	/* IPv4 adresses are in big-endian byte order in item and in efx_spec */
+	if (mask->hdr.src_addr == supp_mask.hdr.src_addr) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_HOST;
+		efx_spec->efs_rem_host.eo_u32[0] = spec->hdr.src_addr;
+	} else if (mask->hdr.src_addr != 0) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.dst_addr == supp_mask.hdr.dst_addr) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_HOST;
+		efx_spec->efs_loc_host.eo_u32[0] = spec->hdr.dst_addr;
+	} else if (mask->hdr.dst_addr != 0) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.next_proto_id == supp_mask.hdr.next_proto_id) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
+		efx_spec->efs_ip_proto = spec->hdr.next_proto_id;
+	} else if (mask->hdr.next_proto_id != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the IPV4 pattern item");
+	return -rte_errno;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -334,6 +410,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L2,
 		.parse = sfc_flow_parse_vlan,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_IPV4,
+		.prev_layer = SFC_FLOW_ITEM_L2,
+		.layer = SFC_FLOW_ITEM_L3,
+		.parse = sfc_flow_parse_ipv4,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH 08/11] net/sfc: add IPV6 in flow API filters support
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (6 preceding siblings ...)
  2017-03-02 16:03 ` [PATCH 07/11] net/sfc: add IPV4 " Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 09/11] net/sfc: add TCP " Andrew Rybchenko
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

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

Exact match of IP protocol, source and destination
addresses is supported by parser.
EtherType match is enforced to IPv6 EtherType.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |   3 ++
 drivers/net/sfc/sfc_flow.c  | 100 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 12ac308..a4ea162 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -134,6 +134,9 @@ Supported pattern items:
 - IPV4 (exact match of source/destination addresses,
   IP transport protocol)
 
+- IPV6 (exact match of source/destination addresses,
+  IP transport protocol)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index ed71ec0..dcc19ff 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -74,6 +74,7 @@ static sfc_flow_item_parse sfc_flow_parse_void;
 static sfc_flow_item_parse sfc_flow_parse_eth;
 static sfc_flow_item_parse sfc_flow_parse_vlan;
 static sfc_flow_item_parse sfc_flow_parse_ipv4;
+static sfc_flow_item_parse sfc_flow_parse_ipv6;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -391,6 +392,99 @@ sfc_flow_parse_ipv4(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+static int
+sfc_flow_parse_ipv6(const struct rte_flow_item *item,
+		    efx_filter_spec_t *efx_spec,
+		    struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_ipv6 *spec = NULL;
+	const struct rte_flow_item_ipv6 *mask = NULL;
+	const uint16_t ether_type_ipv6 = rte_cpu_to_le_16(EFX_ETHER_TYPE_IPV6);
+	const struct rte_flow_item_ipv6 supp_mask = {
+		.hdr = {
+			.src_addr = { 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff },
+			.dst_addr = { 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff },
+			.proto = 0xff,
+		}
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_ipv6_mask,
+				 sizeof(struct rte_flow_item_ipv6),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * Filtering by IPv6 source and destination addresses requires
+	 * the appropriate ETHER_TYPE in hardware filters
+	 */
+	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
+		efx_spec->efs_ether_type = ether_type_ipv6;
+	} else if (efx_spec->efs_ether_type != ether_type_ipv6) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Ethertype in pattern with IPV6 item should be appropriate");
+		return -rte_errno;
+	}
+
+	if (spec == NULL)
+		return 0;
+
+	/* IPv6 adresses are in big-endian byte order in item and in efx_spec */
+	if (memcmp(mask->hdr.src_addr, supp_mask.hdr.src_addr,
+		   sizeof(mask->hdr.src_addr)) == 0) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_HOST;
+
+		RTE_BUILD_BUG_ON(sizeof(efx_spec->efs_rem_host) !=
+				 sizeof(spec->hdr.src_addr));
+		rte_memcpy(&efx_spec->efs_rem_host, spec->hdr.src_addr,
+			   sizeof(efx_spec->efs_rem_host));
+	} else if (!sfc_flow_is_zero(mask->hdr.src_addr,
+				     sizeof(mask->hdr.src_addr))) {
+		goto fail_bad_mask;
+	}
+
+	if (memcmp(mask->hdr.dst_addr, supp_mask.hdr.dst_addr,
+		   sizeof(mask->hdr.dst_addr)) == 0) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_HOST;
+
+		RTE_BUILD_BUG_ON(sizeof(efx_spec->efs_loc_host) !=
+				 sizeof(spec->hdr.dst_addr));
+		rte_memcpy(&efx_spec->efs_loc_host, spec->hdr.dst_addr,
+			   sizeof(efx_spec->efs_loc_host));
+	} else if (!sfc_flow_is_zero(mask->hdr.dst_addr,
+				     sizeof(mask->hdr.dst_addr))) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.proto == supp_mask.hdr.proto) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
+		efx_spec->efs_ip_proto = spec->hdr.proto;
+	} else if (mask->hdr.proto != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the IPV6 pattern item");
+	return -rte_errno;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -416,6 +510,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L3,
 		.parse = sfc_flow_parse_ipv4,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_IPV6,
+		.prev_layer = SFC_FLOW_ITEM_L2,
+		.layer = SFC_FLOW_ITEM_L3,
+		.parse = sfc_flow_parse_ipv6,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH 09/11] net/sfc: add TCP in flow API filters support
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (7 preceding siblings ...)
  2017-03-02 16:03 ` [PATCH 08/11] net/sfc: add IPV6 " Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 10/11] net/sfc: add UDP " Andrew Rybchenko
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

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

Exact match of source and destination ports is supported by parser.
IP protocol match is enforced to TCP.

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

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index a4ea162..7e00fdc 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -137,6 +137,8 @@ Supported pattern items:
 - IPV6 (exact match of source/destination addresses,
   IP transport protocol)
 
+- TCP (exact match of source/destination ports)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index dcc19ff..6825d04 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -75,6 +75,7 @@ static sfc_flow_item_parse sfc_flow_parse_eth;
 static sfc_flow_item_parse sfc_flow_parse_vlan;
 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 boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -485,6 +486,75 @@ sfc_flow_parse_ipv6(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+static int
+sfc_flow_parse_tcp(const struct rte_flow_item *item,
+		   efx_filter_spec_t *efx_spec,
+		   struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_tcp *spec = NULL;
+	const struct rte_flow_item_tcp *mask = NULL;
+	const struct rte_flow_item_tcp supp_mask = {
+		.hdr = {
+			.src_port = 0xffff,
+			.dst_port = 0xffff,
+		}
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_tcp_mask,
+				 sizeof(struct rte_flow_item_tcp),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * Filtering by TCP source and destination ports requires
+	 * the appropriate IP_PROTO in hardware filters
+	 */
+	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 = EFX_IPPROTO_TCP;
+	} else if (efx_spec->efs_ip_proto != EFX_IPPROTO_TCP) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"IP proto in pattern with TCP item should be appropriate");
+		return -rte_errno;
+	}
+
+	if (spec == NULL)
+		return 0;
+
+	/*
+	 * Source and destination ports are in big-endian byte order in item and
+	 * in little-endian in efx_spec, so byte swap is used
+	 */
+	if (mask->hdr.src_port == supp_mask.hdr.src_port) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_PORT;
+		efx_spec->efs_rem_port = rte_bswap16(spec->hdr.src_port);
+	} else if (mask->hdr.src_port != 0) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.dst_port == supp_mask.hdr.dst_port) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_PORT;
+		efx_spec->efs_loc_port = rte_bswap16(spec->hdr.dst_port);
+	} else if (mask->hdr.dst_port != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the TCP pattern item");
+	return -rte_errno;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -516,6 +586,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L3,
 		.parse = sfc_flow_parse_ipv6,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_TCP,
+		.prev_layer = SFC_FLOW_ITEM_L3,
+		.layer = SFC_FLOW_ITEM_L4,
+		.parse = sfc_flow_parse_tcp,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH 10/11] net/sfc: add UDP in flow API filters support
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (8 preceding siblings ...)
  2017-03-02 16:03 ` [PATCH 09/11] net/sfc: add TCP " Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-02 16:03 ` [PATCH 11/11] net/sfc: add unknown unicast/multicast match in flow API Andrew Rybchenko
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

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

Exact match of source and destination ports is supported by parser.
IP protocol match is enforced to UDP.

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

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 7e00fdc..4d91b1d 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -139,6 +139,8 @@ Supported pattern items:
 
 - TCP (exact match of source/destination ports)
 
+- UDP (exact match of source/destination ports)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 6825d04..7a1f38f 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -76,6 +76,7 @@ static sfc_flow_item_parse sfc_flow_parse_vlan;
 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 boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -555,6 +556,75 @@ sfc_flow_parse_tcp(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+static int
+sfc_flow_parse_udp(const struct rte_flow_item *item,
+		   efx_filter_spec_t *efx_spec,
+		   struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_udp *spec = NULL;
+	const struct rte_flow_item_udp *mask = NULL;
+	const struct rte_flow_item_udp supp_mask = {
+		.hdr = {
+			.src_port = 0xffff,
+			.dst_port = 0xffff,
+		}
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_udp_mask,
+				 sizeof(struct rte_flow_item_udp),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * Filtering by UDP source and destination ports requires
+	 * the appropriate IP_PROTO in hardware filters
+	 */
+	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 = EFX_IPPROTO_UDP;
+	} else if (efx_spec->efs_ip_proto != EFX_IPPROTO_UDP) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"IP proto in pattern with UDP item should be appropriate");
+		return -rte_errno;
+	}
+
+	if (spec == NULL)
+		return 0;
+
+	/*
+	 * Source and destination ports are in big-endian byte order in item and
+	 * in little-endian in efx_spec, so byte swap is used
+	 */
+	if (mask->hdr.src_port == supp_mask.hdr.src_port) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_PORT;
+		efx_spec->efs_rem_port = rte_bswap16(spec->hdr.src_port);
+	} else if (mask->hdr.src_port != 0) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.dst_port == supp_mask.hdr.dst_port) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_PORT;
+		efx_spec->efs_loc_port = rte_bswap16(spec->hdr.dst_port);
+	} else if (mask->hdr.dst_port != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the UDP pattern item");
+	return -rte_errno;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -592,6 +662,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L4,
 		.parse = sfc_flow_parse_tcp,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_UDP,
+		.prev_layer = SFC_FLOW_ITEM_L3,
+		.layer = SFC_FLOW_ITEM_L4,
+		.parse = sfc_flow_parse_udp,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH 11/11] net/sfc: add unknown unicast/multicast match in flow API
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (9 preceding siblings ...)
  2017-03-02 16:03 ` [PATCH 10/11] net/sfc: add UDP " Andrew Rybchenko
@ 2017-03-02 16:03 ` Andrew Rybchenko
  2017-03-07 13:27 ` [PATCH 00/11] Support flow API in Solarflare PMD Ferruh Yigit
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
  12 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-02 16:03 UTC (permalink / raw)
  To: dev; +Cc: Roman Zhukov

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

Support individual/group destination address match (unknown unicast
and all-multicast correspondingly in terms of firmware).

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst | 11 ++++++++++-
 drivers/net/sfc/sfc_flow.c  | 14 ++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 4d91b1d..8229d7d 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -127,7 +127,8 @@ Supported pattern items:
 
 - VOID
 
-- ETH (exact match of source/destination addresses, EtherType)
+- ETH (exact match of source/destination addresses, individual/group match
+  of destination address, EtherType)
 
 - VLAN (exact match of VID, double-tagging is supported)
 
@@ -149,6 +150,14 @@ Supported actions:
 
 Validating flow rules depends on the firmware variant.
 
+Ethernet destinaton individual/group match
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Ethernet item supports I/G matching, if only the corresponding bit is set
+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.
+
 
 Supported NICs
 --------------
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 7a1f38f..defdb2f 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -212,6 +212,8 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 		.src.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
 		.type = 0xffff,
 	};
+	const uint8_t ig_mask[EFX_MAC_ADDR_LEN] =
+		{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
 	rc = sfc_flow_parse_init(item,
 				 (const void **)&spec,
@@ -227,10 +229,22 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 	if (spec == NULL)
 		return 0;
 
+	/*
+	 * In addition to full and empty masks of destination address,
+	 * individual/group mask is also supported
+	 */
 	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_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_FILTER_MATCH_UNKNOWN_UCAST_DST;
+		else
+			efx_spec->efs_match_flags |=
+				EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
 	} else if (!is_zero_ether_addr(&mask->dst)) {
 		goto fail_bad_mask;
 	}
-- 
2.9.3

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

* Re: [PATCH 05/11] net/sfc: add flow API filters support
  2017-03-02 16:03 ` [PATCH 05/11] net/sfc: add flow API filters support Andrew Rybchenko
@ 2017-03-07 13:21   ` Ferruh Yigit
  2017-03-09 15:29     ` Andrew Rybchenko
  0 siblings, 1 reply; 33+ messages in thread
From: Ferruh Yigit @ 2017-03-07 13:21 UTC (permalink / raw)
  To: Andrew Rybchenko, dev; +Cc: Roman Zhukov

On 3/2/2017 4:03 PM, Andrew Rybchenko wrote:
> From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
> 
> Only pattern items VOID, ETH and actions VOID, QUEUE is now
> supported.
> 
> Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>

<...>

> diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
> new file mode 100644
> index 0000000..0590756
> --- /dev/null
> +++ b/drivers/net/sfc/sfc_flow.c
> @@ -0,0 +1,693 @@
> +/*-
> + * Copyright (c) 2017 Solarflare Communications Inc.
> + * All rights reserved.

Missing "BSD LICENSE" line. This is same for all new files.
I think this discussed before, I don't know if that line is mandatory,
but can be good to have at least to be consistent to rest of the codes.

<...>

> +/*
> + * At now flow API is implemented in such a manner that each
> + * flow rule is converted to a hardware filter.
> + * 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.
> + */
> +
> +enum sfc_flow_item_layers {
> +	SFC_FLOW_ITEM_ANY_LAYER = 0,
> +	SFC_FLOW_ITEM_START_LAYER = 1,
> +	SFC_FLOW_ITEM_L2 = 2,
> +	SFC_FLOW_ITEM_L3 = 3,
> +	SFC_FLOW_ITEM_L4 = 4,
> +};

No need to explicitly assign default values.

<...>

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

* Re: [PATCH 07/11] net/sfc: add IPV4 in flow API filters support
  2017-03-02 16:03 ` [PATCH 07/11] net/sfc: add IPV4 " Andrew Rybchenko
@ 2017-03-07 13:21   ` Ferruh Yigit
  0 siblings, 0 replies; 33+ messages in thread
From: Ferruh Yigit @ 2017-03-07 13:21 UTC (permalink / raw)
  To: Andrew Rybchenko, dev; +Cc: Roman Zhukov

On 3/2/2017 4:03 PM, Andrew Rybchenko wrote:
> From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
> 
> Exact match of IP protocol, source and destination
> addresses is supported by parser.
> EtherType match is enforced to IPv4 EtherType.
> 
> Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
> Reviewed-by: Andrew Lee <alee@solarflare.com>

<...>

>  
> +static int
> +sfc_flow_parse_ipv4(const struct rte_flow_item *item,

Adding a function comment to all parser types can be useful. What do you
think?

It can help to verify implementation against intention. Also gives quick
information about supported parser without digging from function each time.

A list of valid/expected spec, mask and last values for that parser.
Also details like "if the mask is NULL, default mask will be used" can
be documented here.

> +		    efx_filter_spec_t *efx_spec,
> +		    struct rte_flow_error *error)
> +{
<...>

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

* Re: [PATCH 02/11] net/sfc/base: improve API to get supported filter matches
  2017-03-02 16:03 ` [PATCH 02/11] net/sfc/base: improve API to get supported filter matches Andrew Rybchenko
@ 2017-03-07 13:25   ` Ferruh Yigit
  2017-03-07 14:47     ` Andrew Rybchenko
  0 siblings, 1 reply; 33+ messages in thread
From: Ferruh Yigit @ 2017-03-07 13:25 UTC (permalink / raw)
  To: Andrew Rybchenko, dev; +Cc: Mark Spender

On 3/2/2017 4:03 PM, Andrew Rybchenko wrote:
> From: Mark Spender <mspender@solarflare.com>
> 
> The previous API had various problems, including the length of the
> caller provided buffer not being specified, no means being available
> to discover how big the buffer needs to be, and a lack of clarity of
> what the resulting list contains.
> 
> To improve it:
> - add the buffer length as a parameter
> - if the provided buffer is too short, fail with ENOSPC and return
>   the required length
> - ensure that the list contents are valid and add comments describing it
> 
> It is safe to change this API as, unsuprisingly, it has no users.
> 
> Signed-off-by: Mark Spender <mspender@solarflare.com>
> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>

<...>

>  
> -	*length = index;
> -	memcpy(list, rx_matches, *length);
> +	memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));

Checkpatch warning:

WARNING:SPACING: space prohibited between function name and open
parenthesis '('
#326: FILE: drivers/net/sfc/base/efx_filter.c:1410:
+       memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]))

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

* Re: [PATCH 00/11] Support flow API in Solarflare PMD
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (10 preceding siblings ...)
  2017-03-02 16:03 ` [PATCH 11/11] net/sfc: add unknown unicast/multicast match in flow API Andrew Rybchenko
@ 2017-03-07 13:27 ` Ferruh Yigit
  2017-03-07 14:56   ` Andrew Rybchenko
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
  12 siblings, 1 reply; 33+ messages in thread
From: Ferruh Yigit @ 2017-03-07 13:27 UTC (permalink / raw)
  To: Andrew Rybchenko, dev

On 3/2/2017 4:03 PM, Andrew Rybchenko wrote:
> Support simple queue destination flow API filters in Solarflare
> libefx-based PMD including:
>  - Ethernet source/destination, EtherType exact matching
>  - VLAN ID exact matching including double-tagging
>  - IPv4/6 source/destination and IP protocol exact matching
>  - TCP/UDP source/destination exact matching
> 
> Supported combinations of fields mentioned above depend on
> firmware (including running variant) and correctly processed by
> validate callback.
> 
> 
> Andrew Rybchenko (2):
>   net/sfc: implement dummy filter control callback
>   net/sfc: provide a way to check if filter is supported
> 
> Mark Spender (2):
>   net/sfc/base: split local MAC I/G back into separate flags
>   net/sfc/base: improve API to get supported filter matches
> 
> Roman Zhukov (7):
>   net/sfc: add flow API filters support
>   net/sfc: add VLAN in flow API filters support
>   net/sfc: add IPV4 in flow API filters support
>   net/sfc: add IPV6 in flow API filters support
>   net/sfc: add TCP in flow API filters support
>   net/sfc: add UDP in flow API filters support
>   net/sfc: add unknown unicast/multicast match in flow API

Hi Andrew,

Patchset looks good overall, I just did some really minor comments, can
you please address them in next version of the patchset?

Also can you please update release notes, to announce "SFC rte_flow
support" ?

Thanks,
ferruh

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

* Re: [PATCH 02/11] net/sfc/base: improve API to get supported filter matches
  2017-03-07 13:25   ` Ferruh Yigit
@ 2017-03-07 14:47     ` Andrew Rybchenko
  2017-03-07 14:56       ` Ferruh Yigit
  0 siblings, 1 reply; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-07 14:47 UTC (permalink / raw)
  To: Ferruh Yigit, dev; +Cc: Mark Spender

On 03/07/2017 04:25 PM, Ferruh Yigit wrote:
> On 3/2/2017 4:03 PM, Andrew Rybchenko wrote:
>> From: Mark Spender <mspender@solarflare.com>
>>
>> The previous API had various problems, including the length of the
>> caller provided buffer not being specified, no means being available
>> to discover how big the buffer needs to be, and a lack of clarity of
>> what the resulting list contains.
>>
>> To improve it:
>> - add the buffer length as a parameter
>> - if the provided buffer is too short, fail with ENOSPC and return
>>    the required length
>> - ensure that the list contents are valid and add comments describing it
>>
>> It is safe to change this API as, unsuprisingly, it has no users.
>>
>> Signed-off-by: Mark Spender <mspender@solarflare.com>
>> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
> <...>
>
>>   
>> -	*length = index;
>> -	memcpy(list, rx_matches, *length);
>> +	memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
> Checkpatch warning:
>
> WARNING:SPACING: space prohibited between function name and open
> parenthesis '('
> #326: FILE: drivers/net/sfc/base/efx_filter.c:1410:
> +       memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]))


Ferruh,

it is a base driver patch and base driver has a bit different coding 
conventions
(due to usage on other operating systems). I hope it is not a problem.

Thanks,
Andrew.

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

* Re: [PATCH 02/11] net/sfc/base: improve API to get supported filter matches
  2017-03-07 14:47     ` Andrew Rybchenko
@ 2017-03-07 14:56       ` Ferruh Yigit
  0 siblings, 0 replies; 33+ messages in thread
From: Ferruh Yigit @ 2017-03-07 14:56 UTC (permalink / raw)
  To: Andrew Rybchenko, dev; +Cc: Mark Spender

On 3/7/2017 2:47 PM, Andrew Rybchenko wrote:
> On 03/07/2017 04:25 PM, Ferruh Yigit wrote:
>> On 3/2/2017 4:03 PM, Andrew Rybchenko wrote:
>>> From: Mark Spender <mspender@solarflare.com>
>>>
>>> The previous API had various problems, including the length of the
>>> caller provided buffer not being specified, no means being available
>>> to discover how big the buffer needs to be, and a lack of clarity of
>>> what the resulting list contains.
>>>
>>> To improve it:
>>> - add the buffer length as a parameter
>>> - if the provided buffer is too short, fail with ENOSPC and return
>>>   the required length
>>> - ensure that the list contents are valid and add comments describing it
>>>
>>> It is safe to change this API as, unsuprisingly, it has no users.
>>>
>>> Signed-off-by: Mark Spender <mspender@solarflare.com>
>>> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
>> <...>
>>
>>>  
>>> -	*length = index;
>>> -	memcpy(list, rx_matches, *length);
>>> +	memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
>> Checkpatch warning:
>>
>> WARNING:SPACING: space prohibited between function name and open
>> parenthesis '('
>> #326: FILE: drivers/net/sfc/base/efx_filter.c:1410:
>> +       memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]))
> 
> 
> Ferruh,
> 
> it is a base driver patch and base driver has a bit different coding
> conventions
> (due to usage on other operating systems). I hope it is not a problem.

It is a whitespace warning, I think it can be OK for base code.

> 
> Thanks,
> Andrew.

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

* Re: [PATCH 00/11] Support flow API in Solarflare PMD
  2017-03-07 13:27 ` [PATCH 00/11] Support flow API in Solarflare PMD Ferruh Yigit
@ 2017-03-07 14:56   ` Andrew Rybchenko
  0 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-07 14:56 UTC (permalink / raw)
  To: Ferruh Yigit, dev

On 03/07/2017 04:27 PM, Ferruh Yigit wrote:
> On 3/2/2017 4:03 PM, Andrew Rybchenko wrote:
>> Support simple queue destination flow API filters in Solarflare
>> libefx-based PMD including:
>>   - Ethernet source/destination, EtherType exact matching
>>   - VLAN ID exact matching including double-tagging
>>   - IPv4/6 source/destination and IP protocol exact matching
>>   - TCP/UDP source/destination exact matching
>>
>> Supported combinations of fields mentioned above depend on
>> firmware (including running variant) and correctly processed by
>> validate callback.
>>
>>
>> Andrew Rybchenko (2):
>>    net/sfc: implement dummy filter control callback
>>    net/sfc: provide a way to check if filter is supported
>>
>> Mark Spender (2):
>>    net/sfc/base: split local MAC I/G back into separate flags
>>    net/sfc/base: improve API to get supported filter matches
>>
>> Roman Zhukov (7):
>>    net/sfc: add flow API filters support
>>    net/sfc: add VLAN in flow API filters support
>>    net/sfc: add IPV4 in flow API filters support
>>    net/sfc: add IPV6 in flow API filters support
>>    net/sfc: add TCP in flow API filters support
>>    net/sfc: add UDP in flow API filters support
>>    net/sfc: add unknown unicast/multicast match in flow API
> Hi Andrew,
>
> Patchset looks good overall, I just did some really minor comments, can
> you please address them in next version of the patchset?

Hi Ferruh,

thanks for the review. We'll address the review notes in v2.

> Also can you please update release notes, to announce "SFC rte_flow
> support" ?

Will do. I remember about roadmap, but I'm always forgetting about 
release notes.

Thanks,
Andrew.

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

* [PATCH v2 00/11] Support flow API in Solarflare PMD
  2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
                   ` (11 preceding siblings ...)
  2017-03-07 13:27 ` [PATCH 00/11] Support flow API in Solarflare PMD Ferruh Yigit
@ 2017-03-09 15:26 ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 01/11] net/sfc/base: split local MAC I/G back into separate flags Andrew Rybchenko
                     ` (11 more replies)
  12 siblings, 12 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit

Support simple queue destination flow API filters in Solarflare
libefx-based PMD including:
 - Ethernet source/destination, EtherType exact matching
 - VLAN ID exact matching including double-tagging
 - IPv4/6 source/destination and IP protocol exact matching
 - TCP/UDP source/destination exact matching

Supported combinations of fields mentioned above depend on
firmware (including running variant) and correctly processed by
validate callback.

v1 -> v2:
 - fix spelling
 - add comments to protocol parsers
 - add release notes
 - add l3 and l4 layer enum items on demand

Andrew Rybchenko (2):
  net/sfc: implement dummy filter control callback
  net/sfc: provide a way to check if filter is supported

Mark Spender (2):
  net/sfc/base: split local MAC I/G back into separate flags
  net/sfc/base: improve API to get supported filter matches

Roman Zhukov (7):
  net/sfc: add flow API filters support
  net/sfc: add VLAN in flow API filters support
  net/sfc: add IPV4 in flow API filters support
  net/sfc: add IPV6 in flow API filters support
  net/sfc: add TCP in flow API filters support
  net/sfc: add UDP in flow API filters support
  net/sfc: add unknown unicast/multicast match in flow API

 doc/guides/nics/features/sfc_efx.ini   |    1 +
 doc/guides/nics/sfc_efx.rst            |   45 ++
 doc/guides/rel_notes/release_17_05.rst |    4 +
 drivers/net/sfc/Makefile               |    2 +
 drivers/net/sfc/base/ef10_filter.c     |  134 ++--
 drivers/net/sfc/base/ef10_impl.h       |    7 +-
 drivers/net/sfc/base/efx.h             |   17 +-
 drivers/net/sfc/base/efx_filter.c      |   76 +-
 drivers/net/sfc/base/efx_impl.h        |    3 +-
 drivers/net/sfc/sfc.c                  |   18 +
 drivers/net/sfc/sfc.h                  |    3 +
 drivers/net/sfc/sfc_ethdev.c           |   59 +-
 drivers/net/sfc/sfc_filter.c           |  135 ++++
 drivers/net/sfc/sfc_filter.h           |   60 ++
 drivers/net/sfc/sfc_flow.c             | 1181 ++++++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_flow.h             |   62 ++
 16 files changed, 1711 insertions(+), 96 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_filter.c
 create mode 100644 drivers/net/sfc/sfc_filter.h
 create mode 100644 drivers/net/sfc/sfc_flow.c
 create mode 100644 drivers/net/sfc/sfc_flow.h

-- 
2.9.3

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

* [PATCH v2 01/11] net/sfc/base: split local MAC I/G back into separate flags
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 02/11] net/sfc/base: improve API to get supported filter matches Andrew Rybchenko
                     ` (10 subsequent siblings)
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit, Mark Spender

From: Mark Spender <mspender@solarflare.com>

The flag EFX_FILTER_MATCH_LOC_MAC_IG to represent filtering on the
individual/group bit of the MAC address (with the two cases being
distingusished by the MAC address in the filter specification) was
introduced to mirror the Linux driver filtering code, but the
implementations are different enough anyway that it isn't of much
value.

Having separate flags for unknown unicast and multicast simplifies
the code and allows the set of flags to match those used by MCDI.

It will also makes it easier to report whether these filters are
supported.

In the MCDI definitions, the unknown multicast and unicast flags
have the values 0x40000000 and 0x80000000 respectively, and so using
the same values for simplicity requires 32 bits in the filter
specification to store the flags. This means the structure is now
a little bigger than 64 bytes, but filters are not often used on
critical paths so this shouldn't have much impact - on Linux they
are also bigger than they used to be.

Signed-off-by: Mark Spender <mspender@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 drivers/net/sfc/base/ef10_filter.c | 48 ++++----------------------------------
 drivers/net/sfc/base/efx.h         | 10 ++++----
 drivers/net/sfc/base/efx_filter.c  |  8 ++-----
 3 files changed, 12 insertions(+), 54 deletions(-)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index c161977..f520147 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -142,6 +142,10 @@ ef10_filter_init(
 	    MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_OUTER_VLAN));
 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
 	    MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_IP_PROTO));
+	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST ==
+	    MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST));
+	EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST ==
+	    MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST));
 #undef MATCH_MASK
 
 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp);
@@ -184,7 +188,6 @@ efx_mcdi_filter_op_add(
 	efx_mcdi_req_t req;
 	uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN,
 			    MC_CMD_FILTER_OP_OUT_LEN)];
-	uint32_t match_fields = 0;
 	efx_rc_t rc;
 
 	memset(payload, 0, sizeof (payload));
@@ -211,26 +214,10 @@ efx_mcdi_filter_op_add(
 		goto fail1;
 	}
 
-	if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) {
-		/*
-		 * The LOC_MAC_IG match flag can represent unknown unicast
-		 *  or multicast filters - use the MAC address to distinguish
-		 *  them.
-		 */
-		if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac))
-			match_fields |= 1U <<
-				MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN;
-		else
-			match_fields |= 1U <<
-				MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN;
-	}
-
-	match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG);
-
 	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID,
 	    EVB_PORT_ID_ASSIGNED);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS,
-	    match_fields);
+	    spec->efs_match_flags);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST,
 	    MC_CMD_FILTER_OP_IN_RX_DEST_HOST);
 	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE,
@@ -889,9 +876,6 @@ efx_mcdi_get_parser_disp_info(
 	uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
 			    MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)];
 	efx_rc_t rc;
-	uint32_t i;
-	boolean_t support_unknown_ucast = B_FALSE;
-	boolean_t support_unknown_mcast = B_FALSE;
 
 	(void) memset(payload, 0, sizeof (payload));
 	req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO;
@@ -927,28 +911,6 @@ efx_mcdi_get_parser_disp_info(
 	EFX_STATIC_ASSERT(sizeof (uint32_t) ==
 	    MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);
 
-	/*
-	 * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change
-	 * the lower priority one to LOC_MAC_IG.
-	 */
-	for (i = 0; i < *length; i++) {
-		if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) {
-			list[i] &=
-			(~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN);
-			support_unknown_ucast = B_TRUE;
-		}
-		if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) {
-			list[i] &=
-			(~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN);
-			support_unknown_mcast = B_TRUE;
-		}
-
-		if (support_unknown_ucast && support_unknown_mcast) {
-			list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG;
-			break;
-		}
-	}
-
 	return (0);
 
 fail2:
diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index 7c2fab7..43157e2 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -2228,10 +2228,10 @@ typedef enum efx_filter_match_flags_e {
 	EFX_FILTER_MATCH_OUTER_VID = 0x0100,	/* Match by outer VLAN ID */
 	EFX_FILTER_MATCH_IP_PROTO = 0x0200,	/* Match by IP transport
 						 * protocol */
-	EFX_FILTER_MATCH_LOC_MAC_IG = 0x0400,	/* Match by local MAC address
-						 * I/G bit. Used for RX default
-						 * unicast and multicast/
-						 * broadcast filters. */
+	/* Match otherwise-unmatched multicast and broadcast packets */
+	EFX_FILTER_MATCH_UNKNOWN_MCAST_DST = 0x40000000,
+	/* Match otherwise-unmatched unicast packets */
+	EFX_FILTER_MATCH_UNKNOWN_UCAST_DST = 0x80000000,
 } efx_filter_match_flags_t;
 
 typedef enum efx_filter_priority_s {
@@ -2253,7 +2253,7 @@ typedef enum efx_filter_priority_s {
  */
 
 typedef struct efx_filter_spec_s {
-	uint32_t	efs_match_flags:12;
+	uint32_t	efs_match_flags;
 	uint32_t	efs_priority:2;
 	uint32_t	efs_flags:6;
 	uint32_t	efs_dmaq_id:12;
diff --git a/drivers/net/sfc/base/efx_filter.c b/drivers/net/sfc/base/efx_filter.c
index a20efaf..4f58a7d 100644
--- a/drivers/net/sfc/base/efx_filter.c
+++ b/drivers/net/sfc/base/efx_filter.c
@@ -149,9 +149,6 @@ efx_filter_init(
 	const efx_filter_ops_t *efop;
 	efx_rc_t rc;
 
-	/* Check that efx_filter_spec_t is 64 bytes. */
-	EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64);
-
 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
@@ -387,7 +384,7 @@ efx_filter_spec_set_uc_def(
 {
 	EFSYS_ASSERT3P(spec, !=, NULL);
 
-	spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
+	spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
 	return (0);
 }
 
@@ -400,8 +397,7 @@ efx_filter_spec_set_mc_def(
 {
 	EFSYS_ASSERT3P(spec, !=, NULL);
 
-	spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
-	spec->efs_loc_mac[0] = 1;
+	spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
 	return (0);
 }
 
-- 
2.9.3

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

* [PATCH v2 02/11] net/sfc/base: improve API to get supported filter matches
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 01/11] net/sfc/base: split local MAC I/G back into separate flags Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 03/11] net/sfc: implement dummy filter control callback Andrew Rybchenko
                     ` (9 subsequent siblings)
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit, Mark Spender

From: Mark Spender <mspender@solarflare.com>

The previous API had various problems, including the length of the
caller provided buffer not being specified, no means being available
to discover how big the buffer needs to be, and a lack of clarity of
what the resulting list contains.

To improve it:
- add the buffer length as a parameter
- if the provided buffer is too short, fail with ENOSPC and return
  the required length
- ensure that the list contents are valid and add comments describing it

It is safe to change this API as, unsuprisingly, it has no users.

Signed-off-by: Mark Spender <mspender@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 drivers/net/sfc/base/ef10_filter.c | 90 +++++++++++++++++++++++++++++++-------
 drivers/net/sfc/base/ef10_impl.h   |  7 +--
 drivers/net/sfc/base/efx.h         |  7 +--
 drivers/net/sfc/base/efx_filter.c  | 68 +++++++++++++++++++---------
 drivers/net/sfc/base/efx_impl.h    |  3 +-
 5 files changed, 132 insertions(+), 43 deletions(-)

diff --git a/drivers/net/sfc/base/ef10_filter.c b/drivers/net/sfc/base/ef10_filter.c
index f520147..695bb84 100644
--- a/drivers/net/sfc/base/ef10_filter.c
+++ b/drivers/net/sfc/base/ef10_filter.c
@@ -868,13 +868,16 @@ ef10_filter_delete(
 
 static	__checkReturn	efx_rc_t
 efx_mcdi_get_parser_disp_info(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length)
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp)
 {
 	efx_mcdi_req_t req;
 	uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
 			    MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)];
+	size_t matches_count;
+	size_t list_size;
 	efx_rc_t rc;
 
 	(void) memset(payload, 0, sizeof (payload));
@@ -894,25 +897,41 @@ efx_mcdi_get_parser_disp_info(
 		goto fail1;
 	}
 
-	*length = MCDI_OUT_DWORD(req,
+	matches_count = MCDI_OUT_DWORD(req,
 	    GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES);
 
 	if (req.emr_out_length_used <
-	    MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) {
+	    MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(matches_count)) {
 		rc = EMSGSIZE;
 		goto fail2;
 	}
 
-	memcpy(list,
-	    MCDI_OUT2(req,
-	    uint32_t,
-	    GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
-	    (*length) * sizeof (uint32_t));
+	*list_lengthp = matches_count;
+
+	if (buffer_length < matches_count) {
+		rc = ENOSPC;
+		goto fail3;
+	}
+
+	/*
+	 * Check that the elements in the list in the MCDI response are the size
+	 * we expect, so we can just copy them directly. Any conversion of the
+	 * flags is handled by the caller.
+	 */
 	EFX_STATIC_ASSERT(sizeof (uint32_t) ==
 	    MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);
 
+	list_size = matches_count *
+		MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN;
+	memcpy(buffer,
+	    MCDI_OUT2(req, uint32_t,
+		    GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
+	    list_size);
+
 	return (0);
 
+fail3:
+	EFSYS_PROBE(fail3);
 fail2:
 	EFSYS_PROBE(fail2);
 fail1:
@@ -923,14 +942,55 @@ efx_mcdi_get_parser_disp_info(
 
 	__checkReturn	efx_rc_t
 ef10_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length)
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp)
 {
-	efx_rc_t rc;
 
-	if ((rc = efx_mcdi_get_parser_disp_info(enp, list, length)) != 0)
+	size_t mcdi_list_length;
+	size_t list_length;
+	uint32_t i;
+	efx_rc_t rc;
+	uint32_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_UNKNOWN_MCAST_DST |
+	    EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
+
+	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length,
+					    &mcdi_list_length);
+	if (rc != 0) {
+		if (rc == ENOSPC) {
+			/* Pass through mcdi_list_length for the list length */
+			*list_lengthp = mcdi_list_length;
+		}
 		goto fail1;
+	}
+
+	/*
+	 * The static assertions in ef10_filter_init() ensure that the values of
+	 * the EFX_FILTER_MATCH flags match those used by MCDI, so they don't
+	 * need to be converted.
+	 *
+	 * In case support is added to MCDI for additional flags, remove any
+	 * matches from the list which include flags we don't support. The order
+	 * of the matches is preserved as they are ordered from highest to
+	 * lowest priority.
+	 */
+	EFSYS_ASSERT(mcdi_list_length <= buffer_length);
+	list_length = 0;
+	for (i = 0; i < mcdi_list_length; i++) {
+		if ((buffer[i] & ~all_filter_flags) == 0) {
+			buffer[list_length] = buffer[i];
+			list_length++;
+		}
+	}
+
+	*list_lengthp = list_length;
 
 	return (0);
 
diff --git a/drivers/net/sfc/base/ef10_impl.h b/drivers/net/sfc/base/ef10_impl.h
index 192be5d..8c3dffe 100644
--- a/drivers/net/sfc/base/ef10_impl.h
+++ b/drivers/net/sfc/base/ef10_impl.h
@@ -1043,9 +1043,10 @@ ef10_filter_delete(
 
 extern	__checkReturn	efx_rc_t
 ef10_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length);
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp);
 
 extern	__checkReturn	efx_rc_t
 ef10_filter_reconfigure(
diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index 43157e2..6118296 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -2300,9 +2300,10 @@ efx_filter_restore(
 
 extern	__checkReturn	efx_rc_t
 efx_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length);
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp);
 
 extern			void
 efx_filter_spec_init_rx(
diff --git a/drivers/net/sfc/base/efx_filter.c b/drivers/net/sfc/base/efx_filter.c
index 4f58a7d..ba31026 100644
--- a/drivers/net/sfc/base/efx_filter.c
+++ b/drivers/net/sfc/base/efx_filter.c
@@ -61,9 +61,10 @@ siena_filter_delete(
 
 static	__checkReturn	efx_rc_t
 siena_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length);
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp);
 
 #endif /* EFSYS_OPT_SIENA */
 
@@ -209,11 +210,22 @@ efx_filter_fini(
 	enp->en_mod_flags &= ~EFX_MOD_FILTER;
 }
 
+/*
+ * Query the possible combinations of match flags which can be filtered on.
+ * These are returned as a list, of which each 32 bit element is a bitmask
+ * formed of EFX_FILTER_MATCH flags.
+ *
+ * The combinations are ordered in priority from highest to lowest.
+ *
+ * If the provided buffer is too short to hold the list, the call with fail with
+ * ENOSPC and *list_lengthp will be set to the buffer length required.
+ */
 	__checkReturn	efx_rc_t
 efx_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length)
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp)
 {
 	efx_rc_t rc;
 
@@ -222,11 +234,20 @@ efx_filter_supported_filters(
 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
 	EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
 
-	if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0)
+	if (buffer == NULL) {
+		rc = EINVAL;
 		goto fail1;
+	}
+
+	rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
+						    list_lengthp);
+	if (rc != 0)
+		goto fail2;
 
 	return (0);
 
+fail2:
+	EFSYS_PROBE(fail2);
 fail1:
 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
 
@@ -1346,23 +1367,20 @@ siena_filter_delete(
 	return (rc);
 }
 
-#define	MAX_SUPPORTED 4
+#define	SIENA_MAX_SUPPORTED_MATCHES 4
 
 static	__checkReturn	efx_rc_t
 siena_filter_supported_filters(
-	__in		efx_nic_t *enp,
-	__out		uint32_t *list,
-	__out		size_t *length)
+	__in				efx_nic_t *enp,
+	__out_ecount(buffer_length)	uint32_t *buffer,
+	__in				size_t buffer_length,
+	__out				size_t *list_lengthp)
 {
-	int index = 0;
-	uint32_t rx_matches[MAX_SUPPORTED];
+	uint32_t index = 0;
+	uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
+	size_t list_length;
 	efx_rc_t rc;
 
-	if (list == NULL) {
-		rc = EINVAL;
-		goto fail1;
-	}
-
 	rx_matches[index++] =
 	    EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
 	    EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
@@ -1379,14 +1397,22 @@ siena_filter_supported_filters(
 		rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
 	}
 
-	EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED);
+	EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
+	list_length = index;
+
+	*list_lengthp = list_length;
+
+	if (buffer_length < list_length) {
+		rc = ENOSPC;
+		goto fail1;
+	}
 
-	*length = index;
-	memcpy(list, rx_matches, *length);
+	memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
 
 	return (0);
 
 fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
 
 	return (rc);
 }
diff --git a/drivers/net/sfc/base/efx_impl.h b/drivers/net/sfc/base/efx_impl.h
index a38dad4..43add6d 100644
--- a/drivers/net/sfc/base/efx_impl.h
+++ b/drivers/net/sfc/base/efx_impl.h
@@ -235,7 +235,8 @@ typedef struct efx_filter_ops_s {
 	efx_rc_t	(*efo_add)(efx_nic_t *, efx_filter_spec_t *,
 				   boolean_t may_replace);
 	efx_rc_t	(*efo_delete)(efx_nic_t *, efx_filter_spec_t *);
-	efx_rc_t	(*efo_supported_filters)(efx_nic_t *, uint32_t *, size_t *);
+	efx_rc_t	(*efo_supported_filters)(efx_nic_t *, uint32_t *,
+				   size_t, size_t *);
 	efx_rc_t	(*efo_reconfigure)(efx_nic_t *, uint8_t const *, boolean_t,
 				   boolean_t, boolean_t, boolean_t,
 				   uint8_t const *, uint32_t);
-- 
2.9.3

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

* [PATCH v2 03/11] net/sfc: implement dummy filter control callback
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 01/11] net/sfc/base: split local MAC I/G back into separate flags Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 02/11] net/sfc/base: improve API to get supported filter matches Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 04/11] net/sfc: provide a way to check if filter is supported Andrew Rybchenko
                     ` (8 subsequent siblings)
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit

Just log error for all filter types and return no support indication.

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
Reviewed-by: Robert Stonehouse <rstonehouse@solarflare.com>
---
 drivers/net/sfc/sfc_ethdev.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index cac01ac..e696dd2 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -1208,6 +1208,54 @@ sfc_dev_rss_reta_update(struct rte_eth_dev *dev,
 }
 #endif
 
+static int
+sfc_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,
+		    __rte_unused enum rte_filter_op filter_op,
+		    __rte_unused void *arg)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	int rc = ENOTSUP;
+
+	sfc_log_init(sa, "entry");
+
+	switch (filter_type) {
+	case RTE_ETH_FILTER_NONE:
+		sfc_err(sa, "Global filters configuration not supported");
+		break;
+	case RTE_ETH_FILTER_MACVLAN:
+		sfc_err(sa, "MACVLAN filters not supported");
+		break;
+	case RTE_ETH_FILTER_ETHERTYPE:
+		sfc_err(sa, "EtherType filters not supported");
+		break;
+	case RTE_ETH_FILTER_FLEXIBLE:
+		sfc_err(sa, "Flexible filters not supported");
+		break;
+	case RTE_ETH_FILTER_SYN:
+		sfc_err(sa, "SYN filters not supported");
+		break;
+	case RTE_ETH_FILTER_NTUPLE:
+		sfc_err(sa, "NTUPLE filters not supported");
+		break;
+	case RTE_ETH_FILTER_TUNNEL:
+		sfc_err(sa, "Tunnel filters not supported");
+		break;
+	case RTE_ETH_FILTER_FDIR:
+		sfc_err(sa, "Flow Director filters not supported");
+		break;
+	case RTE_ETH_FILTER_HASH:
+		sfc_err(sa, "Hash filters not supported");
+		break;
+	default:
+		sfc_err(sa, "Unknown filter type %u", filter_type);
+		break;
+	}
+
+	sfc_log_init(sa, "exit: %d", -rc);
+	SFC_ASSERT(rc >= 0);
+	return -rc;
+}
+
 static const struct eth_dev_ops sfc_eth_dev_ops = {
 	.dev_configure			= sfc_dev_configure,
 	.dev_start			= sfc_dev_start,
@@ -1247,6 +1295,7 @@ static const struct eth_dev_ops sfc_eth_dev_ops = {
 	.rss_hash_update		= sfc_dev_rss_hash_update,
 	.rss_hash_conf_get		= sfc_dev_rss_hash_conf_get,
 #endif
+	.filter_ctrl			= sfc_dev_filter_ctrl,
 	.set_mc_addr_list		= sfc_set_mc_addr_list,
 	.rxq_info_get			= sfc_rx_queue_info_get,
 	.txq_info_get			= sfc_tx_queue_info_get,
-- 
2.9.3

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

* [PATCH v2 04/11] net/sfc: provide a way to check if filter is supported
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
                     ` (2 preceding siblings ...)
  2017-03-09 15:26   ` [PATCH v2 03/11] net/sfc: implement dummy filter control callback Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 05/11] net/sfc: add flow API filters support Andrew Rybchenko
                     ` (7 subsequent siblings)
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit

The information is obtained from firmware on attach. It may
change after MC reboot (firmware version or variant change).
Cache should be refreshed after MC reboot when it is handled
properly (not yet).

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
Reviewed-by: Robert Stonehouse <rstonehouse@solarflare.com>
---
 drivers/net/sfc/Makefile     |   1 +
 drivers/net/sfc/sfc.c        |   7 +++
 drivers/net/sfc/sfc.h        |   3 +
 drivers/net/sfc/sfc_filter.c | 135 +++++++++++++++++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_filter.h |  56 ++++++++++++++++++
 5 files changed, 202 insertions(+)
 create mode 100644 drivers/net/sfc/sfc_filter.c
 create mode 100644 drivers/net/sfc/sfc_filter.h

diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index 619a0ed..2b7ede8 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/sfc/Makefile
@@ -90,6 +90,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_port.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_rx.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_tx.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_tso.c
+SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_filter.c
 
 VPATH += $(SRCDIR)/base
 
diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c
index 03ecec2..6fd8bf1 100644
--- a/drivers/net/sfc/sfc.c
+++ b/drivers/net/sfc/sfc.c
@@ -633,6 +633,10 @@ sfc_attach(struct sfc_adapter *sa)
 	if (rc != 0)
 		goto fail_set_rss_defaults;
 
+	rc = sfc_filter_attach(sa);
+	if (rc != 0)
+		goto fail_filter_attach;
+
 	sfc_log_init(sa, "fini nic");
 	efx_nic_fini(enp);
 
@@ -641,6 +645,7 @@ sfc_attach(struct sfc_adapter *sa)
 	sfc_log_init(sa, "done");
 	return 0;
 
+fail_filter_attach:
 fail_set_rss_defaults:
 	sfc_intr_detach(sa);
 
@@ -678,6 +683,8 @@ sfc_detach(struct sfc_adapter *sa)
 
 	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
+	sfc_filter_detach(sa);
+
 	sfc_intr_detach(sa);
 
 	sfc_log_init(sa, "unprobe nic");
diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 655328f..b782360 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -38,6 +38,8 @@
 
 #include "efx.h"
 
+#include "sfc_filter.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -180,6 +182,7 @@ struct sfc_adapter {
 	struct sfc_mcdi			mcdi;
 	struct sfc_intr			intr;
 	struct sfc_port			port;
+	struct sfc_filter		filter;
 
 	unsigned int			rxq_max;
 	unsigned int			txq_max;
diff --git a/drivers/net/sfc/sfc_filter.c b/drivers/net/sfc/sfc_filter.c
new file mode 100644
index 0000000..98435e9
--- /dev/null
+++ b/drivers/net/sfc/sfc_filter.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2017 Solarflare Communications Inc.
+ * All rights reserved.
+ *
+ * This software was jointly developed between OKTET Labs (under contract
+ * for Solarflare) and Solarflare Communications, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_common.h>
+
+#include "efx.h"
+
+#include "sfc.h"
+#include "sfc_log.h"
+
+boolean_t
+sfc_filter_is_match_supported(struct sfc_adapter *sa, uint32_t match)
+{
+	struct sfc_filter *filter = &sa->filter;
+	size_t i;
+
+	for (i = 0; i < filter->supported_match_num; ++i) {
+		if (match == filter->supported_match[i])
+			return B_TRUE;
+	}
+
+	return B_FALSE;
+}
+
+static int
+sfc_filter_cache_match_supported(struct sfc_adapter *sa)
+{
+	struct sfc_filter *filter = &sa->filter;
+	size_t num = filter->supported_match_num;
+	uint32_t *buf = filter->supported_match;
+	unsigned int retry;
+	int rc;
+
+	/* Just a guess of possibly sufficient entries */
+	if (num == 0)
+		num = 16;
+
+	for (retry = 0; retry < 2; ++retry) {
+		if (num != filter->supported_match_num) {
+			rc = ENOMEM;
+			buf = rte_realloc(buf, num * sizeof(*buf), 0);
+			if (buf == NULL)
+				goto fail_realloc;
+		}
+
+		rc = efx_filter_supported_filters(sa->nic, buf, num, &num);
+		if (rc == 0) {
+			filter->supported_match_num = num;
+			filter->supported_match = buf;
+
+			return 0;
+		} else if (rc != ENOSPC) {
+			goto fail_efx_filter_supported_filters;
+		}
+	}
+
+	SFC_ASSERT(rc == ENOSPC);
+
+fail_efx_filter_supported_filters:
+fail_realloc:
+	/* Original pointer is not freed by rte_realloc() on failure */
+	rte_free(buf);
+	filter->supported_match = NULL;
+	filter->supported_match_num = 0;
+	return rc;
+}
+
+int
+sfc_filter_attach(struct sfc_adapter *sa)
+{
+	int rc;
+
+	sfc_log_init(sa, "entry");
+
+	rc = efx_filter_init(sa->nic);
+	if (rc != 0)
+		goto fail_filter_init;
+
+	rc = sfc_filter_cache_match_supported(sa);
+	if (rc != 0)
+		goto fail_cache_match_supported;
+
+	efx_filter_fini(sa->nic);
+
+	sfc_log_init(sa, "done");
+
+	return 0;
+
+fail_cache_match_supported:
+	efx_filter_fini(sa->nic);
+
+fail_filter_init:
+	sfc_log_init(sa, "failed %d", rc);
+	return rc;
+}
+
+void
+sfc_filter_detach(struct sfc_adapter *sa)
+{
+	struct sfc_filter *filter = &sa->filter;
+
+	sfc_log_init(sa, "entry");
+
+	rte_free(filter->supported_match);
+	filter->supported_match = NULL;
+	filter->supported_match_num = 0;
+
+	sfc_log_init(sa, "done");
+}
diff --git a/drivers/net/sfc/sfc_filter.h b/drivers/net/sfc/sfc_filter.h
new file mode 100644
index 0000000..5ba1617
--- /dev/null
+++ b/drivers/net/sfc/sfc_filter.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2017 Solarflare Communications Inc.
+ * All rights reserved.
+ *
+ * This software was jointly developed between OKTET Labs (under contract
+ * for Solarflare) and Solarflare Communications, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SFC_FILTER_H
+#define _SFC_FILTER_H
+
+#include "efx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct sfc_filter {
+	/** Number of elements in match_supported array */
+	size_t				supported_match_num;
+	/** Driver cache of supported filter match masks */
+	uint32_t			*supported_match;
+};
+
+struct sfc_adapter;
+
+int sfc_filter_attach(struct sfc_adapter *sa);
+void sfc_filter_detach(struct sfc_adapter *sa);
+
+boolean_t sfc_filter_is_match_supported(struct sfc_adapter *sa, uint32_t match);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SFC_FILTER_H */
-- 
2.9.3

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

* [PATCH v2 05/11] net/sfc: add flow API filters support
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
                     ` (3 preceding siblings ...)
  2017-03-09 15:26   ` [PATCH v2 04/11] net/sfc: provide a way to check if filter is supported Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 06/11] net/sfc: add VLAN in " Andrew Rybchenko
                     ` (6 subsequent siblings)
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit, Roman Zhukov

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

Only pattern items VOID, ETH and actions VOID, QUEUE is now
supported.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 doc/guides/nics/features/sfc_efx.ini   |   1 +
 doc/guides/nics/sfc_efx.rst            |  24 ++
 doc/guides/rel_notes/release_17_05.rst |   4 +
 drivers/net/sfc/Makefile               |   1 +
 drivers/net/sfc/sfc.c                  |  11 +
 drivers/net/sfc/sfc_ethdev.c           |  14 +-
 drivers/net/sfc/sfc_filter.h           |   4 +
 drivers/net/sfc/sfc_flow.c             | 704 +++++++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_flow.h             |  62 +++
 9 files changed, 822 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_flow.c
 create mode 100644 drivers/net/sfc/sfc_flow.h

diff --git a/doc/guides/nics/features/sfc_efx.ini b/doc/guides/nics/features/sfc_efx.ini
index 3a15baa..bb60ad6 100644
--- a/doc/guides/nics/features/sfc_efx.ini
+++ b/doc/guides/nics/features/sfc_efx.ini
@@ -19,6 +19,7 @@ RSS hash             = Y
 RSS key update       = Y
 RSS reta update      = Y
 Flow control         = Y
+Flow API             = Y
 VLAN offload         = P
 L3 checksum offload  = Y
 L4 checksum offload  = Y
diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 0a05a0a..f2e410f 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -81,6 +81,8 @@ SFC EFX PMD has support for:
 
 - Transmit VLAN insertion (if running firmware variant supports it)
 
+- Flow API
+
 
 Non-supported Features
 ----------------------
@@ -114,6 +116,28 @@ required in the receive buffer.
 It should be taken into account when mbuf pool for receive is created.
 
 
+Flow API support
+----------------
+
+Supported attributes:
+
+- Ingress
+
+Supported pattern items:
+
+- VOID
+
+- ETH (exact match of source/destination addresses, EtherType)
+
+Supported actions:
+
+- VOID
+
+- QUEUE
+
+Validating flow rules depends on the firmware variant.
+
+
 Supported NICs
 --------------
 
diff --git a/doc/guides/rel_notes/release_17_05.rst b/doc/guides/rel_notes/release_17_05.rst
index 123eeb4..3ab4a9b 100644
--- a/doc/guides/rel_notes/release_17_05.rst
+++ b/doc/guides/rel_notes/release_17_05.rst
@@ -64,6 +64,10 @@ New Features
   performance enhancements viz. configurable TX data ring, Receive
   Data Ring, ability to register memory regions.
 
+* **Updated the sfc_efx driver.**
+
+  * Generic flow API support for Ethernet, VLAN, IPv4, IPv6, UDP and TCP
+    pattern items with QUEUE action for ingress traffic.
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index 2b7ede8..e1ee04c 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/sfc/Makefile
@@ -91,6 +91,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_rx.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_tx.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_tso.c
 SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_filter.c
+SRCS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc_flow.c
 
 VPATH += $(SRCDIR)/base
 
diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c
index 6fd8bf1..3e419b6 100644
--- a/drivers/net/sfc/sfc.c
+++ b/drivers/net/sfc/sfc.c
@@ -320,10 +320,17 @@ sfc_start(struct sfc_adapter *sa)
 	if (rc != 0)
 		goto fail_tx_start;
 
+	rc = sfc_flow_start(sa);
+	if (rc != 0)
+		goto fail_flows_insert;
+
 	sa->state = SFC_ADAPTER_STARTED;
 	sfc_log_init(sa, "done");
 	return 0;
 
+fail_flows_insert:
+	sfc_tx_stop(sa);
+
 fail_tx_start:
 	sfc_rx_stop(sa);
 
@@ -368,6 +375,7 @@ sfc_stop(struct sfc_adapter *sa)
 
 	sa->state = SFC_ADAPTER_STOPPING;
 
+	sfc_flow_stop(sa);
 	sfc_tx_stop(sa);
 	sfc_rx_stop(sa);
 	sfc_port_stop(sa);
@@ -640,6 +648,8 @@ sfc_attach(struct sfc_adapter *sa)
 	sfc_log_init(sa, "fini nic");
 	efx_nic_fini(enp);
 
+	sfc_flow_init(sa);
+
 	sa->state = SFC_ADAPTER_INITIALIZED;
 
 	sfc_log_init(sa, "done");
@@ -698,5 +708,6 @@ sfc_detach(struct sfc_adapter *sa)
 
 	sfc_mem_bar_fini(sa);
 
+	sfc_flow_fini(sa);
 	sa->state = SFC_ADAPTER_UNINITIALIZED;
 }
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index e696dd2..5297159 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -40,7 +40,7 @@
 #include "sfc_ev.h"
 #include "sfc_rx.h"
 #include "sfc_tx.h"
-
+#include "sfc_flow.h"
 
 static void
 sfc_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
@@ -1210,8 +1210,8 @@ sfc_dev_rss_reta_update(struct rte_eth_dev *dev,
 
 static int
 sfc_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,
-		    __rte_unused enum rte_filter_op filter_op,
-		    __rte_unused void *arg)
+		    enum rte_filter_op filter_op,
+		    void *arg)
 {
 	struct sfc_adapter *sa = dev->data->dev_private;
 	int rc = ENOTSUP;
@@ -1246,6 +1246,14 @@ sfc_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,
 	case RTE_ETH_FILTER_HASH:
 		sfc_err(sa, "Hash filters not supported");
 		break;
+	case RTE_ETH_FILTER_GENERIC:
+		if (filter_op != RTE_ETH_FILTER_GET) {
+			rc = EINVAL;
+		} else {
+			*(const void **)arg = &sfc_flow_ops;
+			rc = 0;
+		}
+		break;
 	default:
 		sfc_err(sa, "Unknown filter type %u", filter_type);
 		break;
diff --git a/drivers/net/sfc/sfc_filter.h b/drivers/net/sfc/sfc_filter.h
index 5ba1617..fe23eee 100644
--- a/drivers/net/sfc/sfc_filter.h
+++ b/drivers/net/sfc/sfc_filter.h
@@ -32,6 +32,8 @@
 
 #include "efx.h"
 
+#include "sfc_flow.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -41,6 +43,8 @@ struct sfc_filter {
 	size_t				supported_match_num;
 	/** Driver cache of supported filter match masks */
 	uint32_t			*supported_match;
+	/** List of flow rules */
+	struct sfc_flow_list		flow_list;
 };
 
 struct sfc_adapter;
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
new file mode 100644
index 0000000..6b20bae
--- /dev/null
+++ b/drivers/net/sfc/sfc_flow.c
@@ -0,0 +1,704 @@
+/*-
+ * Copyright (c) 2017 Solarflare Communications Inc.
+ * All rights reserved.
+ *
+ * This software was jointly developed between OKTET Labs (under contract
+ * for Solarflare) and Solarflare Communications, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_tailq.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_eth_ctrl.h>
+#include <rte_ether.h>
+#include <rte_flow.h>
+#include <rte_flow_driver.h>
+
+#include "efx.h"
+
+#include "sfc.h"
+#include "sfc_rx.h"
+#include "sfc_filter.h"
+#include "sfc_flow.h"
+#include "sfc_log.h"
+
+/*
+ * At now flow API is implemented in such a manner that each
+ * flow rule is converted to a hardware filter.
+ * 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.
+ */
+
+enum sfc_flow_item_layers {
+	SFC_FLOW_ITEM_ANY_LAYER,
+	SFC_FLOW_ITEM_START_LAYER,
+	SFC_FLOW_ITEM_L2,
+};
+
+typedef int (sfc_flow_item_parse)(const struct rte_flow_item *item,
+				  efx_filter_spec_t *spec,
+				  struct rte_flow_error *error);
+
+struct sfc_flow_item {
+	enum rte_flow_item_type type;		/* Type of item */
+	enum sfc_flow_item_layers layer;	/* Layer of item */
+	enum sfc_flow_item_layers prev_layer;	/* Previous layer of item */
+	sfc_flow_item_parse *parse;		/* Parsing function */
+};
+
+static sfc_flow_item_parse sfc_flow_parse_void;
+static sfc_flow_item_parse sfc_flow_parse_eth;
+
+static boolean_t
+sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
+{
+	uint8_t sum = 0;
+	unsigned int i;
+
+	for (i = 0; i < size; i++)
+		sum |= buf[i];
+
+	return (sum == 0) ? B_TRUE : B_FALSE;
+}
+
+/*
+ * Validate item and prepare structures spec and mask for parsing
+ */
+static int
+sfc_flow_parse_init(const struct rte_flow_item *item,
+		    const void **spec_ptr,
+		    const void **mask_ptr,
+		    const void *supp_mask,
+		    const void *def_mask,
+		    unsigned int size,
+		    struct rte_flow_error *error)
+{
+	const uint8_t *spec;
+	const uint8_t *mask;
+	const uint8_t *last;
+	uint8_t match;
+	uint8_t supp;
+	unsigned int i;
+
+	if (item == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				   "NULL item");
+		return -rte_errno;
+	}
+
+	if ((item->last != NULL || item->mask != NULL) && item->spec == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "Mask or last is set without spec");
+		return -rte_errno;
+	}
+
+	/*
+	 * If "mask" is not set, default mask is used,
+	 * but if default mask is NULL, "mask" should be set
+	 */
+	if (item->mask == NULL) {
+		if (def_mask == NULL) {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				"Mask should be specified");
+			return -rte_errno;
+		}
+
+		mask = (const uint8_t *)def_mask;
+	} else {
+		mask = (const uint8_t *)item->mask;
+	}
+
+	spec = (const uint8_t *)item->spec;
+	last = (const uint8_t *)item->last;
+
+	if (spec == NULL)
+		goto exit;
+
+	/*
+	 * If field values in "last" are either 0 or equal to the corresponding
+	 * values in "spec" then they are ignored
+	 */
+	if (last != NULL &&
+	    !sfc_flow_is_zero(last, size) &&
+	    memcmp(last, spec, size) != 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "Ranging is not supported");
+		return -rte_errno;
+	}
+
+	if (supp_mask == NULL) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Supported mask for item should be specified");
+		return -rte_errno;
+	}
+
+	/* Check that mask and spec not asks for more match than supp_mask */
+	for (i = 0; i < size; i++) {
+		match = spec[i] | mask[i];
+		supp = ((const uint8_t *)supp_mask)[i];
+
+		if ((match | supp) != supp) {
+			rte_flow_error_set(error, ENOTSUP,
+					   RTE_FLOW_ERROR_TYPE_ITEM, item,
+					   "Item's field is not supported");
+			return -rte_errno;
+		}
+	}
+
+exit:
+	*spec_ptr = spec;
+	*mask_ptr = mask;
+	return 0;
+}
+
+/*
+ * Protocol parsers.
+ * Masking is not supported, so masks in items should be either
+ * full or empty (zeroed) and set only for supported fields which
+ * are specified in the supp_mask.
+ */
+
+static int
+sfc_flow_parse_void(__rte_unused const struct rte_flow_item *item,
+		    __rte_unused efx_filter_spec_t *efx_spec,
+		    __rte_unused struct rte_flow_error *error)
+{
+	return 0;
+}
+
+/**
+ * Convert Ethernet item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only source and destination addresses and
+ *   Ethernet type fields are 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_eth(const struct rte_flow_item *item,
+		   efx_filter_spec_t *efx_spec,
+		   struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_eth *spec = NULL;
+	const struct rte_flow_item_eth *mask = NULL;
+	const struct rte_flow_item_eth supp_mask = {
+		.dst.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+		.src.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+		.type = 0xffff,
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_eth_mask,
+				 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 (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_MAC_ADDR_LEN);
+	} else if (!is_zero_ether_addr(&mask->dst)) {
+		goto fail_bad_mask;
+	}
+
+	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,
+			   EFX_MAC_ADDR_LEN);
+	} else if (!is_zero_ether_addr(&mask->src)) {
+		goto fail_bad_mask;
+	}
+
+	/*
+	 * Ether type is in big-endian byte order in item and
+	 * in little-endian in efx_spec, so byte swap is used
+	 */
+	if (mask->type == supp_mask.type) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
+		efx_spec->efs_ether_type = rte_bswap16(spec->type);
+	} else if (mask->type != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the ETH pattern item");
+	return -rte_errno;
+}
+
+static const struct sfc_flow_item sfc_flow_items[] = {
+	{
+		.type = RTE_FLOW_ITEM_TYPE_VOID,
+		.prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
+		.layer = SFC_FLOW_ITEM_ANY_LAYER,
+		.parse = sfc_flow_parse_void,
+	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_ETH,
+		.prev_layer = SFC_FLOW_ITEM_START_LAYER,
+		.layer = SFC_FLOW_ITEM_L2,
+		.parse = sfc_flow_parse_eth,
+	},
+};
+
+/*
+ * Protocol-independent flow API support
+ */
+static int
+sfc_flow_parse_attr(const struct rte_flow_attr *attr,
+		    struct rte_flow *flow,
+		    struct rte_flow_error *error)
+{
+	if (attr == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ATTR, NULL,
+				   "NULL attribute");
+		return -rte_errno;
+	}
+	if (attr->group != 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr,
+				   "Groups are not supported");
+		return -rte_errno;
+	}
+	if (attr->priority != 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, attr,
+				   "Priorities are not supported");
+		return -rte_errno;
+	}
+	if (attr->egress != 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attr,
+				   "Egress is not supported");
+		return -rte_errno;
+	}
+	if (attr->ingress == 0) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, attr,
+				   "Only ingress is supported");
+		return -rte_errno;
+	}
+
+	flow->spec.efs_flags |= EFX_FILTER_FLAG_RX;
+	flow->spec.efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
+
+	return 0;
+}
+
+/* Get item from array sfc_flow_items */
+static const struct sfc_flow_item *
+sfc_flow_get_item(enum rte_flow_item_type type)
+{
+	unsigned int i;
+
+	for (i = 0; i < RTE_DIM(sfc_flow_items); i++)
+		if (sfc_flow_items[i].type == type)
+			return &sfc_flow_items[i];
+
+	return NULL;
+}
+
+static int
+sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
+		       struct rte_flow *flow,
+		       struct rte_flow_error *error)
+{
+	int rc;
+	unsigned int prev_layer = SFC_FLOW_ITEM_ANY_LAYER;
+	const struct sfc_flow_item *item;
+
+	if (pattern == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM_NUM, NULL,
+				   "NULL pattern");
+		return -rte_errno;
+	}
+
+	for (; pattern != NULL &&
+	       pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+		item = sfc_flow_get_item(pattern->type);
+		if (item == NULL) {
+			rte_flow_error_set(error, ENOTSUP,
+					   RTE_FLOW_ERROR_TYPE_ITEM, pattern,
+					   "Unsupported pattern item");
+			return -rte_errno;
+		}
+
+		/*
+		 * Omitting one or several protocol layers at the beginning
+		 * of pattern is supported
+		 */
+		if (item->prev_layer != SFC_FLOW_ITEM_ANY_LAYER &&
+		    prev_layer != SFC_FLOW_ITEM_ANY_LAYER &&
+		    item->prev_layer != prev_layer) {
+			rte_flow_error_set(error, ENOTSUP,
+					   RTE_FLOW_ERROR_TYPE_ITEM, pattern,
+					   "Unexpected sequence of pattern items");
+			return -rte_errno;
+		}
+
+		rc = item->parse(pattern, &flow->spec, error);
+		if (rc != 0)
+			return rc;
+
+		if (item->layer != SFC_FLOW_ITEM_ANY_LAYER)
+			prev_layer = item->layer;
+	}
+
+	if (pattern == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				   "NULL item");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
+static int
+sfc_flow_parse_queue(struct sfc_adapter *sa,
+		     const struct rte_flow_action_queue *queue,
+		     struct rte_flow *flow)
+{
+	struct sfc_rxq *rxq;
+
+	if (queue->index >= sa->rxq_count)
+		return -EINVAL;
+
+	rxq = sa->rxq_info[queue->index].rxq;
+	flow->spec.efs_dmaq_id = (uint16_t)rxq->hw_index;
+
+	return 0;
+}
+
+static int
+sfc_flow_parse_actions(struct sfc_adapter *sa,
+		       const struct rte_flow_action actions[],
+		       struct rte_flow *flow,
+		       struct rte_flow_error *error)
+{
+	int rc;
+	boolean_t is_specified = B_FALSE;
+
+	if (actions == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ACTION_NUM, NULL,
+				   "NULL actions");
+		return -rte_errno;
+	}
+
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		switch (actions->type) {
+		case RTE_FLOW_ACTION_TYPE_VOID:
+			break;
+
+		case RTE_FLOW_ACTION_TYPE_QUEUE:
+			rc = sfc_flow_parse_queue(sa, actions->conf, flow);
+			if (rc != 0) {
+				rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ACTION, actions,
+					"Bad QUEUE action");
+				return -rte_errno;
+			}
+
+			is_specified = B_TRUE;
+			break;
+
+		default:
+			rte_flow_error_set(error, ENOTSUP,
+					   RTE_FLOW_ERROR_TYPE_ACTION, actions,
+					   "Action is not supported");
+			return -rte_errno;
+		}
+	}
+
+	if (!is_specified) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ACTION_NUM, actions,
+				   "Action is unspecified");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
+static int
+sfc_flow_parse(struct rte_eth_dev *dev,
+	       const struct rte_flow_attr *attr,
+	       const struct rte_flow_item pattern[],
+	       const struct rte_flow_action actions[],
+	       struct rte_flow *flow,
+	       struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	int rc;
+
+	memset(&flow->spec, 0, sizeof(flow->spec));
+
+	rc = sfc_flow_parse_attr(attr, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
+
+	rc = sfc_flow_parse_pattern(pattern, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
+
+	rc = sfc_flow_parse_actions(sa, actions, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
+
+	if (!sfc_filter_is_match_supported(sa, flow->spec.efs_match_flags)) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Flow rule pattern is not supported");
+		return -rte_errno;
+	}
+
+fail_bad_value:
+	return rc;
+}
+
+static int
+sfc_flow_validate(struct rte_eth_dev *dev,
+		  const struct rte_flow_attr *attr,
+		  const struct rte_flow_item pattern[],
+		  const struct rte_flow_action actions[],
+		  struct rte_flow_error *error)
+{
+	struct rte_flow flow;
+
+	return sfc_flow_parse(dev, attr, pattern, actions, &flow, error);
+}
+
+static struct rte_flow *
+sfc_flow_create(struct rte_eth_dev *dev,
+		const struct rte_flow_attr *attr,
+		const struct rte_flow_item pattern[],
+		const struct rte_flow_action actions[],
+		struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	struct rte_flow *flow = NULL;
+	int rc;
+
+	flow = rte_zmalloc("sfc_rte_flow", sizeof(*flow), 0);
+	if (flow == NULL) {
+		rte_flow_error_set(error, ENOMEM,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Failed to allocate memory");
+		goto fail_no_mem;
+	}
+
+	rc = sfc_flow_parse(dev, attr, pattern, actions, flow, error);
+	if (rc != 0)
+		goto fail_bad_value;
+
+	TAILQ_INSERT_TAIL(&sa->filter.flow_list, flow, entries);
+
+	sfc_adapter_lock(sa);
+
+	if (sa->state == SFC_ADAPTER_STARTED) {
+		rc = efx_filter_insert(sa->nic, &flow->spec);
+		if (rc != 0) {
+			rte_flow_error_set(error, rc,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Failed to insert filter");
+			goto fail_filter_insert;
+		}
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return flow;
+
+fail_filter_insert:
+	TAILQ_REMOVE(&sa->filter.flow_list, flow, entries);
+
+fail_bad_value:
+	rte_free(flow);
+	sfc_adapter_unlock(sa);
+
+fail_no_mem:
+	return NULL;
+}
+
+static int
+sfc_flow_remove(struct sfc_adapter *sa,
+		struct rte_flow *flow,
+		struct rte_flow_error *error)
+{
+	int rc = 0;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	if (sa->state == SFC_ADAPTER_STARTED) {
+		rc = efx_filter_remove(sa->nic, &flow->spec);
+		if (rc != 0)
+			rte_flow_error_set(error, rc,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Failed to destroy flow rule");
+	}
+
+	TAILQ_REMOVE(&sa->filter.flow_list, flow, entries);
+	rte_free(flow);
+
+	return rc;
+}
+
+static int
+sfc_flow_destroy(struct rte_eth_dev *dev,
+		 struct rte_flow *flow,
+		 struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	struct rte_flow *flow_ptr;
+	int rc = EINVAL;
+
+	sfc_adapter_lock(sa);
+
+	TAILQ_FOREACH(flow_ptr, &sa->filter.flow_list, entries) {
+		if (flow_ptr == flow)
+			rc = 0;
+	}
+	if (rc != 0) {
+		rte_flow_error_set(error, rc,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to find flow rule to destroy");
+		goto fail_bad_value;
+	}
+
+	rc = sfc_flow_remove(sa, flow, error);
+
+fail_bad_value:
+	sfc_adapter_unlock(sa);
+
+	return -rc;
+}
+
+static int
+sfc_flow_flush(struct rte_eth_dev *dev,
+	       struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = dev->data->dev_private;
+	struct rte_flow *flow;
+	int rc = 0;
+	int ret = 0;
+
+	sfc_adapter_lock(sa);
+
+	while ((flow = TAILQ_FIRST(&sa->filter.flow_list)) != NULL) {
+		rc = sfc_flow_remove(sa, flow, error);
+		if (rc != 0)
+			ret = rc;
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return -ret;
+}
+
+const struct rte_flow_ops sfc_flow_ops = {
+	.validate = sfc_flow_validate,
+	.create = sfc_flow_create,
+	.destroy = sfc_flow_destroy,
+	.flush = sfc_flow_flush,
+	.query = NULL,
+};
+
+void
+sfc_flow_init(struct sfc_adapter *sa)
+{
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	TAILQ_INIT(&sa->filter.flow_list);
+}
+
+void
+sfc_flow_fini(struct sfc_adapter *sa)
+{
+	struct rte_flow *flow;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	while ((flow = TAILQ_FIRST(&sa->filter.flow_list)) != NULL) {
+		TAILQ_REMOVE(&sa->filter.flow_list, flow, entries);
+		rte_free(flow);
+	}
+}
+
+void
+sfc_flow_stop(struct sfc_adapter *sa)
+{
+	struct rte_flow *flow;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	TAILQ_FOREACH(flow, &sa->filter.flow_list, entries)
+		efx_filter_remove(sa->nic, &flow->spec);
+}
+
+int
+sfc_flow_start(struct sfc_adapter *sa)
+{
+	struct rte_flow *flow;
+	int rc = 0;
+
+	sfc_log_init(sa, "entry");
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	TAILQ_FOREACH(flow, &sa->filter.flow_list, entries) {
+		rc = efx_filter_insert(sa->nic, &flow->spec);
+		if (rc != 0)
+			goto fail_bad_flow;
+	}
+
+	sfc_log_init(sa, "done");
+
+fail_bad_flow:
+	return rc;
+}
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
new file mode 100644
index 0000000..d38ac35
--- /dev/null
+++ b/drivers/net/sfc/sfc_flow.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2017 Solarflare Communications Inc.
+ * All rights reserved.
+ *
+ * This software was jointly developed between OKTET Labs (under contract
+ * for Solarflare) and Solarflare Communications, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SFC_FLOW_H
+#define _SFC_FLOW_H
+
+#include <rte_tailq.h>
+#include <rte_flow_driver.h>
+
+#include "efx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* PMD-specific definition of the opaque type from rte_flow.h */
+struct rte_flow {
+	efx_filter_spec_t spec;		/* filter specification */
+	TAILQ_ENTRY(rte_flow) entries;	/* flow list entries */
+};
+
+TAILQ_HEAD(sfc_flow_list, rte_flow);
+
+extern const struct rte_flow_ops sfc_flow_ops;
+
+struct sfc_adapter;
+
+void sfc_flow_init(struct sfc_adapter *sa);
+void sfc_flow_fini(struct sfc_adapter *sa);
+int sfc_flow_start(struct sfc_adapter *sa);
+void sfc_flow_stop(struct sfc_adapter *sa);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SFC_FLOW_H */
-- 
2.9.3

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

* [PATCH v2 06/11] net/sfc: add VLAN in flow API filters support
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
                     ` (4 preceding siblings ...)
  2017-03-09 15:26   ` [PATCH v2 05/11] net/sfc: add flow API filters support Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 07/11] net/sfc: add IPV4 " Andrew Rybchenko
                     ` (5 subsequent siblings)
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit, Roman Zhukov

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

Exact match of VLAN ID bits is supported only and required in VLAN item.
Mask to match VLAN ID bits only is required, default mask to match entire
TCI is not supported.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  2 ++
 drivers/net/sfc/sfc_flow.c  | 74 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index f2e410f..71dc99f 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -129,6 +129,8 @@ Supported pattern items:
 
 - ETH (exact match of source/destination addresses, EtherType)
 
+- VLAN (exact match of VID, double-tagging is supported)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 6b20bae..70d926f 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -70,6 +70,7 @@ struct sfc_flow_item {
 
 static sfc_flow_item_parse sfc_flow_parse_void;
 static sfc_flow_item_parse sfc_flow_parse_eth;
+static sfc_flow_item_parse sfc_flow_parse_vlan;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -269,6 +270,73 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+/**
+ * Convert VLAN item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only VID field is supported.
+ *   The mask can not be NULL. 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_vlan(const struct rte_flow_item *item,
+		    efx_filter_spec_t *efx_spec,
+		    struct rte_flow_error *error)
+{
+	int rc;
+	uint16_t vid;
+	const struct rte_flow_item_vlan *spec = NULL;
+	const struct rte_flow_item_vlan *mask = NULL;
+	const struct rte_flow_item_vlan supp_mask = {
+		.tci = rte_cpu_to_be_16(ETH_VLAN_ID_MAX),
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 NULL,
+				 sizeof(struct rte_flow_item_vlan),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * VID is in big-endian byte order in item and
+	 * in little-endian in efx_spec, so byte swap is used.
+	 * If two VLAN items are included, the first matches
+	 * the outer tag and the next matches the inner tag.
+	 */
+	if (mask->tci == supp_mask.tci) {
+		vid = rte_bswap16(spec->tci);
+
+		if (!(efx_spec->efs_match_flags &
+		      EFX_FILTER_MATCH_OUTER_VID)) {
+			efx_spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
+			efx_spec->efs_outer_vid = vid;
+		} else if (!(efx_spec->efs_match_flags &
+			     EFX_FILTER_MATCH_INNER_VID)) {
+			efx_spec->efs_match_flags |= EFX_FILTER_MATCH_INNER_VID;
+			efx_spec->efs_inner_vid = vid;
+		} else {
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ITEM, item,
+					   "More than two VLAN items");
+			return -rte_errno;
+		}
+	} else {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "VLAN ID in TCI match is required");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -282,6 +350,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L2,
 		.parse = sfc_flow_parse_eth,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_VLAN,
+		.prev_layer = SFC_FLOW_ITEM_L2,
+		.layer = SFC_FLOW_ITEM_L2,
+		.parse = sfc_flow_parse_vlan,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH v2 07/11] net/sfc: add IPV4 in flow API filters support
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
                     ` (5 preceding siblings ...)
  2017-03-09 15:26   ` [PATCH v2 06/11] net/sfc: add VLAN in " Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 08/11] net/sfc: add IPV6 " Andrew Rybchenko
                     ` (4 subsequent siblings)
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit, Roman Zhukov

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

Exact match of IP protocol, source and destination
addresses is supported by parser.
EtherType match is enforced to IPv4 EtherType.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  3 ++
 drivers/net/sfc/sfc_flow.c  | 98 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 71dc99f..12ac308 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -131,6 +131,9 @@ Supported pattern items:
 
 - VLAN (exact match of VID, double-tagging is supported)
 
+- IPV4 (exact match of source/destination addresses,
+  IP transport protocol)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 70d926f..05be5a5 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -55,6 +55,7 @@ enum sfc_flow_item_layers {
 	SFC_FLOW_ITEM_ANY_LAYER,
 	SFC_FLOW_ITEM_START_LAYER,
 	SFC_FLOW_ITEM_L2,
+	SFC_FLOW_ITEM_L3,
 };
 
 typedef int (sfc_flow_item_parse)(const struct rte_flow_item *item,
@@ -71,6 +72,7 @@ struct sfc_flow_item {
 static sfc_flow_item_parse sfc_flow_parse_void;
 static sfc_flow_item_parse sfc_flow_parse_eth;
 static sfc_flow_item_parse sfc_flow_parse_vlan;
+static sfc_flow_item_parse sfc_flow_parse_ipv4;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -337,6 +339,96 @@ sfc_flow_parse_vlan(const struct rte_flow_item *item,
 	return 0;
 }
 
+/**
+ * Convert IPv4 item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only source and destination addresses and
+ *   protocol fields are 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_ipv4(const struct rte_flow_item *item,
+		    efx_filter_spec_t *efx_spec,
+		    struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_ipv4 *spec = NULL;
+	const struct rte_flow_item_ipv4 *mask = NULL;
+	const uint16_t ether_type_ipv4 = rte_cpu_to_le_16(EFX_ETHER_TYPE_IPV4);
+	const struct rte_flow_item_ipv4 supp_mask = {
+		.hdr = {
+			.src_addr = 0xffffffff,
+			.dst_addr = 0xffffffff,
+			.next_proto_id = 0xff,
+		}
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_ipv4_mask,
+				 sizeof(struct rte_flow_item_ipv4),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * Filtering by IPv4 source and destination addresses requires
+	 * the appropriate ETHER_TYPE in hardware filters
+	 */
+	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
+		efx_spec->efs_ether_type = ether_type_ipv4;
+	} else if (efx_spec->efs_ether_type != ether_type_ipv4) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Ethertype in pattern with IPV4 item should be appropriate");
+		return -rte_errno;
+	}
+
+	if (spec == NULL)
+		return 0;
+
+	/*
+	 * IPv4 addresses are in big-endian byte order in item and in
+	 * efx_spec
+	 */
+	if (mask->hdr.src_addr == supp_mask.hdr.src_addr) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_HOST;
+		efx_spec->efs_rem_host.eo_u32[0] = spec->hdr.src_addr;
+	} else if (mask->hdr.src_addr != 0) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.dst_addr == supp_mask.hdr.dst_addr) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_HOST;
+		efx_spec->efs_loc_host.eo_u32[0] = spec->hdr.dst_addr;
+	} else if (mask->hdr.dst_addr != 0) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.next_proto_id == supp_mask.hdr.next_proto_id) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
+		efx_spec->efs_ip_proto = spec->hdr.next_proto_id;
+	} else if (mask->hdr.next_proto_id != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the IPV4 pattern item");
+	return -rte_errno;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -356,6 +448,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L2,
 		.parse = sfc_flow_parse_vlan,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_IPV4,
+		.prev_layer = SFC_FLOW_ITEM_L2,
+		.layer = SFC_FLOW_ITEM_L3,
+		.parse = sfc_flow_parse_ipv4,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH v2 08/11] net/sfc: add IPV6 in flow API filters support
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
                     ` (6 preceding siblings ...)
  2017-03-09 15:26   ` [PATCH v2 07/11] net/sfc: add IPV4 " Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 09/11] net/sfc: add TCP " Andrew Rybchenko
                     ` (3 subsequent siblings)
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit, Roman Zhukov

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

Exact match of IP protocol, source and destination
addresses is supported by parser.
EtherType match is enforced to IPv6 EtherType.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |   3 ++
 drivers/net/sfc/sfc_flow.c  | 115 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 12ac308..a4ea162 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -134,6 +134,9 @@ Supported pattern items:
 - IPV4 (exact match of source/destination addresses,
   IP transport protocol)
 
+- IPV6 (exact match of source/destination addresses,
+  IP transport protocol)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 05be5a5..1079ca4 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -73,6 +73,7 @@ static sfc_flow_item_parse sfc_flow_parse_void;
 static sfc_flow_item_parse sfc_flow_parse_eth;
 static sfc_flow_item_parse sfc_flow_parse_vlan;
 static sfc_flow_item_parse sfc_flow_parse_ipv4;
+static sfc_flow_item_parse sfc_flow_parse_ipv6;
 
 static boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -429,6 +430,114 @@ sfc_flow_parse_ipv4(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+/**
+ * Convert IPv6 item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only source and destination addresses and
+ *   next header fields are 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_ipv6(const struct rte_flow_item *item,
+		    efx_filter_spec_t *efx_spec,
+		    struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_ipv6 *spec = NULL;
+	const struct rte_flow_item_ipv6 *mask = NULL;
+	const uint16_t ether_type_ipv6 = rte_cpu_to_le_16(EFX_ETHER_TYPE_IPV6);
+	const struct rte_flow_item_ipv6 supp_mask = {
+		.hdr = {
+			.src_addr = { 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff },
+			.dst_addr = { 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff },
+			.proto = 0xff,
+		}
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_ipv6_mask,
+				 sizeof(struct rte_flow_item_ipv6),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * Filtering by IPv6 source and destination addresses requires
+	 * the appropriate ETHER_TYPE in hardware filters
+	 */
+	if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
+		efx_spec->efs_ether_type = ether_type_ipv6;
+	} else if (efx_spec->efs_ether_type != ether_type_ipv6) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"Ethertype in pattern with IPV6 item should be appropriate");
+		return -rte_errno;
+	}
+
+	if (spec == NULL)
+		return 0;
+
+	/*
+	 * IPv6 addresses are in big-endian byte order in item and in
+	 * efx_spec
+	 */
+	if (memcmp(mask->hdr.src_addr, supp_mask.hdr.src_addr,
+		   sizeof(mask->hdr.src_addr)) == 0) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_HOST;
+
+		RTE_BUILD_BUG_ON(sizeof(efx_spec->efs_rem_host) !=
+				 sizeof(spec->hdr.src_addr));
+		rte_memcpy(&efx_spec->efs_rem_host, spec->hdr.src_addr,
+			   sizeof(efx_spec->efs_rem_host));
+	} else if (!sfc_flow_is_zero(mask->hdr.src_addr,
+				     sizeof(mask->hdr.src_addr))) {
+		goto fail_bad_mask;
+	}
+
+	if (memcmp(mask->hdr.dst_addr, supp_mask.hdr.dst_addr,
+		   sizeof(mask->hdr.dst_addr)) == 0) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_HOST;
+
+		RTE_BUILD_BUG_ON(sizeof(efx_spec->efs_loc_host) !=
+				 sizeof(spec->hdr.dst_addr));
+		rte_memcpy(&efx_spec->efs_loc_host, spec->hdr.dst_addr,
+			   sizeof(efx_spec->efs_loc_host));
+	} else if (!sfc_flow_is_zero(mask->hdr.dst_addr,
+				     sizeof(mask->hdr.dst_addr))) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.proto == supp_mask.hdr.proto) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
+		efx_spec->efs_ip_proto = spec->hdr.proto;
+	} else if (mask->hdr.proto != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the IPV6 pattern item");
+	return -rte_errno;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -454,6 +563,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L3,
 		.parse = sfc_flow_parse_ipv4,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_IPV6,
+		.prev_layer = SFC_FLOW_ITEM_L2,
+		.layer = SFC_FLOW_ITEM_L3,
+		.parse = sfc_flow_parse_ipv6,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH v2 09/11] net/sfc: add TCP in flow API filters support
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
                     ` (7 preceding siblings ...)
  2017-03-09 15:26   ` [PATCH v2 08/11] net/sfc: add IPV6 " Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 10/11] net/sfc: add UDP " Andrew Rybchenko
                     ` (2 subsequent siblings)
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit, Roman Zhukov

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

Exact match of source and destination ports is supported by parser.
IP protocol match is enforced to TCP.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  2 +
 drivers/net/sfc/sfc_flow.c  | 89 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index a4ea162..7e00fdc 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -137,6 +137,8 @@ Supported pattern items:
 - IPV6 (exact match of source/destination addresses,
   IP transport protocol)
 
+- TCP (exact match of source/destination ports)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 1079ca4..38e6b73 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -56,6 +56,7 @@ enum sfc_flow_item_layers {
 	SFC_FLOW_ITEM_START_LAYER,
 	SFC_FLOW_ITEM_L2,
 	SFC_FLOW_ITEM_L3,
+	SFC_FLOW_ITEM_L4,
 };
 
 typedef int (sfc_flow_item_parse)(const struct rte_flow_item *item,
@@ -74,6 +75,7 @@ static sfc_flow_item_parse sfc_flow_parse_eth;
 static sfc_flow_item_parse sfc_flow_parse_vlan;
 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 boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -538,6 +540,87 @@ sfc_flow_parse_ipv6(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+/**
+ * Convert TCP item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only source and destination ports fields
+ *   are 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_tcp(const struct rte_flow_item *item,
+		   efx_filter_spec_t *efx_spec,
+		   struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_tcp *spec = NULL;
+	const struct rte_flow_item_tcp *mask = NULL;
+	const struct rte_flow_item_tcp supp_mask = {
+		.hdr = {
+			.src_port = 0xffff,
+			.dst_port = 0xffff,
+		}
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_tcp_mask,
+				 sizeof(struct rte_flow_item_tcp),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * Filtering by TCP source and destination ports requires
+	 * the appropriate IP_PROTO in hardware filters
+	 */
+	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 = EFX_IPPROTO_TCP;
+	} else if (efx_spec->efs_ip_proto != EFX_IPPROTO_TCP) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"IP proto in pattern with TCP item should be appropriate");
+		return -rte_errno;
+	}
+
+	if (spec == NULL)
+		return 0;
+
+	/*
+	 * Source and destination ports are in big-endian byte order in item and
+	 * in little-endian in efx_spec, so byte swap is used
+	 */
+	if (mask->hdr.src_port == supp_mask.hdr.src_port) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_PORT;
+		efx_spec->efs_rem_port = rte_bswap16(spec->hdr.src_port);
+	} else if (mask->hdr.src_port != 0) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.dst_port == supp_mask.hdr.dst_port) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_PORT;
+		efx_spec->efs_loc_port = rte_bswap16(spec->hdr.dst_port);
+	} else if (mask->hdr.dst_port != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the TCP pattern item");
+	return -rte_errno;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -569,6 +652,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L3,
 		.parse = sfc_flow_parse_ipv6,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_TCP,
+		.prev_layer = SFC_FLOW_ITEM_L3,
+		.layer = SFC_FLOW_ITEM_L4,
+		.parse = sfc_flow_parse_tcp,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH v2 10/11] net/sfc: add UDP in flow API filters support
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
                     ` (8 preceding siblings ...)
  2017-03-09 15:26   ` [PATCH v2 09/11] net/sfc: add TCP " Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 15:26   ` [PATCH v2 11/11] net/sfc: add unknown unicast/multicast match in flow API Andrew Rybchenko
  2017-03-09 17:28   ` [PATCH v2 00/11] Support flow API in Solarflare PMD Ferruh Yigit
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit, Roman Zhukov

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

Exact match of source and destination ports is supported by parser.
IP protocol match is enforced to UDP.

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst |  2 ++
 drivers/net/sfc/sfc_flow.c  | 88 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 7e00fdc..4d91b1d 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -139,6 +139,8 @@ Supported pattern items:
 
 - TCP (exact match of source/destination ports)
 
+- UDP (exact match of source/destination ports)
+
 Supported actions:
 
 - VOID
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 38e6b73..ae36934 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -76,6 +76,7 @@ static sfc_flow_item_parse sfc_flow_parse_vlan;
 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 boolean_t
 sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
@@ -621,6 +622,87 @@ sfc_flow_parse_tcp(const struct rte_flow_item *item,
 	return -rte_errno;
 }
 
+/**
+ * Convert UDP item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification. Only source and destination ports fields
+ *   are 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_udp(const struct rte_flow_item *item,
+		   efx_filter_spec_t *efx_spec,
+		   struct rte_flow_error *error)
+{
+	int rc;
+	const struct rte_flow_item_udp *spec = NULL;
+	const struct rte_flow_item_udp *mask = NULL;
+	const struct rte_flow_item_udp supp_mask = {
+		.hdr = {
+			.src_port = 0xffff,
+			.dst_port = 0xffff,
+		}
+	};
+
+	rc = sfc_flow_parse_init(item,
+				 (const void **)&spec,
+				 (const void **)&mask,
+				 &supp_mask,
+				 &rte_flow_item_udp_mask,
+				 sizeof(struct rte_flow_item_udp),
+				 error);
+	if (rc != 0)
+		return rc;
+
+	/*
+	 * Filtering by UDP source and destination ports requires
+	 * the appropriate IP_PROTO in hardware filters
+	 */
+	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 = EFX_IPPROTO_UDP;
+	} else if (efx_spec->efs_ip_proto != EFX_IPPROTO_UDP) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, item,
+			"IP proto in pattern with UDP item should be appropriate");
+		return -rte_errno;
+	}
+
+	if (spec == NULL)
+		return 0;
+
+	/*
+	 * Source and destination ports are in big-endian byte order in item and
+	 * in little-endian in efx_spec, so byte swap is used
+	 */
+	if (mask->hdr.src_port == supp_mask.hdr.src_port) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_PORT;
+		efx_spec->efs_rem_port = rte_bswap16(spec->hdr.src_port);
+	} else if (mask->hdr.src_port != 0) {
+		goto fail_bad_mask;
+	}
+
+	if (mask->hdr.dst_port == supp_mask.hdr.dst_port) {
+		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_PORT;
+		efx_spec->efs_loc_port = rte_bswap16(spec->hdr.dst_port);
+	} else if (mask->hdr.dst_port != 0) {
+		goto fail_bad_mask;
+	}
+
+	return 0;
+
+fail_bad_mask:
+	rte_flow_error_set(error, EINVAL,
+			   RTE_FLOW_ERROR_TYPE_ITEM, item,
+			   "Bad mask in the UDP pattern item");
+	return -rte_errno;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -658,6 +740,12 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.layer = SFC_FLOW_ITEM_L4,
 		.parse = sfc_flow_parse_tcp,
 	},
+	{
+		.type = RTE_FLOW_ITEM_TYPE_UDP,
+		.prev_layer = SFC_FLOW_ITEM_L3,
+		.layer = SFC_FLOW_ITEM_L4,
+		.parse = sfc_flow_parse_udp,
+	},
 };
 
 /*
-- 
2.9.3

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

* [PATCH v2 11/11] net/sfc: add unknown unicast/multicast match in flow API
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
                     ` (9 preceding siblings ...)
  2017-03-09 15:26   ` [PATCH v2 10/11] net/sfc: add UDP " Andrew Rybchenko
@ 2017-03-09 15:26   ` Andrew Rybchenko
  2017-03-09 17:28   ` [PATCH v2 00/11] Support flow API in Solarflare PMD Ferruh Yigit
  11 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:26 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit, Roman Zhukov

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

Support individual/group destination address match (unknown unicast
and all-multicast correspondingly in terms of firmware).

Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
---
 doc/guides/nics/sfc_efx.rst | 11 ++++++++++-
 drivers/net/sfc/sfc_flow.c  | 17 +++++++++++++++--
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 4d91b1d..8229d7d 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -127,7 +127,8 @@ Supported pattern items:
 
 - VOID
 
-- ETH (exact match of source/destination addresses, EtherType)
+- ETH (exact match of source/destination addresses, individual/group match
+  of destination address, EtherType)
 
 - VLAN (exact match of VID, double-tagging is supported)
 
@@ -149,6 +150,14 @@ Supported actions:
 
 Validating flow rules depends on the firmware variant.
 
+Ethernet destinaton individual/group match
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Ethernet item supports I/G matching, if only the corresponding bit is set
+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.
+
 
 Supported NICs
 --------------
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index ae36934..fe352c0 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -205,8 +205,10 @@ sfc_flow_parse_void(__rte_unused const struct rte_flow_item *item,
  *
  * @param item[in]
  *   Item specification. Only source and destination addresses and
- *   Ethernet type fields are supported. If the mask is NULL, default
- *   mask will be used. Ranging is not supported.
+ *   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.
  * @param efx_spec[in, out]
  *   EFX filter specification to update.
  * @param[out] error
@@ -225,6 +227,9 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 		.src.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
 		.type = 0xffff,
 	};
+	const uint8_t ig_mask[EFX_MAC_ADDR_LEN] = {
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
 
 	rc = sfc_flow_parse_init(item,
 				 (const void **)&spec,
@@ -244,6 +249,14 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
 		efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
 		rte_memcpy(efx_spec->efs_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_FILTER_MATCH_UNKNOWN_UCAST_DST;
+		else
+			efx_spec->efs_match_flags |=
+				EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
 	} else if (!is_zero_ether_addr(&mask->dst)) {
 		goto fail_bad_mask;
 	}
-- 
2.9.3

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

* Re: [PATCH 05/11] net/sfc: add flow API filters support
  2017-03-07 13:21   ` Ferruh Yigit
@ 2017-03-09 15:29     ` Andrew Rybchenko
  0 siblings, 0 replies; 33+ messages in thread
From: Andrew Rybchenko @ 2017-03-09 15:29 UTC (permalink / raw)
  To: Ferruh Yigit, dev; +Cc: Roman Zhukov

On 03/07/2017 04:21 PM, Ferruh Yigit wrote:
> On 3/2/2017 4:03 PM, Andrew Rybchenko wrote:
>> From: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
>>
>> Only pattern items VOID, ETH and actions VOID, QUEUE is now
>> supported.
>>
>> Signed-off-by: Roman Zhukov <Roman.Zhukov@oktetlabs.ru>
>> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
> <...>
>
>> diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
>> new file mode 100644
>> index 0000000..0590756
>> --- /dev/null
>> +++ b/drivers/net/sfc/sfc_flow.c
>> @@ -0,0 +1,693 @@
>> +/*-
>> + * Copyright (c) 2017 Solarflare Communications Inc.
>> + * All rights reserved.
> Missing "BSD LICENSE" line. This is same for all new files.
> I think this discussed before, I don't know if that line is mandatory,
> but can be good to have at least to be consistent to rest of the codes.

Since it is common for all our files, let me address is separately.

Thanks,
Andrew.

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

* Re: [PATCH v2 00/11] Support flow API in Solarflare PMD
  2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
                     ` (10 preceding siblings ...)
  2017-03-09 15:26   ` [PATCH v2 11/11] net/sfc: add unknown unicast/multicast match in flow API Andrew Rybchenko
@ 2017-03-09 17:28   ` Ferruh Yigit
  11 siblings, 0 replies; 33+ messages in thread
From: Ferruh Yigit @ 2017-03-09 17:28 UTC (permalink / raw)
  To: Andrew Rybchenko, dev

On 3/9/2017 3:26 PM, Andrew Rybchenko wrote:
> Support simple queue destination flow API filters in Solarflare
> libefx-based PMD including:
>  - Ethernet source/destination, EtherType exact matching
>  - VLAN ID exact matching including double-tagging
>  - IPv4/6 source/destination and IP protocol exact matching
>  - TCP/UDP source/destination exact matching
> 
> Supported combinations of fields mentioned above depend on
> firmware (including running variant) and correctly processed by
> validate callback.
> 
> v1 -> v2:
>  - fix spelling
>  - add comments to protocol parsers
>  - add release notes
>  - add l3 and l4 layer enum items on demand
> 
> Andrew Rybchenko (2):
>   net/sfc: implement dummy filter control callback
>   net/sfc: provide a way to check if filter is supported
> 
> Mark Spender (2):
>   net/sfc/base: split local MAC I/G back into separate flags
>   net/sfc/base: improve API to get supported filter matches
> 
> Roman Zhukov (7):
>   net/sfc: add flow API filters support
>   net/sfc: add VLAN in flow API filters support
>   net/sfc: add IPV4 in flow API filters support
>   net/sfc: add IPV6 in flow API filters support
>   net/sfc: add TCP in flow API filters support
>   net/sfc: add UDP in flow API filters support
>   net/sfc: add unknown unicast/multicast match in flow API

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

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

end of thread, other threads:[~2017-03-09 17:28 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-02 16:03 [PATCH 00/11] Support flow API in Solarflare PMD Andrew Rybchenko
2017-03-02 16:03 ` [PATCH 01/11] net/sfc/base: split local MAC I/G back into separate flags Andrew Rybchenko
2017-03-02 16:03 ` [PATCH 02/11] net/sfc/base: improve API to get supported filter matches Andrew Rybchenko
2017-03-07 13:25   ` Ferruh Yigit
2017-03-07 14:47     ` Andrew Rybchenko
2017-03-07 14:56       ` Ferruh Yigit
2017-03-02 16:03 ` [PATCH 03/11] net/sfc: implement dummy filter control callback Andrew Rybchenko
2017-03-02 16:03 ` [PATCH 04/11] net/sfc: provide a way to check if filter is supported Andrew Rybchenko
2017-03-02 16:03 ` [PATCH 05/11] net/sfc: add flow API filters support Andrew Rybchenko
2017-03-07 13:21   ` Ferruh Yigit
2017-03-09 15:29     ` Andrew Rybchenko
2017-03-02 16:03 ` [PATCH 06/11] net/sfc: add VLAN in " Andrew Rybchenko
2017-03-02 16:03 ` [PATCH 07/11] net/sfc: add IPV4 " Andrew Rybchenko
2017-03-07 13:21   ` Ferruh Yigit
2017-03-02 16:03 ` [PATCH 08/11] net/sfc: add IPV6 " Andrew Rybchenko
2017-03-02 16:03 ` [PATCH 09/11] net/sfc: add TCP " Andrew Rybchenko
2017-03-02 16:03 ` [PATCH 10/11] net/sfc: add UDP " Andrew Rybchenko
2017-03-02 16:03 ` [PATCH 11/11] net/sfc: add unknown unicast/multicast match in flow API Andrew Rybchenko
2017-03-07 13:27 ` [PATCH 00/11] Support flow API in Solarflare PMD Ferruh Yigit
2017-03-07 14:56   ` Andrew Rybchenko
2017-03-09 15:26 ` [PATCH v2 " Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 01/11] net/sfc/base: split local MAC I/G back into separate flags Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 02/11] net/sfc/base: improve API to get supported filter matches Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 03/11] net/sfc: implement dummy filter control callback Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 04/11] net/sfc: provide a way to check if filter is supported Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 05/11] net/sfc: add flow API filters support Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 06/11] net/sfc: add VLAN in " Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 07/11] net/sfc: add IPV4 " Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 08/11] net/sfc: add IPV6 " Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 09/11] net/sfc: add TCP " Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 10/11] net/sfc: add UDP " Andrew Rybchenko
2017-03-09 15:26   ` [PATCH v2 11/11] net/sfc: add unknown unicast/multicast match in flow API Andrew Rybchenko
2017-03-09 17:28   ` [PATCH v2 00/11] Support flow API in Solarflare PMD Ferruh Yigit

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.