[v3] ethdev: add API to query proxy port to manage transfer flows

Message ID 20211006123300.7848-1-ivan.malov@oktetlabs.ru (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series [v3] ethdev: add API to query proxy port to manage transfer flows |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation warning apply issues
ci/iol-testing warning apply patch failure

Commit Message

Ivan Malov Oct. 6, 2021, 12:33 p.m. UTC
  Not all DPDK ports in a given switching domain may have the
privilege to manage "transfer" flows. Add an API to find a
port with sufficient privileges by any port in the domain.

Signed-off-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Acked-by: Ori Kam <orika@nvidia.com>
---
Patch series [1] has reworked support for "transfer" flows.
This allows to elaborate on the idea which first appeared
in RFC [2]. Hence the patch in question.

net/sfc driver is going to support the new API. The
corresponding patch is already in progress and will
be provided in the course of this release cycle.

[1] https://patches.dpdk.org/project/dpdk/list/?series=19326
[2] https://patches.dpdk.org/project/dpdk/list/?series=18737

Changes in v2:
* The patch has review notes from Thomas Monjalon applied
* The patch has the ack from Ori Kam added

Changes in v3:
* The patch has review notes from Andrew Rybchenko applied
---
 app/test-pmd/config.c                  | 106 ++++++++++++++++++++++++-
 app/test-pmd/testpmd.c                 |  21 +++++
 app/test-pmd/testpmd.h                 |   4 +
 app/test-pmd/util.c                    |   5 +-
 doc/guides/rel_notes/release_21_11.rst |   3 +
 lib/ethdev/rte_flow.c                  |  22 +++++
 lib/ethdev/rte_flow.h                  |  36 +++++++++
 lib/ethdev/rte_flow_driver.h           |   5 ++
 lib/ethdev/version.map                 |   3 +
 9 files changed, 201 insertions(+), 4 deletions(-)
  

Patch

diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 9c66329e96..2772c83d0a 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -1505,10 +1505,25 @@  port_action_handle_create(portid_t port_id, uint32_t id,
 	struct port_indirect_action *pia;
 	int ret;
 	struct rte_flow_error error;
+	struct rte_port *port;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
 
 	ret = action_alloc(port_id, id, &pia);
 	if (ret)
 		return ret;
+
+	port = &ports[port_id];
+
+	if (conf->transfer)
+		port_id = port->flow_transfer_proxy;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+
 	if (action->type == RTE_FLOW_ACTION_TYPE_AGE) {
 		struct rte_flow_action_age *age =
 			(struct rte_flow_action_age *)(uintptr_t)(action->conf);
@@ -1531,6 +1546,7 @@  port_action_handle_create(portid_t port_id, uint32_t id,
 		return port_flow_complain(&error);
 	}
 	pia->type = action->type;
+	pia->transfer = conf->transfer;
 	printf("Indirect action #%u created\n", pia->id);
 	return 0;
 }
@@ -1557,9 +1573,18 @@  port_action_handle_destroy(portid_t port_id,
 		for (i = 0; i != n; ++i) {
 			struct rte_flow_error error;
 			struct port_indirect_action *pia = *tmp;
+			portid_t port_id_eff = port_id;
 
 			if (actions[i] != pia->id)
 				continue;
+
+			if (pia->transfer)
+				port_id_eff = port->flow_transfer_proxy;
+
+			if (port_id_is_invalid(port_id_eff, ENABLED_WARN) ||
+			    port_id_eff == (portid_t)RTE_PORT_ALL)
+				return -EINVAL;
+
 			/*
 			 * Poisoning to make sure PMDs update it in case
 			 * of error.
@@ -1567,7 +1592,7 @@  port_action_handle_destroy(portid_t port_id,
 			memset(&error, 0x33, sizeof(error));
 
 			if (pia->handle && rte_flow_action_handle_destroy(
-					port_id, pia->handle, &error)) {
+					port_id_eff, pia->handle, &error)) {
 				ret = port_flow_complain(&error);
 				continue;
 			}
@@ -1602,8 +1627,15 @@  port_action_handle_update(portid_t port_id, uint32_t id,
 	struct rte_flow_error error;
 	struct rte_flow_action_handle *action_handle;
 	struct port_indirect_action *pia;
+	struct rte_port *port;
 	const void *update;
 
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+
+	port = &ports[port_id];
+
 	action_handle = port_action_handle_get_by_id(port_id, id);
 	if (!action_handle)
 		return -EINVAL;
@@ -1618,6 +1650,14 @@  port_action_handle_update(portid_t port_id, uint32_t id,
 		update = action;
 		break;
 	}
+
+	if (pia->transfer)
+		port_id = port->flow_transfer_proxy;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+
 	if (rte_flow_action_handle_update(port_id, action_handle, update,
 					  &error)) {
 		return port_flow_complain(&error);
@@ -1636,6 +1676,14 @@  port_action_handle_query(portid_t port_id, uint32_t id)
 		struct rte_flow_query_age age;
 		struct rte_flow_action_conntrack ct;
 	} query;
+	portid_t port_id_eff = port_id;
+	struct rte_port *port;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+
+	port = &ports[port_id];
 
 	pia = action_get_by_id(port_id, id);
 	if (!pia)
@@ -1650,10 +1698,19 @@  port_action_handle_query(portid_t port_id, uint32_t id)
 			id, pia->type, port_id);
 		return -ENOTSUP;
 	}
+
+	if (pia->transfer)
+		port_id_eff = port->flow_transfer_proxy;
+
+	if (port_id_is_invalid(port_id_eff, ENABLED_WARN) ||
+	    port_id_eff == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+
 	/* Poisoning to make sure PMDs update it in case of error. */
 	memset(&error, 0x55, sizeof(error));
 	memset(&query, 0, sizeof(query));
-	if (rte_flow_action_handle_query(port_id, pia->handle, &query, &error))
+	if (rte_flow_action_handle_query(port_id_eff, pia->handle, &query,
+					 &error))
 		return port_flow_complain(&error);
 	switch (pia->type) {
 	case RTE_FLOW_ACTION_TYPE_AGE:
@@ -1872,6 +1929,20 @@  port_flow_validate(portid_t port_id,
 {
 	struct rte_flow_error error;
 	struct port_flow_tunnel *pft = NULL;
+	struct rte_port *port;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+
+	port = &ports[port_id];
+
+	if (attr->transfer)
+		port_id = port->flow_transfer_proxy;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
 
 	/* Poisoning to make sure PMDs update it in case of error. */
 	memset(&error, 0x11, sizeof(error));
@@ -1925,7 +1996,19 @@  port_flow_create(portid_t port_id,
 	struct port_flow_tunnel *pft = NULL;
 	struct rte_flow_action_age *age = age_action_get(actions);
 
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+
 	port = &ports[port_id];
+
+	if (attr->transfer)
+		port_id = port->flow_transfer_proxy;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+
 	if (port->flow_list) {
 		if (port->flow_list->id == UINT32_MAX) {
 			fprintf(stderr,
@@ -1989,6 +2072,7 @@  port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule)
 		uint32_t i;
 
 		for (i = 0; i != n; ++i) {
+			portid_t port_id_eff = port_id;
 			struct rte_flow_error error;
 			struct port_flow *pf = *tmp;
 
@@ -1999,7 +2083,15 @@  port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule)
 			 * of error.
 			 */
 			memset(&error, 0x33, sizeof(error));
-			if (rte_flow_destroy(port_id, pf->flow, &error)) {
+
+			if (pf->rule.attr->transfer)
+				port_id_eff = port->flow_transfer_proxy;
+
+			if (port_id_is_invalid(port_id_eff, ENABLED_WARN) ||
+			    port_id_eff == (portid_t)RTE_PORT_ALL)
+				return -EINVAL;
+
+			if (rte_flow_destroy(port_id_eff, pf->flow, &error)) {
 				ret = port_flow_complain(&error);
 				continue;
 			}
@@ -2133,6 +2225,14 @@  port_flow_query(portid_t port_id, uint32_t rule,
 		fprintf(stderr, "Flow rule #%u not found\n", rule);
 		return -ENOENT;
 	}
+
+	if (pf->rule.attr->transfer)
+		port_id = port->flow_transfer_proxy;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+
 	ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,
 			    &name, sizeof(name),
 			    (void *)(uintptr_t)action->type, &error);
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 97ae52e17e..a88e920bd0 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -533,6 +533,25 @@  int proc_id;
  */
 unsigned int num_procs = 1;
 
+static void
+flow_pick_transfer_proxy_mp(uint16_t port_id)
+{
+	struct rte_port *port = &ports[port_id];
+	int ret;
+
+	port->flow_transfer_proxy = port_id;
+
+	if (!is_proc_primary())
+		return;
+
+	ret = rte_flow_pick_transfer_proxy(port_id, &port->flow_transfer_proxy,
+					   NULL);
+	if (ret != 0) {
+		fprintf(stderr, "Error picking flow transfer proxy for port %u: %s - ignore\n",
+			port_id, rte_strerror(-ret));
+	}
+}
+
 static int
 eth_dev_configure_mp(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
 		      const struct rte_eth_conf *dev_conf)
@@ -1489,6 +1508,8 @@  init_config_port_offloads(portid_t pid, uint32_t socket_id)
 	int ret;
 	int i;
 
+	flow_pick_transfer_proxy_mp(pid);
+
 	port->dev_conf.txmode = tx_mode;
 	port->dev_conf.rxmode = rx_mode;
 
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 5863b2f43f..b3dfd350e5 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -173,6 +173,8 @@  struct port_indirect_action {
 	enum rte_flow_action_type type; /**< Action type. */
 	struct rte_flow_action_handle *handle;	/**< Indirect action handle. */
 	enum age_action_context_type age_type; /**< Age action context type. */
+	/** If true, the action applies to "transfer" flows, and vice versa */
+	bool transfer;
 };
 
 struct port_flow_tunnel {
@@ -234,6 +236,8 @@  struct rte_port {
 	/**< dynamic flags. */
 	uint64_t		mbuf_dynf;
 	const struct rte_eth_rxtx_callback *tx_set_dynf_cb[RTE_MAX_QUEUES_PER_PORT+1];
+	/** Associated port which is supposed to handle "transfer" flows */
+	portid_t		flow_transfer_proxy;
 };
 
 /**
diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c
index 14a9a251fb..d9edbbf9ee 100644
--- a/app/test-pmd/util.c
+++ b/app/test-pmd/util.c
@@ -98,13 +98,16 @@  dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
 		int ret;
 		struct rte_flow_error error;
 		struct rte_flow_restore_info info = { 0, };
+		struct rte_port *port = &ports[port_id];
 
 		mb = pkts[i];
 		eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
 		eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
 		packet_type = mb->packet_type;
 		is_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);
-		ret = rte_flow_get_restore_info(port_id, mb, &info, &error);
+
+		ret = rte_flow_get_restore_info(port->flow_transfer_proxy,
+						mb, &info, &error);
 		if (!ret) {
 			MKDUMPSTR(print_buf, buf_size, cur_len,
 				  "restore info:");
diff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst
index 0787baed8c..894a23caba 100644
--- a/doc/guides/rel_notes/release_21_11.rst
+++ b/doc/guides/rel_notes/release_21_11.rst
@@ -67,6 +67,9 @@  New Features
   Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and
   TCP/UDP/SCTP header checksum field can be used as input set for RSS.
 
+* **Added an API to get a proxy port to manage "transfer" flows**
+  A new API, ``rte_flow_pick_transfer_proxy()``, was added.
+
 * **Updated Broadcom bnxt PMD.**
 
   * Added flow offload support for Thor.
diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
index 647bbf91ce..469a5f16b8 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -1270,3 +1270,25 @@  rte_flow_tunnel_item_release(uint16_t port_id,
 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
 				  NULL, rte_strerror(ENOTSUP));
 }
+
+int
+rte_flow_pick_transfer_proxy(uint16_t port_id, uint16_t *proxy_port_id,
+			     struct rte_flow_error *error)
+{
+	const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
+	struct rte_eth_dev *dev;
+
+	if (unlikely(ops == NULL))
+		return -rte_errno;
+
+	if (ops->pick_transfer_proxy == NULL) {
+		*proxy_port_id = port_id;
+		return 0;
+	}
+
+	dev = &rte_eth_devices[port_id];
+
+	return flow_err(port_id,
+			ops->pick_transfer_proxy(dev, proxy_port_id, error),
+			error);
+}
diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
index f195aa7224..66cb3b475d 100644
--- a/lib/ethdev/rte_flow.h
+++ b/lib/ethdev/rte_flow.h
@@ -122,6 +122,9 @@  struct rte_flow_attr {
 	 *
 	 * In order to match traffic originating from specific source(s), the
 	 * application should use pattern items ETHDEV and ESWITCH_PORT.
+	 *
+	 * Managing "transfer" flows requires that the user communicate them
+	 * through a suitable port. @see rte_flow_pick_transfer_proxy().
 	 */
 	uint32_t transfer:1;
 	uint32_t reserved:29; /**< Reserved, must be zero. */
@@ -4427,6 +4430,39 @@  rte_flow_tunnel_item_release(uint16_t port_id,
 			     struct rte_flow_item *items,
 			     uint32_t num_of_items,
 			     struct rte_flow_error *error);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Get a proxy port to manage "transfer" flows.
+ *
+ * Managing "transfer" flows requires that the user communicate them
+ * via a port which has the privilege to control the embedded switch.
+ * For some vendors, all ports in a given switching domain have
+ * this privilege. For other vendors, it's only one port.
+ *
+ * This API indicates such a privileged port (a "proxy")
+ * for a given port in the same switching domain.
+ *
+ * @note
+ *   If the PMD serving @p port_id doesn't have the corresponding method
+ *   implemented, the API will return @p port_id via @p proxy_port_id.
+ *
+ * @param port_id
+ *   Indicates the port to get a "proxy" for
+ * @param[out] proxy_port_id
+ *   Indicates the "proxy" port
+ * @param[out] error
+ *   If not NULL, allows the PMD to provide verbose report in case of error
+ *
+ * @return
+ *   0 on success, a negative error code otherwise
+ */
+__rte_experimental
+int
+rte_flow_pick_transfer_proxy(uint16_t port_id, uint16_t *proxy_port_id,
+			     struct rte_flow_error *error);
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/ethdev/rte_flow_driver.h b/lib/ethdev/rte_flow_driver.h
index 46f62c2ec2..ed52e59a0a 100644
--- a/lib/ethdev/rte_flow_driver.h
+++ b/lib/ethdev/rte_flow_driver.h
@@ -139,6 +139,11 @@  struct rte_flow_ops {
 		 struct rte_flow_item *pmd_items,
 		 uint32_t num_of_items,
 		 struct rte_flow_error *err);
+	/** See rte_flow_pick_transfer_proxy() */
+	int (*pick_transfer_proxy)
+		(struct rte_eth_dev *dev,
+		 uint16_t *proxy_port_id,
+		 struct rte_flow_error *error);
 };
 
 /**
diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
index 904bce6ea1..d4286dc8dd 100644
--- a/lib/ethdev/version.map
+++ b/lib/ethdev/version.map
@@ -247,6 +247,9 @@  EXPERIMENTAL {
 	rte_mtr_meter_policy_delete;
 	rte_mtr_meter_policy_update;
 	rte_mtr_meter_policy_validate;
+
+	# added in 21.11
+	rte_flow_pick_transfer_proxy;
 };
 
 INTERNAL {