From patchwork Fri Aug 27 06:56:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Rybchenko X-Patchwork-Id: 97435 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id D5DE8A0C43; Fri, 27 Aug 2021 08:59:33 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 38DAD4126D; Fri, 27 Aug 2021 08:58:41 +0200 (CEST) Received: from shelob.oktetlabs.ru (shelob.oktetlabs.ru [91.220.146.113]) by mails.dpdk.org (Postfix) with ESMTP id 9FB1341251 for ; Fri, 27 Aug 2021 08:58:36 +0200 (CEST) Received: by shelob.oktetlabs.ru (Postfix, from userid 122) id 67B3B7F6DB; Fri, 27 Aug 2021 09:58:36 +0300 (MSK) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on shelob.oktetlabs.ru X-Spam-Level: X-Spam-Status: No, score=0.8 required=5.0 tests=ALL_TRUSTED, DKIM_ADSP_DISCARD, URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from aros.oktetlabs.ru (aros.oktetlabs.ru [192.168.38.17]) by shelob.oktetlabs.ru (Postfix) with ESMTP id E07F17F6E4; Fri, 27 Aug 2021 09:57:34 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 shelob.oktetlabs.ru E07F17F6E4 Authentication-Results: shelob.oktetlabs.ru/E07F17F6E4; dkim=none; dkim-atps=neutral From: Andrew Rybchenko To: dev@dpdk.org Cc: Igor Romanov , Andy Moreton , Ivan Malov Date: Fri, 27 Aug 2021 09:56:58 +0300 Message-Id: <20210827065717.1838258-20-andrew.rybchenko@oktetlabs.ru> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210827065717.1838258-1-andrew.rybchenko@oktetlabs.ru> References: <20210827065717.1838258-1-andrew.rybchenko@oktetlabs.ru> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH 19/38] net/sfc: implement port representor start and stop X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Igor Romanov Implement queue start and stop operation both in port representors and representor proxy. Signed-off-by: Igor Romanov Signed-off-by: Andrew Rybchenko Reviewed-by: Andy Moreton Reviewed-by: Ivan Malov --- drivers/net/sfc/sfc_mae.h | 9 +- drivers/net/sfc/sfc_repr.c | 181 +++++++++++ drivers/net/sfc/sfc_repr_proxy.c | 453 ++++++++++++++++++++++++++- drivers/net/sfc/sfc_repr_proxy.h | 16 + drivers/net/sfc/sfc_repr_proxy_api.h | 3 + 5 files changed, 644 insertions(+), 18 deletions(-) diff --git a/drivers/net/sfc/sfc_mae.h b/drivers/net/sfc/sfc_mae.h index 684f0daf7a..d835056aef 100644 --- a/drivers/net/sfc/sfc_mae.h +++ b/drivers/net/sfc/sfc_mae.h @@ -139,10 +139,17 @@ struct sfc_mae_counter_registry { uint32_t service_id; }; +/** + * MAE rules used to capture traffic generated by VFs and direct it to + * representors (one for each VF). + */ +#define SFC_MAE_NB_REPR_RULES_MAX (64) + /** Rules to forward traffic from PHY port to PF and from PF to PHY port */ #define SFC_MAE_NB_SWITCHDEV_RULES (2) /** Maximum required internal MAE rules */ -#define SFC_MAE_NB_RULES_MAX (SFC_MAE_NB_SWITCHDEV_RULES) +#define SFC_MAE_NB_RULES_MAX (SFC_MAE_NB_SWITCHDEV_RULES + \ + SFC_MAE_NB_REPR_RULES_MAX) struct sfc_mae_rule { efx_mae_match_spec_t *spec; diff --git a/drivers/net/sfc/sfc_repr.c b/drivers/net/sfc/sfc_repr.c index b3876586cc..bfe6dd4c9b 100644 --- a/drivers/net/sfc/sfc_repr.c +++ b/drivers/net/sfc/sfc_repr.c @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -21,6 +22,7 @@ #include "sfc_ethdev_state.h" #include "sfc_repr_proxy_api.h" #include "sfc_switch.h" +#include "sfc_dp_tx.h" /** Multi-process shared representor private data */ struct sfc_repr_shared { @@ -144,6 +146,179 @@ sfc_repr_lock_fini(__rte_unused struct sfc_repr *sr) /* Just for symmetry of the API */ } +static void +sfc_repr_rx_queue_stop(void *queue) +{ + struct sfc_repr_rxq *rxq = queue; + + if (rxq == NULL) + return; + + rte_ring_reset(rxq->ring); +} + +static void +sfc_repr_tx_queue_stop(void *queue) +{ + struct sfc_repr_txq *txq = queue; + + if (txq == NULL) + return; + + rte_ring_reset(txq->ring); +} + +static int +sfc_repr_start(struct rte_eth_dev *dev) +{ + struct sfc_repr *sr = sfc_repr_by_eth_dev(dev); + struct sfc_repr_shared *srs; + int ret; + + sfcr_info(sr, "entry"); + + SFC_ASSERT(sfc_repr_lock_is_locked(sr)); + + switch (sr->state) { + case SFC_ETHDEV_CONFIGURED: + break; + case SFC_ETHDEV_STARTED: + sfcr_info(sr, "already started"); + return 0; + default: + ret = -EINVAL; + goto fail_bad_state; + } + + sr->state = SFC_ETHDEV_STARTING; + + srs = sfc_repr_shared_by_eth_dev(dev); + ret = sfc_repr_proxy_start_repr(srs->pf_port_id, srs->repr_id); + if (ret != 0) { + SFC_ASSERT(ret > 0); + ret = -ret; + goto fail_start; + } + + sr->state = SFC_ETHDEV_STARTED; + + sfcr_info(sr, "done"); + + return 0; + +fail_start: + sr->state = SFC_ETHDEV_CONFIGURED; + +fail_bad_state: + sfcr_err(sr, "%s() failed: %s", __func__, rte_strerror(-ret)); + return ret; +} + +static int +sfc_repr_dev_start(struct rte_eth_dev *dev) +{ + struct sfc_repr *sr = sfc_repr_by_eth_dev(dev); + int ret; + + sfcr_info(sr, "entry"); + + sfc_repr_lock(sr); + ret = sfc_repr_start(dev); + sfc_repr_unlock(sr); + + if (ret != 0) + goto fail_start; + + sfcr_info(sr, "done"); + + return 0; + +fail_start: + sfcr_err(sr, "%s() failed: %s", __func__, rte_strerror(-ret)); + return ret; +} + +static int +sfc_repr_stop(struct rte_eth_dev *dev) +{ + struct sfc_repr *sr = sfc_repr_by_eth_dev(dev); + struct sfc_repr_shared *srs; + unsigned int i; + int ret; + + sfcr_info(sr, "entry"); + + SFC_ASSERT(sfc_repr_lock_is_locked(sr)); + + switch (sr->state) { + case SFC_ETHDEV_STARTED: + break; + case SFC_ETHDEV_CONFIGURED: + sfcr_info(sr, "already stopped"); + return 0; + default: + sfcr_err(sr, "stop in unexpected state %u", sr->state); + SFC_ASSERT(B_FALSE); + ret = -EINVAL; + goto fail_bad_state; + } + + srs = sfc_repr_shared_by_eth_dev(dev); + ret = sfc_repr_proxy_stop_repr(srs->pf_port_id, srs->repr_id); + if (ret != 0) { + SFC_ASSERT(ret > 0); + ret = -ret; + goto fail_stop; + } + + for (i = 0; i < dev->data->nb_rx_queues; i++) + sfc_repr_rx_queue_stop(dev->data->rx_queues[i]); + + for (i = 0; i < dev->data->nb_tx_queues; i++) + sfc_repr_tx_queue_stop(dev->data->tx_queues[i]); + + sr->state = SFC_ETHDEV_CONFIGURED; + sfcr_info(sr, "done"); + + return 0; + +fail_bad_state: +fail_stop: + sfcr_err(sr, "%s() failed: %s", __func__, rte_strerror(-ret)); + + return ret; +} + +static int +sfc_repr_dev_stop(struct rte_eth_dev *dev) +{ + struct sfc_repr *sr = sfc_repr_by_eth_dev(dev); + int ret; + + sfcr_info(sr, "entry"); + + sfc_repr_lock(sr); + + ret = sfc_repr_stop(dev); + if (ret != 0) { + sfcr_err(sr, "%s() failed to stop representor", __func__); + goto fail_stop; + } + + sfc_repr_unlock(sr); + + sfcr_info(sr, "done"); + + return 0; + +fail_stop: + sfc_repr_unlock(sr); + + sfcr_err(sr, "%s() failed %s", __func__, rte_strerror(-ret)); + + return ret; +} + static int sfc_repr_check_conf(struct sfc_repr *sr, uint16_t nb_rx_queues, const struct rte_eth_conf *conf) @@ -557,6 +732,10 @@ sfc_repr_dev_close(struct rte_eth_dev *dev) sfc_repr_lock(sr); switch (sr->state) { + case SFC_ETHDEV_STARTED: + sfc_repr_stop(dev); + SFC_ASSERT(sr->state == SFC_ETHDEV_CONFIGURED); + /* FALLTHROUGH */ case SFC_ETHDEV_CONFIGURED: sfc_repr_close(sr); SFC_ASSERT(sr->state == SFC_ETHDEV_INITIALIZED); @@ -599,6 +778,8 @@ sfc_repr_dev_close(struct rte_eth_dev *dev) static const struct eth_dev_ops sfc_repr_dev_ops = { .dev_configure = sfc_repr_dev_configure, + .dev_start = sfc_repr_dev_start, + .dev_stop = sfc_repr_dev_stop, .dev_close = sfc_repr_dev_close, .dev_infos_get = sfc_repr_dev_infos_get, .rx_queue_setup = sfc_repr_rx_queue_setup, diff --git a/drivers/net/sfc/sfc_repr_proxy.c b/drivers/net/sfc/sfc_repr_proxy.c index a5be8fa270..ea03d5afdd 100644 --- a/drivers/net/sfc/sfc_repr_proxy.c +++ b/drivers/net/sfc/sfc_repr_proxy.c @@ -53,6 +53,19 @@ sfc_put_adapter(struct sfc_adapter *sa) sfc_adapter_unlock(sa); } +static struct sfc_repr_proxy_port * +sfc_repr_proxy_find_port(struct sfc_repr_proxy *rp, uint16_t repr_id) +{ + struct sfc_repr_proxy_port *port; + + TAILQ_FOREACH(port, &rp->ports, entries) { + if (port->repr_id == repr_id) + return port; + } + + return NULL; +} + static int sfc_repr_proxy_mbox_send(struct sfc_repr_proxy_mbox *mbox, struct sfc_repr_proxy_port *port, @@ -117,6 +130,12 @@ sfc_repr_proxy_mbox_handle(struct sfc_repr_proxy *rp) case SFC_REPR_PROXY_MBOX_DEL_PORT: TAILQ_REMOVE(&rp->ports, mbox->port, entries); break; + case SFC_REPR_PROXY_MBOX_START_PORT: + mbox->port->started = true; + break; + case SFC_REPR_PROXY_MBOX_STOP_PORT: + mbox->port->started = false; + break; default: SFC_ASSERT(0); return; @@ -463,6 +482,158 @@ sfc_repr_proxy_rxq_start(struct sfc_adapter *sa) return rc; } +static int +sfc_repr_proxy_mae_rule_insert(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) +{ + struct sfc_repr_proxy *rp = &sa->repr_proxy; + efx_mport_sel_t mport_alias_selector; + efx_mport_sel_t mport_vf_selector; + struct sfc_mae_rule *mae_rule; + int rc; + + sfc_log_init(sa, "entry"); + + rc = efx_mae_mport_by_id(&port->egress_mport, + &mport_vf_selector); + if (rc != 0) { + sfc_err(sa, "failed to get VF mport for repr %u", + port->repr_id); + goto fail_get_vf; + } + + rc = efx_mae_mport_by_id(&rp->mport_alias, &mport_alias_selector); + if (rc != 0) { + sfc_err(sa, "failed to get mport selector for repr %u", + port->repr_id); + goto fail_get_alias; + } + + rc = sfc_mae_rule_add_mport_match_deliver(sa, &mport_vf_selector, + &mport_alias_selector, -1, + &mae_rule); + if (rc != 0) { + sfc_err(sa, "failed to insert MAE rule for repr %u", + port->repr_id); + goto fail_rule_add; + } + + port->mae_rule = mae_rule; + + sfc_log_init(sa, "done"); + + return 0; + +fail_rule_add: +fail_get_alias: +fail_get_vf: + sfc_log_init(sa, "failed: %s", rte_strerror(rc)); + return rc; +} + +static void +sfc_repr_proxy_mae_rule_remove(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) +{ + struct sfc_mae_rule *mae_rule = port->mae_rule; + + sfc_mae_rule_del(sa, mae_rule); +} + +static int +sfc_repr_proxy_mport_filter_insert(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_rxq *rxq_ctrl; + struct sfc_repr_proxy_filter *filter = &rp->mport_filter; + efx_mport_sel_t mport_alias_selector; + static const efx_filter_match_flags_t flags[RTE_DIM(filter->specs)] = { + EFX_FILTER_MATCH_UNKNOWN_UCAST_DST, + EFX_FILTER_MATCH_UNKNOWN_MCAST_DST }; + unsigned int i; + int rc; + + sfc_log_init(sa, "entry"); + + if (sfc_repr_nb_rxq(sas) == 1) { + rxq_ctrl = &sa->rxq_ctrl[rp->dp_rxq[0].sw_index]; + } else { + sfc_err(sa, "multiple representor proxy RxQs not supported"); + rc = ENOTSUP; + goto fail_multiple_queues; + } + + rc = efx_mae_mport_by_id(&rp->mport_alias, &mport_alias_selector); + if (rc != 0) { + sfc_err(sa, "failed to get repr proxy mport by ID"); + goto fail_get_selector; + } + + memset(filter->specs, 0, sizeof(filter->specs)); + for (i = 0; i < RTE_DIM(filter->specs); i++) { + filter->specs[i].efs_priority = EFX_FILTER_PRI_MANUAL; + filter->specs[i].efs_flags = EFX_FILTER_FLAG_RX; + filter->specs[i].efs_dmaq_id = rxq_ctrl->hw_index; + filter->specs[i].efs_match_flags = flags[i] | + EFX_FILTER_MATCH_MPORT; + filter->specs[i].efs_ingress_mport = mport_alias_selector.sel; + + rc = efx_filter_insert(sa->nic, &filter->specs[i]); + if (rc != 0) { + sfc_err(sa, "failed to insert repr proxy filter"); + goto fail_insert; + } + } + + sfc_log_init(sa, "done"); + + return 0; + +fail_insert: + while (i-- > 0) + efx_filter_remove(sa->nic, &filter->specs[i]); + +fail_get_selector: +fail_multiple_queues: + sfc_log_init(sa, "failed: %s", rte_strerror(rc)); + return rc; +} + +static void +sfc_repr_proxy_mport_filter_remove(struct sfc_adapter *sa) +{ + struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_repr_proxy_filter *filter = &rp->mport_filter; + unsigned int i; + + for (i = 0; i < RTE_DIM(filter->specs); i++) + efx_filter_remove(sa->nic, &filter->specs[i]); +} + +static int +sfc_repr_proxy_port_rule_insert(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) +{ + int rc; + + rc = sfc_repr_proxy_mae_rule_insert(sa, port); + if (rc != 0) + goto fail_mae_rule_insert; + + return 0; + +fail_mae_rule_insert: + return rc; +} + +static void +sfc_repr_proxy_port_rule_remove(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) +{ + sfc_repr_proxy_mae_rule_remove(sa, port); +} + static int sfc_repr_proxy_ports_init(struct sfc_adapter *sa) { @@ -644,24 +815,105 @@ sfc_repr_proxy_detach(struct sfc_adapter *sa) sfc_log_init(sa, "done"); } +static int +sfc_repr_proxy_do_start_port(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) +{ + struct sfc_repr_proxy *rp = &sa->repr_proxy; + int rc; + + rc = sfc_repr_proxy_port_rule_insert(sa, port); + if (rc != 0) + goto fail_filter_insert; + + if (rp->started) { + rc = sfc_repr_proxy_mbox_send(&rp->mbox, port, + SFC_REPR_PROXY_MBOX_START_PORT); + if (rc != 0) { + sfc_err(sa, "failed to start proxy port %u", + port->repr_id); + goto fail_port_start; + } + } else { + port->started = true; + } + + return 0; + +fail_port_start: + sfc_repr_proxy_port_rule_remove(sa, port); +fail_filter_insert: + sfc_err(sa, "%s() failed %s", __func__, rte_strerror(rc)); + + return rc; +} + +static int +sfc_repr_proxy_do_stop_port(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) + +{ + struct sfc_repr_proxy *rp = &sa->repr_proxy; + int rc; + + if (rp->started) { + rc = sfc_repr_proxy_mbox_send(&rp->mbox, port, + SFC_REPR_PROXY_MBOX_STOP_PORT); + if (rc != 0) { + sfc_err(sa, "failed to stop proxy port %u: %s", + port->repr_id, rte_strerror(rc)); + return rc; + } + } else { + port->started = false; + } + + sfc_repr_proxy_port_rule_remove(sa, port); + + return 0; +} + +static bool +sfc_repr_proxy_port_enabled(struct sfc_repr_proxy_port *port) +{ + return port->rte_port_id != RTE_MAX_ETHPORTS && port->enabled; +} + +static bool +sfc_repr_proxy_ports_disabled(struct sfc_repr_proxy *rp) +{ + struct sfc_repr_proxy_port *port; + + TAILQ_FOREACH(port, &rp->ports, entries) { + if (sfc_repr_proxy_port_enabled(port)) + return false; + } + + return true; +} + int sfc_repr_proxy_start(struct sfc_adapter *sa) { struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_repr_proxy_port *last_port = NULL; + struct sfc_repr_proxy_port *port; int rc; sfc_log_init(sa, "entry"); - /* - * The condition to start the proxy is insufficient. It will be - * complemented with representor port start/stop support. - */ + /* Representor proxy is not started when no representors are started */ if (!sfc_repr_available(sas)) { sfc_log_init(sa, "representors not supported - skip"); return 0; } + if (sfc_repr_proxy_ports_disabled(rp)) { + sfc_log_init(sa, "no started representor ports - skip"); + return 0; + } + rc = sfc_repr_proxy_rxq_start(sa); if (rc != 0) goto fail_rxq_start; @@ -698,12 +950,40 @@ sfc_repr_proxy_start(struct sfc_adapter *sa) goto fail_runstate_set; } + TAILQ_FOREACH(port, &rp->ports, entries) { + if (sfc_repr_proxy_port_enabled(port)) { + rc = sfc_repr_proxy_do_start_port(sa, port); + if (rc != 0) + goto fail_start_id; + + last_port = port; + } + } + + rc = sfc_repr_proxy_mport_filter_insert(sa); + if (rc != 0) + goto fail_mport_filter_insert; + rp->started = true; sfc_log_init(sa, "done"); return 0; +fail_mport_filter_insert: +fail_start_id: + if (last_port != NULL) { + TAILQ_FOREACH(port, &rp->ports, entries) { + if (sfc_repr_proxy_port_enabled(port)) { + (void)sfc_repr_proxy_do_stop_port(sa, port); + if (port == last_port) + break; + } + } + } + + rte_service_runstate_set(rp->service_id, 0); + fail_runstate_set: rte_service_component_runstate_set(rp->service_id, 0); @@ -726,6 +1006,7 @@ sfc_repr_proxy_stop(struct sfc_adapter *sa) { struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_repr_proxy_port *port; int rc; sfc_log_init(sa, "entry"); @@ -735,6 +1016,24 @@ sfc_repr_proxy_stop(struct sfc_adapter *sa) return; } + if (sfc_repr_proxy_ports_disabled(rp)) { + sfc_log_init(sa, "no started representor ports - skip"); + return; + } + + TAILQ_FOREACH(port, &rp->ports, entries) { + if (sfc_repr_proxy_port_enabled(port)) { + rc = sfc_repr_proxy_do_stop_port(sa, port); + if (rc != 0) { + sfc_err(sa, + "failed to stop representor proxy port %u: %s", + port->repr_id, rte_strerror(rc)); + } + } + } + + sfc_repr_proxy_mport_filter_remove(sa); + rc = rte_service_runstate_set(rp->service_id, 0); if (rc < 0) { sfc_err(sa, "failed to stop %s: %s", @@ -759,19 +1058,6 @@ sfc_repr_proxy_stop(struct sfc_adapter *sa) sfc_log_init(sa, "done"); } -static struct sfc_repr_proxy_port * -sfc_repr_proxy_find_port(struct sfc_repr_proxy *rp, uint16_t repr_id) -{ - struct sfc_repr_proxy_port *port; - - TAILQ_FOREACH(port, &rp->ports, entries) { - if (port->repr_id == repr_id) - return port; - } - - return NULL; -} - int sfc_repr_proxy_add_port(uint16_t pf_port_id, uint16_t repr_id, uint16_t rte_port_id, const efx_mport_sel_t *mport_sel) @@ -1020,3 +1306,136 @@ sfc_repr_proxy_del_txq(uint16_t pf_port_id, uint16_t repr_id, sfc_log_init(sa, "done"); sfc_put_adapter(sa); } + +int +sfc_repr_proxy_start_repr(uint16_t pf_port_id, uint16_t repr_id) +{ + bool proxy_start_required = false; + struct sfc_repr_proxy_port *port; + struct sfc_repr_proxy *rp; + struct sfc_adapter *sa; + int rc; + + sa = sfc_get_adapter_by_pf_port_id(pf_port_id); + rp = sfc_repr_proxy_by_adapter(sa); + + sfc_log_init(sa, "entry"); + + port = sfc_repr_proxy_find_port(rp, repr_id); + if (port == NULL) { + sfc_err(sa, "%s() failed: no such port", __func__); + rc = ENOENT; + goto fail_not_found; + } + + if (port->enabled) { + rc = EALREADY; + sfc_err(sa, "failed: repr %u proxy port already started", + repr_id); + goto fail_already_started; + } + + if (sa->state == SFC_ETHDEV_STARTED) { + if (sfc_repr_proxy_ports_disabled(rp)) { + proxy_start_required = true; + } else { + rc = sfc_repr_proxy_do_start_port(sa, port); + if (rc != 0) { + sfc_err(sa, + "failed to start repr %u proxy port", + repr_id); + goto fail_start_id; + } + } + } + + port->enabled = true; + + if (proxy_start_required) { + rc = sfc_repr_proxy_start(sa); + if (rc != 0) { + sfc_err(sa, "failed to start proxy"); + goto fail_proxy_start; + } + } + + sfc_log_init(sa, "done"); + sfc_put_adapter(sa); + + return 0; + +fail_proxy_start: + port->enabled = false; + +fail_start_id: +fail_already_started: +fail_not_found: + sfc_err(sa, "failed to start repr %u proxy port: %s", repr_id, + rte_strerror(rc)); + sfc_put_adapter(sa); + + return rc; +} + +int +sfc_repr_proxy_stop_repr(uint16_t pf_port_id, uint16_t repr_id) +{ + struct sfc_repr_proxy_port *port; + struct sfc_repr_proxy_port *p; + struct sfc_repr_proxy *rp; + struct sfc_adapter *sa; + int rc; + + sa = sfc_get_adapter_by_pf_port_id(pf_port_id); + rp = sfc_repr_proxy_by_adapter(sa); + + sfc_log_init(sa, "entry"); + + port = sfc_repr_proxy_find_port(rp, repr_id); + if (port == NULL) { + sfc_err(sa, "%s() failed: no such port", __func__); + return ENOENT; + } + + if (!port->enabled) { + sfc_log_init(sa, "repr %u proxy port is not started - skip", + repr_id); + sfc_put_adapter(sa); + return 0; + } + + if (sa->state == SFC_ETHDEV_STARTED) { + bool last_enabled = true; + + TAILQ_FOREACH(p, &rp->ports, entries) { + if (p == port) + continue; + + if (sfc_repr_proxy_port_enabled(p)) { + last_enabled = false; + break; + } + } + + rc = 0; + if (last_enabled) + sfc_repr_proxy_stop(sa); + else + rc = sfc_repr_proxy_do_stop_port(sa, port); + + if (rc != 0) { + sfc_err(sa, + "failed to stop representor proxy TxQ %u: %s", + repr_id, rte_strerror(rc)); + sfc_put_adapter(sa); + return rc; + } + } + + port->enabled = false; + + sfc_log_init(sa, "done"); + sfc_put_adapter(sa); + + return 0; +} diff --git a/drivers/net/sfc/sfc_repr_proxy.h b/drivers/net/sfc/sfc_repr_proxy.h index 1fe7ff3695..c350713a55 100644 --- a/drivers/net/sfc/sfc_repr_proxy.h +++ b/drivers/net/sfc/sfc_repr_proxy.h @@ -19,6 +19,8 @@ #include "sfc_repr.h" #include "sfc_dp.h" +#include "sfc_flow.h" +#include "sfc_mae.h" #ifdef __cplusplus extern "C" { @@ -49,6 +51,14 @@ struct sfc_repr_proxy_txq { struct rte_ring *ring; }; +struct sfc_repr_proxy_filter { + /* + * 2 filters are required to match all incoming traffic, unknown + * unicast and unknown multicast. + */ + efx_filter_spec_t specs[2]; +}; + struct sfc_repr_proxy_port { TAILQ_ENTRY(sfc_repr_proxy_port) entries; uint16_t repr_id; @@ -56,6 +66,9 @@ struct sfc_repr_proxy_port { efx_mport_id_t egress_mport; struct sfc_repr_proxy_rxq rxq[SFC_REPR_RXQ_MAX]; struct sfc_repr_proxy_txq txq[SFC_REPR_TXQ_MAX]; + struct sfc_mae_rule *mae_rule; + bool enabled; + bool started; }; struct sfc_repr_proxy_dp_rxq { @@ -72,6 +85,8 @@ struct sfc_repr_proxy_dp_txq { enum sfc_repr_proxy_mbox_op { SFC_REPR_PROXY_MBOX_ADD_PORT, SFC_REPR_PROXY_MBOX_DEL_PORT, + SFC_REPR_PROXY_MBOX_START_PORT, + SFC_REPR_PROXY_MBOX_STOP_PORT, }; struct sfc_repr_proxy_mbox { @@ -92,6 +107,7 @@ struct sfc_repr_proxy { bool started; struct sfc_repr_proxy_dp_rxq dp_rxq[SFC_REPR_PROXY_NB_RXQ_MAX]; struct sfc_repr_proxy_dp_txq dp_txq[SFC_REPR_PROXY_NB_TXQ_MAX]; + struct sfc_repr_proxy_filter mport_filter; struct sfc_repr_proxy_mbox mbox; }; diff --git a/drivers/net/sfc/sfc_repr_proxy_api.h b/drivers/net/sfc/sfc_repr_proxy_api.h index d1c0760efa..95b065801d 100644 --- a/drivers/net/sfc/sfc_repr_proxy_api.h +++ b/drivers/net/sfc/sfc_repr_proxy_api.h @@ -38,6 +38,9 @@ int sfc_repr_proxy_add_txq(uint16_t pf_port_id, uint16_t repr_id, void sfc_repr_proxy_del_txq(uint16_t pf_port_id, uint16_t repr_id, uint16_t queue_id); +int sfc_repr_proxy_start_repr(uint16_t pf_port_id, uint16_t repr_id); +int sfc_repr_proxy_stop_repr(uint16_t pf_port_id, uint16_t repr_id); + #ifdef __cplusplus } #endif