ethdev: query proxy port to manage transfer flows
authorIvan Malov <ivan.malov@oktetlabs.ru>
Thu, 14 Oct 2021 03:21:45 +0000 (06:21 +0300)
committerFerruh Yigit <ferruh.yigit@intel.com>
Thu, 14 Oct 2021 11:42:59 +0000 (13:42 +0200)
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>
app/test-pmd/config.c
app/test-pmd/testpmd.c
app/test-pmd/testpmd.h
app/test-pmd/util.c
doc/guides/rel_notes/release_21_11.rst
lib/ethdev/rte_flow.c
lib/ethdev/rte_flow.h
lib/ethdev/rte_flow_driver.h
lib/ethdev/version.map

index 7221644..6ea8630 100644 (file)
@@ -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);
index a7841c5..38d7ce8 100644 (file)
@@ -568,6 +568,25 @@ eth_rx_metadata_negotiate_mp(uint16_t port_id)
        }
 }
 
+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)
@@ -1525,6 +1544,7 @@ init_config_port_offloads(portid_t pid, uint32_t socket_id)
        int i;
 
        eth_rx_metadata_negotiate_mp(pid);
+       flow_pick_transfer_proxy_mp(pid);
 
        port->dev_conf.txmode = tx_mode;
        port->dev_conf.rxmode = rx_mode;
index e9d9db0..786b7c7 100644 (file)
@@ -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;
 };
 
 /**
index 51506e4..480cc11 100644 (file)
@@ -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:");
index bbb056b..0c3ecd3 100644 (file)
@@ -94,6 +94,10 @@ New Features
   * ``RTE_ETH_RX_METADATA_USER_MARK``
   * ``RTE_ETH_RX_METADATA_TUNNEL_ID``
 
+* **Added an API to get a proxy port to manage "transfer" flows.**
+
+  A new API, ``rte_flow_pick_transfer_proxy()``, was added.
+
 * **Updated af_packet ethdev driver.**
 
   * Default VLAN strip behavior was changed. VLAN tag won't be stripped
index 542e40e..29f2b0e 100644 (file)
@@ -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);
+}
index 7e7b4bc..ba36edb 100644 (file)
@@ -122,6 +122,9 @@ struct rte_flow_attr {
         *
         * The application should match traffic originating from precise
         * locations. See items PORT_REPRESENTOR and REPRESENTED_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. */
@@ -4430,6 +4433,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
index 46f62c2..ed52e59 100644 (file)
@@ -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);
 };
 
 /**
index 96ac8ab..6c68d97 100644 (file)
@@ -251,6 +251,7 @@ EXPERIMENTAL {
        # added in 21.11
        rte_eth_macaddrs_get;
        rte_eth_rx_metadata_negotiate;
+       rte_flow_pick_transfer_proxy;
 };
 
 INTERNAL {