+static int udp_tunnel_common_check(struct enic *enic,
+ struct rte_eth_udp_tunnel *tnl)
+{
+ if (tnl->prot_type != RTE_ETH_TUNNEL_TYPE_VXLAN &&
+ tnl->prot_type != RTE_ETH_TUNNEL_TYPE_GENEVE)
+ return -ENOTSUP;
+ if (!enic->overlay_offload) {
+ ENICPMD_LOG(DEBUG, " overlay offload is not supported\n");
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
+static int update_tunnel_port(struct enic *enic, uint16_t port, bool vxlan)
+{
+ uint8_t cfg;
+
+ cfg = vxlan ? OVERLAY_CFG_VXLAN_PORT_UPDATE :
+ OVERLAY_CFG_GENEVE_PORT_UPDATE;
+ if (vnic_dev_overlay_offload_cfg(enic->vdev, cfg, port)) {
+ ENICPMD_LOG(DEBUG, " failed to update tunnel port\n");
+ return -EINVAL;
+ }
+ ENICPMD_LOG(DEBUG, " updated %s port to %u\n",
+ vxlan ? "vxlan" : "geneve", port);
+ if (vxlan)
+ enic->vxlan_port = port;
+ else
+ enic->geneve_port = port;
+ return 0;
+}
+
+static int enicpmd_dev_udp_tunnel_port_add(struct rte_eth_dev *eth_dev,
+ struct rte_eth_udp_tunnel *tnl)
+{
+ struct enic *enic = pmd_priv(eth_dev);
+ uint16_t port;
+ bool vxlan;
+ int ret;
+
+ ENICPMD_FUNC_TRACE();
+ ret = udp_tunnel_common_check(enic, tnl);
+ if (ret)
+ return ret;
+ vxlan = (tnl->prot_type == RTE_ETH_TUNNEL_TYPE_VXLAN);
+ if (vxlan)
+ port = enic->vxlan_port;
+ else
+ port = enic->geneve_port;
+ /*
+ * The NIC has 1 configurable port number per tunnel type.
+ * "Adding" a new port number replaces it.
+ */
+ if (tnl->udp_port == port || tnl->udp_port == 0) {
+ ENICPMD_LOG(DEBUG, " %u is already configured or invalid\n",
+ tnl->udp_port);
+ return -EINVAL;
+ }
+ return update_tunnel_port(enic, tnl->udp_port, vxlan);
+}
+
+static int enicpmd_dev_udp_tunnel_port_del(struct rte_eth_dev *eth_dev,
+ struct rte_eth_udp_tunnel *tnl)
+{
+ struct enic *enic = pmd_priv(eth_dev);
+ uint16_t port;
+ bool vxlan;
+ int ret;
+
+ ENICPMD_FUNC_TRACE();
+ ret = udp_tunnel_common_check(enic, tnl);
+ if (ret)
+ return ret;
+ vxlan = (tnl->prot_type == RTE_ETH_TUNNEL_TYPE_VXLAN);
+ if (vxlan)
+ port = enic->vxlan_port;
+ else
+ port = enic->geneve_port;
+ /*
+ * Clear the previously set port number and restore the
+ * hardware default port number. Some drivers disable VXLAN
+ * offloads when there are no configured port numbers. But
+ * enic does not do that as VXLAN is part of overlay offload,
+ * which is tied to inner RSS and TSO.
+ */
+ if (tnl->udp_port != port) {
+ ENICPMD_LOG(DEBUG, " %u is not a configured tunnel port\n",
+ tnl->udp_port);
+ return -EINVAL;
+ }
+ port = vxlan ? RTE_VXLAN_DEFAULT_PORT : RTE_GENEVE_DEFAULT_PORT;
+ return update_tunnel_port(enic, port, vxlan);
+}
+
+static int enicpmd_dev_fw_version_get(struct rte_eth_dev *eth_dev,
+ char *fw_version, size_t fw_size)
+{
+ struct vnic_devcmd_fw_info *info;
+ struct enic *enic;
+ int ret;
+
+ ENICPMD_FUNC_TRACE();
+
+ enic = pmd_priv(eth_dev);
+ ret = vnic_dev_fw_info(enic->vdev, &info);
+ if (ret)
+ return ret;
+ ret = snprintf(fw_version, fw_size, "%s %s",
+ info->fw_version, info->fw_build);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret += 1; /* add the size of '\0' */
+ if (fw_size < (size_t)ret)
+ return ret;
+ else
+ return 0;
+}
+