From 36c35355f6c91c885ed8b50db8af8997a6f0abc4 Mon Sep 17 00:00:00 2001 From: Andrew Rybchenko Date: Sun, 24 Dec 2017 10:46:39 +0000 Subject: [PATCH] net/sfc: support UDP tunnel ports configuration Signed-off-by: Andrew Rybchenko Reviewed-by: Ivan Malov Reviewed-by: Andy Moreton --- doc/guides/nics/sfc_efx.rst | 9 +++ drivers/net/sfc/efsys.h | 2 +- drivers/net/sfc/sfc.c | 24 +++++++ drivers/net/sfc/sfc_ethdev.c | 119 +++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 1 deletion(-) diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst index ae2b54a2ea..bde3cc8fd9 100644 --- a/doc/guides/nics/sfc_efx.rst +++ b/doc/guides/nics/sfc_efx.rst @@ -116,6 +116,15 @@ required in the receive buffer. It should be taken into account when mbuf pool for receive is created. +Tunnels support +--------------- + +NVGRE, VXLAN and GENEVE tunnels are supported on SFN8xxx family adapters +with full-feature firmware variant running. +**sfboot** should be used to configure NIC to run full-feature firmware variant. +See Solarflare Server Adapter User's Guide for details. + + Flow API support ---------------- diff --git a/drivers/net/sfc/efsys.h b/drivers/net/sfc/efsys.h index ba2ee9a652..37e3c0250e 100644 --- a/drivers/net/sfc/efsys.h +++ b/drivers/net/sfc/efsys.h @@ -214,7 +214,7 @@ prefetch_read_once(const volatile void *addr) #define EFSYS_OPT_RX_PACKED_STREAM 0 -#define EFSYS_OPT_TUNNEL 0 +#define EFSYS_OPT_TUNNEL 1 /* ID */ diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c index 1ca123aa17..59e535d716 100644 --- a/drivers/net/sfc/sfc.c +++ b/drivers/net/sfc/sfc.c @@ -274,6 +274,7 @@ sfc_set_drv_limits(struct sfc_adapter *sa) static int sfc_try_start(struct sfc_adapter *sa) { + const efx_nic_cfg_t *encp; int rc; sfc_log_init(sa, "entry"); @@ -291,6 +292,14 @@ sfc_try_start(struct sfc_adapter *sa) if (rc != 0) goto fail_nic_init; + encp = efx_nic_cfg_get(sa->nic); + if (encp->enc_tunnel_encapsulations_supported != 0) { + sfc_log_init(sa, "apply tunnel config"); + rc = efx_tunnel_reconfigure(sa->nic); + if (rc != 0) + goto fail_tunnel_reconfigure; + } + rc = sfc_intr_start(sa); if (rc != 0) goto fail_intr_start; @@ -334,6 +343,7 @@ sfc_try_start(struct sfc_adapter *sa) sfc_intr_stop(sa); fail_intr_start: +fail_tunnel_reconfigure: efx_nic_fini(sa->nic); fail_nic_init: @@ -663,6 +673,16 @@ sfc_attach(struct sfc_adapter *sa) if (rc != 0) goto fail_nic_reset; + /* + * Probed NIC is sufficient for tunnel init. + * Initialize tunnel support to be able to use libefx + * efx_tunnel_config_udp_{add,remove}() in any state and + * efx_tunnel_reconfigure() on start up. + */ + rc = efx_tunnel_init(enp); + if (rc != 0) + goto fail_tunnel_init; + encp = efx_nic_cfg_get(sa->nic); if (sa->dp_tx->features & SFC_DP_TX_FEAT_TSO) { @@ -724,6 +744,9 @@ sfc_attach(struct sfc_adapter *sa) efx_nic_fini(sa->nic); fail_estimate_rsrc_limits: +fail_tunnel_init: + efx_tunnel_fini(sa->nic); + fail_nic_reset: sfc_log_init(sa, "failed %d", rc); @@ -743,6 +766,7 @@ sfc_detach(struct sfc_adapter *sa) sfc_port_detach(sa); sfc_ev_detach(sa); sfc_intr_detach(sa); + efx_tunnel_fini(sa->nic); sa->state = SFC_ADAPTER_UNINITIALIZED; } diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c index 0ac9362528..837fd5555e 100644 --- a/drivers/net/sfc/sfc_ethdev.c +++ b/drivers/net/sfc/sfc_ethdev.c @@ -1225,6 +1225,123 @@ sfc_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id) return 0; } +static efx_tunnel_protocol_t +sfc_tunnel_rte_type_to_efx_udp_proto(enum rte_eth_tunnel_type rte_type) +{ + switch (rte_type) { + case RTE_TUNNEL_TYPE_VXLAN: + return EFX_TUNNEL_PROTOCOL_VXLAN; + case RTE_TUNNEL_TYPE_GENEVE: + return EFX_TUNNEL_PROTOCOL_GENEVE; + default: + return EFX_TUNNEL_NPROTOS; + } +} + +enum sfc_udp_tunnel_op_e { + SFC_UDP_TUNNEL_ADD_PORT, + SFC_UDP_TUNNEL_DEL_PORT, +}; + +static int +sfc_dev_udp_tunnel_op(struct rte_eth_dev *dev, + struct rte_eth_udp_tunnel *tunnel_udp, + enum sfc_udp_tunnel_op_e op) +{ + struct sfc_adapter *sa = dev->data->dev_private; + efx_tunnel_protocol_t tunnel_proto; + int rc; + + sfc_log_init(sa, "%s udp_port=%u prot_type=%u", + (op == SFC_UDP_TUNNEL_ADD_PORT) ? "add" : + (op == SFC_UDP_TUNNEL_DEL_PORT) ? "delete" : "unknown", + tunnel_udp->udp_port, tunnel_udp->prot_type); + + tunnel_proto = + sfc_tunnel_rte_type_to_efx_udp_proto(tunnel_udp->prot_type); + if (tunnel_proto >= EFX_TUNNEL_NPROTOS) { + rc = ENOTSUP; + goto fail_bad_proto; + } + + sfc_adapter_lock(sa); + + switch (op) { + case SFC_UDP_TUNNEL_ADD_PORT: + rc = efx_tunnel_config_udp_add(sa->nic, + tunnel_udp->udp_port, + tunnel_proto); + break; + case SFC_UDP_TUNNEL_DEL_PORT: + rc = efx_tunnel_config_udp_remove(sa->nic, + tunnel_udp->udp_port, + tunnel_proto); + break; + default: + rc = EINVAL; + goto fail_bad_op; + } + + if (rc != 0) + goto fail_op; + + if (sa->state == SFC_ADAPTER_STARTED) { + rc = efx_tunnel_reconfigure(sa->nic); + if (rc == EAGAIN) { + /* + * Configuration is accepted by FW and MC reboot + * is initiated to apply the changes. MC reboot + * will be handled in a usual way (MC reboot + * event on management event queue and adapter + * restart). + */ + rc = 0; + } else if (rc != 0) { + goto fail_reconfigure; + } + } + + sfc_adapter_unlock(sa); + return 0; + +fail_reconfigure: + /* Remove/restore entry since the change makes the trouble */ + switch (op) { + case SFC_UDP_TUNNEL_ADD_PORT: + (void)efx_tunnel_config_udp_remove(sa->nic, + tunnel_udp->udp_port, + tunnel_proto); + break; + case SFC_UDP_TUNNEL_DEL_PORT: + (void)efx_tunnel_config_udp_add(sa->nic, + tunnel_udp->udp_port, + tunnel_proto); + break; + } + +fail_op: +fail_bad_op: + sfc_adapter_unlock(sa); + +fail_bad_proto: + SFC_ASSERT(rc > 0); + return -rc; +} + +static int +sfc_dev_udp_tunnel_port_add(struct rte_eth_dev *dev, + struct rte_eth_udp_tunnel *tunnel_udp) +{ + return sfc_dev_udp_tunnel_op(dev, tunnel_udp, SFC_UDP_TUNNEL_ADD_PORT); +} + +static int +sfc_dev_udp_tunnel_port_del(struct rte_eth_dev *dev, + struct rte_eth_udp_tunnel *tunnel_udp) +{ + return sfc_dev_udp_tunnel_op(dev, tunnel_udp, SFC_UDP_TUNNEL_DEL_PORT); +} + #if EFSYS_OPT_RX_SCALE static int sfc_dev_rss_hash_conf_get(struct rte_eth_dev *dev, @@ -1529,6 +1646,8 @@ static const struct eth_dev_ops sfc_eth_dev_ops = { .flow_ctrl_get = sfc_flow_ctrl_get, .flow_ctrl_set = sfc_flow_ctrl_set, .mac_addr_set = sfc_mac_addr_set, + .udp_tunnel_port_add = sfc_dev_udp_tunnel_port_add, + .udp_tunnel_port_del = sfc_dev_udp_tunnel_port_del, #if EFSYS_OPT_RX_SCALE .reta_update = sfc_dev_rss_reta_update, .reta_query = sfc_dev_rss_reta_query,