net/sfc: support flow action port ID in transfer rules
authorIvan Malov <ivan.malov@oktetlabs.ru>
Tue, 20 Oct 2020 09:13:24 +0000 (10:13 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 3 Nov 2020 22:24:25 +0000 (23:24 +0100)
The action handler will use MAE action DELIVER with MPORT
of the PCIe function associated with a given DPDK port ID.
The DPDK port must not relate to a different physical device.

Signed-off-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
doc/guides/nics/sfc_efx.rst
drivers/net/sfc/sfc_mae.c
drivers/net/sfc/sfc_switch.c
drivers/net/sfc/sfc_switch.h

index 1bf21ac..1718bb1 100644 (file)
@@ -218,6 +218,8 @@ Supported actions (***transfer*** rules):
 
 - VF
 
+- PORT_ID
+
 - DROP
 
 Validating flow rules depends on the firmware variant.
index 64cd6b0..f309efa 100644 (file)
@@ -30,6 +30,7 @@ sfc_mae_assign_entity_mport(struct sfc_adapter *sa,
 int
 sfc_mae_attach(struct sfc_adapter *sa)
 {
+       struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
        struct sfc_mae_switch_port_request switch_port_request = {0};
        const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
        efx_mport_sel_t entity_mport;
@@ -67,6 +68,12 @@ sfc_mae_attach(struct sfc_adapter *sa)
        sfc_log_init(sa, "assign RTE switch port");
        switch_port_request.type = SFC_MAE_SWITCH_PORT_INDEPENDENT;
        switch_port_request.entity_mportp = &entity_mport;
+       /*
+        * As of now, the driver does not support representors, so
+        * RTE ethdev MPORT simply matches that of the entity.
+        */
+       switch_port_request.ethdev_mportp = &entity_mport;
+       switch_port_request.ethdev_port_id = sas->port_id;
        rc = sfc_mae_assign_switch_port(mae->switch_domain_id,
                                        &switch_port_request,
                                        &mae->switch_port_id);
@@ -793,6 +800,27 @@ sfc_mae_rule_parse_action_pf_vf(struct sfc_adapter *sa,
        return efx_mae_action_set_populate_deliver(spec, &mport);
 }
 
+static int
+sfc_mae_rule_parse_action_port_id(struct sfc_adapter *sa,
+                                 const struct rte_flow_action_port_id *conf,
+                                 efx_mae_actions_t *spec)
+{
+       struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
+       struct sfc_mae *mae = &sa->mae;
+       efx_mport_sel_t mport;
+       uint16_t port_id;
+       int rc;
+
+       port_id = (conf->original != 0) ? sas->port_id : conf->id;
+
+       rc = sfc_mae_switch_port_by_ethdev(mae->switch_domain_id,
+                                          port_id, &mport);
+       if (rc != 0)
+               return rc;
+
+       return efx_mae_action_set_populate_deliver(spec, &mport);
+}
+
 static int
 sfc_mae_rule_parse_action(struct sfc_adapter *sa,
                          const struct rte_flow_action *action,
@@ -848,6 +876,11 @@ sfc_mae_rule_parse_action(struct sfc_adapter *sa,
                                       bundle->actions_mask);
                rc = sfc_mae_rule_parse_action_pf_vf(sa, action->conf, spec);
                break;
+       case RTE_FLOW_ACTION_TYPE_PORT_ID:
+               SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_PORT_ID,
+                                      bundle->actions_mask);
+               rc = sfc_mae_rule_parse_action_port_id(sa, action->conf, spec);
+               break;
        case RTE_FLOW_ACTION_TYPE_DROP:
                SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_DROP,
                                       bundle->actions_mask);
index 395fc40..bdea2a2 100644 (file)
  * This mapping comprises a port type to ensure that RTE switch port ID
  * of a represented entity and that of its representor are different in
  * the case when the entity gets plugged into DPDK and not into a guest.
+ *
+ * Entry data also comprises RTE ethdev's own MPORT. This value
+ * coincides with the entity MPORT in the case of independent ports.
+ * In the case of representors, this ID is not a selector and refers
+ * to an allocatable object (that is, it's likely to change on RTE
+ * ethdev replug). Flow API backend must use this value rather
+ * than entity_mport to support flow rule action PORT_ID.
  */
 struct sfc_mae_switch_port {
        TAILQ_ENTRY(sfc_mae_switch_port)        switch_domain_ports;
 
+       /** RTE ethdev MPORT */
+       efx_mport_sel_t                         ethdev_mport;
+       /** RTE ethdev port ID */
+       uint16_t                                ethdev_port_id;
+
        /** Entity (PCIe function) MPORT selector */
        efx_mport_sel_t                         entity_mport;
        /** Port type (independent/representor) */
@@ -263,6 +275,9 @@ sfc_mae_assign_switch_port(uint16_t switch_domain_id,
        TAILQ_INSERT_TAIL(&domain->ports, port, switch_domain_ports);
 
 done:
+       port->ethdev_mport = *req->ethdev_mportp;
+       port->ethdev_port_id = req->ethdev_port_id;
+
        *switch_port_id = port->id;
 
        rte_spinlock_unlock(&sfc_mae_switch.lock);
@@ -274,3 +289,46 @@ fail_find_switch_domain_by_id:
        rte_spinlock_unlock(&sfc_mae_switch.lock);
        return rc;
 }
+
+/* This function expects to be called only when the lock is held */
+static int
+sfc_mae_find_switch_port_by_ethdev(uint16_t switch_domain_id,
+                                  uint16_t ethdev_port_id,
+                                  efx_mport_sel_t *mport_sel)
+{
+       struct sfc_mae_switch_domain *domain;
+       struct sfc_mae_switch_port *port;
+
+       SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
+
+       if (ethdev_port_id == RTE_MAX_ETHPORTS)
+               return EINVAL;
+
+       domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
+       if (domain == NULL)
+               return EINVAL;
+
+       TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
+               if (port->ethdev_port_id == ethdev_port_id) {
+                       *mport_sel = port->ethdev_mport;
+                       return 0;
+               }
+       }
+
+       return ENOENT;
+}
+
+int
+sfc_mae_switch_port_by_ethdev(uint16_t switch_domain_id,
+                             uint16_t ethdev_port_id,
+                             efx_mport_sel_t *mport_sel)
+{
+       int rc;
+
+       rte_spinlock_lock(&sfc_mae_switch.lock);
+       rc = sfc_mae_find_switch_port_by_ethdev(switch_domain_id,
+                                               ethdev_port_id, mport_sel);
+       rte_spinlock_unlock(&sfc_mae_switch.lock);
+
+       return rc;
+}
index 9845ac8..96ece95 100644 (file)
@@ -32,6 +32,8 @@ enum sfc_mae_switch_port_type {
 struct sfc_mae_switch_port_request {
        enum sfc_mae_switch_port_type           type;
        const efx_mport_sel_t                   *entity_mportp;
+       const efx_mport_sel_t                   *ethdev_mportp;
+       uint16_t                                ethdev_port_id;
 };
 
 int sfc_mae_assign_switch_domain(struct sfc_adapter *sa,
@@ -41,6 +43,10 @@ int sfc_mae_assign_switch_port(uint16_t switch_domain_id,
                               const struct sfc_mae_switch_port_request *req,
                               uint16_t *switch_port_id);
 
+int sfc_mae_switch_port_by_ethdev(uint16_t switch_domain_id,
+                                 uint16_t ethdev_port_id,
+                                 efx_mport_sel_t *mport_sel);
+
 #ifdef __cplusplus
 }
 #endif