From: Jie Liu <[email protected]>

This patch enables the configuration of custom UDP port numbers for
tunneling protocols in the SXE2 PMD.

The change includes:
- Adding a new entry in the tunnel port lookup table.
- Updating the hardware profile to recognize
  the custom UDP port as a tunnel type.
- Enabling inner header parsing for packets arriving on these ports.

This allows the Switch module to correctly apply recipes based on
inner packet fields (e.g., inner MAC or IP).

Signed-off-by: Jie Liu <[email protected]>
---
 drivers/net/sxe2/sxe2_cmd_chnl.c           |  96 ++++++++++
 drivers/net/sxe2/sxe2_cmd_chnl.h           |  17 ++
 drivers/net/sxe2/sxe2_drv_cmd.h            |  16 ++
 drivers/net/sxe2/sxe2_ethdev.c             | 206 ++++++++++++++++++++-
 drivers/net/sxe2/sxe2_ethdev.h             |  12 ++
 drivers/net/sxe2/sxe2_flow.c               |  54 ++++++
 drivers/net/sxe2/sxe2_flow.h               |   3 +-
 drivers/net/sxe2/sxe2_flow_define.h        |   1 +
 drivers/net/sxe2/sxe2_flow_parse_pattern.c | 113 +++++++++++
 drivers/net/sxe2/sxe2_flow_parse_pattern.h |   6 +
 drivers/net/sxe2/sxe2_txrx_poll.c          |  46 ++++-
 11 files changed, 566 insertions(+), 4 deletions(-)

diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 6e2dd139a5..926eaee062 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -1455,6 +1455,102 @@ int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter 
*adapter,
        return ret;
 }
 
+int32_t sxe2_drv_udp_tunnel_add(struct sxe2_adapter *adapter,
+                           enum sxe2_udp_tunnel_protocol tunnel_proto,
+                           uint16_t udp_port)
+{
+       struct sxe2_common_device *cdev = adapter->cdev;
+       struct sxe2_drv_udp_tunnel_req req = {};
+       struct sxe2_drv_cmd_params cmd = {};
+       int32_t ret = -1;
+
+       req.type = tunnel_proto;
+       req.port = udp_port;
+       sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_UDPTUNNEL_ADD,
+                                &req, sizeof(req),
+                                NULL, 0);
+       ret = sxe2_drv_cmd_exec(cdev, &cmd);
+       if (ret)
+               PMD_LOG_ERR(DRV, "Failed to add udp proto %d port %d, ret=%d",
+                               tunnel_proto, udp_port, ret);
+
+       return ret;
+}
+
+int32_t sxe2_drv_udp_tunnel_del(struct sxe2_adapter *adapter,
+                           enum sxe2_udp_tunnel_protocol tunnel_proto,
+                           uint16_t udp_port)
+{
+       struct sxe2_common_device *cdev = adapter->cdev;
+       struct sxe2_drv_udp_tunnel_req req = {};
+       struct sxe2_drv_cmd_params cmd = {};
+       int32_t ret = -1;
+
+       req.type = tunnel_proto;
+       req.port = udp_port;
+       sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_UDPTUNNEL_DEL,
+                                &req, sizeof(req),
+                                NULL, 0);
+       ret = sxe2_drv_cmd_exec(cdev, &cmd);
+       if (ret)
+               PMD_LOG_ERR(DRV, "Failed to del udp proto %d port %d, ret=%d",
+                               tunnel_proto, udp_port, ret);
+
+       return ret;
+}
+
+int32_t sxe2_drv_get_udp_tunnel_port(struct sxe2_adapter *adapter,
+                                enum sxe2_flow_udp_tunnel_protocol proto,
+                                uint16_t *port)
+{
+       int32_t ret = 0;
+       static const uint16_t 
flow_proto_to_udp_tunnel_proto[SXE2_FLOW_UDP_TUNNEL_MAX] = {
+               [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN] = 
SXE2_UDP_TUNNEL_PROTOCOL_VXLAN,
+               [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN_GPE] = 
SXE2_UDP_TUNNEL_PROTOCOL_VXLAN_GPE,
+               [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GENEVE] = 
SXE2_UDP_TUNNEL_PROTOCOL_GENEVE,
+               [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GTP_U] = 
SXE2_UDP_TUNNEL_PROTOCOL_GTP_U,
+               [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_NVGRE] = 
SXE2_UDP_TUNNEL_PROTOCOL_NVGRE,
+       };
+       struct sxe2_udp_tunnel_cfg tunnel_config = {};
+
+       tunnel_config.protocol = flow_proto_to_udp_tunnel_proto[proto];
+       ret = sxe2_drv_udp_tunnel_get(adapter, &tunnel_config);
+       if (ret) {
+               PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get udp tunnel port, 
ret=%d", ret);
+               goto l_end;
+       }
+
+       *port = tunnel_config.fw_port;
+l_end:
+       return ret;
+}
+
+int32_t sxe2_drv_udp_tunnel_get(struct sxe2_adapter *adapter,
+                           struct sxe2_udp_tunnel_cfg *tunnel_config)
+{
+       struct sxe2_common_device *cdev = adapter->cdev;
+       struct sxe2_drv_udp_tunnel_req req = {};
+       struct sxe2_drv_udp_tunnel_resp resp = {};
+       struct sxe2_drv_cmd_params cmd = {};
+       int32_t ret = -1;
+
+       req.type = tunnel_config->protocol;
+       sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_UDPTUNNEL_GET,
+                                &req, sizeof(req),
+                                &resp, sizeof(resp));
+       ret = sxe2_drv_cmd_exec(cdev, &cmd);
+       if (ret)
+               PMD_LOG_ERR(DRV, "Failed to get udp proto %d port, ret=%d", 
req.type, ret);
+
+       tunnel_config->fw_port   = resp.port;
+       tunnel_config->fw_status = resp.enable;
+       tunnel_config->fw_dst_en = resp.dst;
+       tunnel_config->fw_src_en = resp.src;
+       tunnel_config->fw_used   = resp.fw_used;
+
+       return ret;
+}
+
 int32_t sxe2_drv_queue_info_get_update(struct sxe2_adapter *adapter, struct 
eth_queue_stats *qstats)
 {
        struct sxe2_drv_cmd_params param = {0};
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index d505f93dc1..43f28c8304 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -67,6 +67,23 @@ int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter 
*adapter,
 
 int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
 
+int32_t sxe2_drv_udp_tunnel_add(struct sxe2_adapter *adapter,
+                           enum sxe2_udp_tunnel_protocol tunnel_proto,
+                           uint16_t udp_port);
+
+int32_t sxe2_drv_udp_tunnel_del(struct sxe2_adapter *adapter,
+                           enum sxe2_udp_tunnel_protocol tunnel_proto,
+                           uint16_t udp_port);
+
+int32_t sxe2_drv_udp_tunnel_get(struct sxe2_adapter *adapter,
+                           struct sxe2_udp_tunnel_cfg *tunnel_config);
+
+int32_t sxe2_drv_get_udp_tunnel_port(struct sxe2_adapter *adapter,
+                                enum sxe2_flow_udp_tunnel_protocol proto,
+                                uint16_t *port);
+
+int32_t sxe2_drv_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi 
*vsi);
+
 int32_t sxe2_drv_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi 
*vsi);
 
 int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 48c012367c..5b5ddf9960 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -261,6 +261,22 @@ struct sxe2_drv_vsi_info_get_resp {
        struct sxe2_drv_msix_caps used_msix;
 };
 
+struct sxe2_drv_udp_tunnel_req {
+       uint8_t type;
+       uint8_t rsv;
+       uint16_t port;
+};
+
+struct sxe2_drv_udp_tunnel_resp {
+       uint8_t type;
+       uint8_t enable;
+       uint8_t dst;
+       uint8_t src;
+       uint16_t port;
+       uint8_t fw_used;
+       uint8_t rsv;
+};
+
 struct sxe2_drv_link_info_resp {
        uint32_t speed;
        uint8_t status;
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 317101fb60..14c8f6c16d 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -40,10 +40,11 @@
 #include "sxe2_ioctl_chnl_func.h"
 #include "sxe2_ethdev_repr.h"
 #include "sxe2vf_regs.h"
+#include "sxe2_switchdev.h"
 
 #define SXE2_PCI_VENDOR_ID_1    0x1ff2
 #define SXE2_PCI_DEVICE_ID_PF_1 0x10b1
-#define SXE2_PCI_DEVICE_ID_VF_1 0x10b2
+#define SXE2_PCI_DEVICE_ID_VF_1 0x10b
 
 #define SXE2_PCI_VENDOR_ID_2    0x1d94
 #define SXE2_PCI_DEVICE_ID_PF_2 0x1260
@@ -115,6 +116,11 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev);
 static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev, struct 
rte_eth_dev_info *dev_info);
 static const uint32_t *sxe2_buffer_split_supported_hdr_ptypes_get(struct 
rte_eth_dev *dev
                                __rte_unused, size_t *no_of_elements 
__rte_unused);
+static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev,
+                                       struct rte_eth_udp_tunnel *tunnel_udp);
+static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev,
+                                       struct rte_eth_udp_tunnel *tunnel_udp);
+
 
 static const struct eth_dev_ops sxe2_eth_dev_ops = {
        .dev_configure              = sxe2_dev_configure,
@@ -162,6 +168,9 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
        .rss_hash_update            = sxe2_dev_rss_hash_update,
        .rss_hash_conf_get          = sxe2_dev_rss_hash_conf_get,
 
+       .udp_tunnel_port_add        = sxe2_udp_tunnel_port_add,
+       .udp_tunnel_port_del        = sxe2_udp_tunnel_port_del,
+
        .flow_ops_get               = sxe2_flow_ops_get,
        .tm_ops_get                 = sxe2_tm_ops_get,
 
@@ -226,6 +235,12 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
        struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
        PMD_INIT_FUNC_TRACE();
 
+       ret = sxe2_flow_init_udp_tunnel_port(dev);
+       if (ret) {
+               PMD_LOG_ERR(DRV, "Failed to init udp tunnel port, ret: %d.", 
ret);
+               goto l_end;
+       }
+
        ret = sxe2_queues_init(dev);
        if (ret) {
                PMD_LOG_ERR(INIT, "Failed to init queues.");
@@ -271,6 +286,188 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
        return ret;
 }
 
+static enum sxe2_udp_tunnel_protocol
+sxe2_udp_tunnel_type_rte_to_sxe2(enum rte_eth_tunnel_type rte_type)
+{
+       static enum sxe2_udp_tunnel_protocol 
sxe2_udp_proto_map[RTE_ETH_TUNNEL_TYPE_MAX] = {
+               [RTE_ETH_TUNNEL_TYPE_NONE] = SXE2_UDP_TUNNEL_MAX,
+               [RTE_ETH_TUNNEL_TYPE_VXLAN] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN,
+               [RTE_ETH_TUNNEL_TYPE_GENEVE] = SXE2_UDP_TUNNEL_PROTOCOL_GENEVE,
+               [RTE_ETH_TUNNEL_TYPE_TEREDO] = SXE2_UDP_TUNNEL_PROTOCOL_TEREDO,
+               [RTE_ETH_TUNNEL_TYPE_NVGRE] = SXE2_UDP_TUNNEL_PROTOCOL_NVGRE,
+               [RTE_ETH_TUNNEL_TYPE_IP_IN_GRE] = SXE2_UDP_TUNNEL_MAX,
+               [RTE_ETH_L2_TUNNEL_TYPE_E_TAG] = SXE2_UDP_TUNNEL_MAX,
+               [RTE_ETH_TUNNEL_TYPE_VXLAN_GPE] = 
SXE2_UDP_TUNNEL_PROTOCOL_VXLAN_GPE,
+               [RTE_ETH_TUNNEL_TYPE_ECPRI]  = SXE2_UDP_TUNNEL_PROTOCOL_ECPRI
+       };
+
+       if (rte_type >= RTE_ETH_TUNNEL_TYPE_MAX) {
+               PMD_LOG_ERR(DRV, "Invalid rte_eth_tunnel_type %d!", rte_type);
+               rte_type = RTE_ETH_TUNNEL_TYPE_NONE;
+       }
+
+       return sxe2_udp_proto_map[rte_type];
+}
+
+int32_t sxe2_udp_tunnel_port_add_common(struct sxe2_adapter *ad,
+                                   enum sxe2_udp_tunnel_protocol tunnel_proto,
+                                   uint16_t udp_port)
+{
+       struct sxe2_udp_tunnel_cfg *tunnel_config;
+       int32_t ret = -1;
+
+       rte_spinlock_lock(&ad->udp_tunnel_ctx.lock);
+
+       tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto];
+
+       if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE) {
+               if (udp_port == tunnel_config->dev_port &&
+                       tunnel_config->dev_ref_cnt < 0xFFFFU) {
+                       tunnel_config->dev_ref_cnt++;
+                       ret = 0;
+                       goto l_unlock_end;
+               } else {
+                       PMD_LOG_ERR(DRV, "Adding multiple ports to the same 
protocol "
+                                   "is not supported!");
+                       ret = -EINVAL;
+                       goto l_unlock_end;
+               }
+       } else {
+               ret = sxe2_drv_udp_tunnel_add(ad, tunnel_proto, udp_port);
+               if (ret != 0)
+                       goto l_unlock_end;
+
+               tunnel_config->protocol = tunnel_proto;
+               tunnel_config->dev_port = udp_port;
+               tunnel_config->dev_status  = SXE2_UDP_TUNNEL_ENABLE;
+               tunnel_config->dev_ref_cnt++;
+       }
+
+l_unlock_end:
+       rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock);
+       return ret;
+}
+
+int32_t sxe2_udp_tunnel_port_del_common(struct sxe2_adapter *ad,
+                                   enum sxe2_udp_tunnel_protocol tunnel_proto,
+                                   uint16_t udp_port)
+{
+       struct sxe2_udp_tunnel_cfg *tunnel_config;
+       int32_t ret = -1;
+
+       rte_spinlock_lock(&ad->udp_tunnel_ctx.lock);
+       tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto];
+
+       if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE &&
+               udp_port == tunnel_config->dev_port) {
+               if (tunnel_config->dev_ref_cnt > 1) {
+                       tunnel_config->dev_ref_cnt--;
+                       ret = 0;
+                       goto l_unlock_end;
+               } else {
+                       ret = sxe2_drv_udp_tunnel_del(ad, tunnel_proto, 
udp_port);
+                       if (ret != 0)
+                               goto l_unlock_end;
+
+                       tunnel_config->dev_status  = SXE2_UDP_TUNNEL_DISABLE;
+                       tunnel_config->dev_ref_cnt = 0;
+               }
+               goto l_unlock_end;
+       }
+
+       ret = -EINVAL;
+
+l_unlock_end:
+       rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock);
+       return ret;
+}
+
+int32_t sxe2_udp_tunnel_port_get_common(struct sxe2_adapter *ad,
+                                   struct sxe2_udp_tunnel_cfg *tunnel_config)
+{
+       return sxe2_drv_udp_tunnel_get(ad, tunnel_config);
+}
+
+static int32_t sxe2_udp_tunnel_port_clear(struct rte_eth_dev *dev)
+{
+       struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+       struct sxe2_udp_tunnel_cfg *tunnel_config;
+       int32_t ret = 0;
+       uint16_t tunnel_proto = 0;
+
+       rte_spinlock_lock(&ad->udp_tunnel_ctx.lock);
+
+       for (tunnel_proto = 0; tunnel_proto < SXE2_UDP_TUNNEL_MAX; 
tunnel_proto++) {
+               tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto];
+               if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE) {
+                       ret = sxe2_drv_udp_tunnel_del(ad, 
tunnel_config->protocol,
+                                       tunnel_config->dev_port);
+                       if (ret) {
+                               PMD_LOG_ERR(DRV, "Failed to delete udp tunnel 
port %d, proto %d",
+                                           tunnel_config->dev_port, 
tunnel_config->protocol);
+                               goto l_unlock_end;
+                       }
+
+                       tunnel_config->dev_status  = SXE2_UDP_TUNNEL_DISABLE;
+                       tunnel_config->dev_ref_cnt = 0;
+               }
+       }
+l_unlock_end:
+       rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock);
+       return ret;
+}
+
+static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev,
+                       struct rte_eth_udp_tunnel *tunnel_udp)
+{
+       int32_t ret = 0;
+       enum sxe2_udp_tunnel_protocol tunnel_proto;
+       struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+       if (tunnel_udp->udp_port == 0) {
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       tunnel_proto = sxe2_udp_tunnel_type_rte_to_sxe2(tunnel_udp->prot_type);
+       if (tunnel_proto >= SXE2_UDP_TUNNEL_MAX) {
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       ret = sxe2_udp_tunnel_port_add_common(ad, tunnel_proto, 
tunnel_udp->udp_port);
+       if (ret) {
+               PMD_LOG_ERR(DRV, "Add tunnel port failed, ret = %d", ret);
+               goto l_end;
+       }
+
+l_end:
+       return ret;
+}
+
+static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev,
+                       struct rte_eth_udp_tunnel *tunnel_udp)
+{
+       int32_t ret = 0;
+       enum sxe2_udp_tunnel_protocol tunnel_proto;
+       struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+       tunnel_proto = sxe2_udp_tunnel_type_rte_to_sxe2(tunnel_udp->prot_type);
+       if (tunnel_proto >= SXE2_UDP_TUNNEL_MAX) {
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       ret = sxe2_udp_tunnel_port_del_common(ad, tunnel_proto, 
tunnel_udp->udp_port);
+       if (ret) {
+               PMD_LOG_ERR(DRV, "Delete tunnel port failed, ret = %d", ret);
+               goto l_end;
+       }
+
+l_end:
+       return ret;
+}
+
 static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
                        struct rte_eth_dev_info *dev_info)
 {
@@ -1300,15 +1497,20 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
        (void)sxe2_dev_stop(dev);
        (void)sxe2_queues_release(dev);
        sxe2_mp_uninit(dev);
-       (void)sxe2_rss_disable(dev);
        (void)sxe2_sched_uinit(dev);
+       (void)sxe2_rss_disable(dev);
+       (void)sxe2_flow_uninit(dev);
+       (void)sxe2_udp_tunnel_port_clear(dev);
        sxe2_vsi_uninit(dev);
        sxe2_security_uinit(dev);
        sxe2_intr_uninit(dev);
        (void)sxe2_switchdev_uninit(dev);
        sxe2_sw_uninit(dev);
+       (void)sxe2_switchdev_uninit(dev);
+       sxe2_dev_pci_map_uinit(dev);
        sxe2_eth_uinit(dev);
        sxe2_dev_pci_map_uinit(dev);
+       sxe2_free_repr_info(dev);
 
 l_end:
        return 0;
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 6397a2e5c6..d6c6a152e7 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -318,6 +318,7 @@ struct sxe2_adapter {
        struct sxe2_sched_hw_cap      sched_ctxt;
        struct sxe2_tm_context        tm_ctxt;
        struct sxe2_devargs           devargs;
+       struct sxe2_udp_tunnel_ctx    udp_tunnel_ctx;
        struct sxe2_security_ctx      security_ctx;
        struct sxe2_repr_context      repr_ctxt;
        struct sxe2_switchdev_info    switchdev_info;
@@ -373,6 +374,17 @@ void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, 
uint32_t res_type);
 
 int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev);
 
+void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type);
+
+int32_t sxe2_udp_tunnel_port_get_common(struct sxe2_adapter *ad,
+               struct sxe2_udp_tunnel_cfg *tunnel_config);
+
+int32_t sxe2_udp_tunnel_port_del_common(struct sxe2_adapter *ad,
+               enum sxe2_udp_tunnel_protocol tunnel_proto, uint16_t udp_port);
+
+int32_t sxe2_udp_tunnel_port_add_common(struct sxe2_adapter *ad,
+               enum sxe2_udp_tunnel_protocol tunnel_proto, uint16_t udp_port);
+
 void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev);
 
 void sxe2_eth_uinit(struct rte_eth_dev *dev);
diff --git a/drivers/net/sxe2/sxe2_flow.c b/drivers/net/sxe2/sxe2_flow.c
index 6999cb0725..63cfc36968 100644
--- a/drivers/net/sxe2/sxe2_flow.c
+++ b/drivers/net/sxe2/sxe2_flow.c
@@ -523,6 +523,51 @@ static int32_t sxe2_flow_adjust_action(struct rte_eth_dev 
*dev __rte_unused,
        return ret;
 }
 
+int32_t sxe2_flow_init_udp_tunnel_port(struct rte_eth_dev *dev)
+{
+       struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+       int32_t ret = 0;
+       uint16_t i = 0;
+       uint16_t *flow_udp_tunnel_port = NULL;
+
+       memset(adapter->flow_ctxt.tunnel_port_list, 0,
+              sizeof(adapter->flow_ctxt.tunnel_port_list));
+
+       flow_udp_tunnel_port = adapter->flow_ctxt.tunnel_port_list;
+       for (i = 0; i < SXE2_FLOW_UDP_TUNNEL_MAX; i++) {
+               if (flow_udp_tunnel_port[i] == 0) {
+                       ret = sxe2_drv_get_udp_tunnel_port(adapter, i,
+                                                          
&flow_udp_tunnel_port[i]);
+                       if (ret != 0) {
+                               PMD_LOG_ERR(DRV, "Failed to get udp tunnel 
port, proto: %d,"
+                                           "ret: %d", i, ret);
+                               goto l_end;
+                       }
+               }
+       }
+
+l_end:
+       return ret;
+}
+
+static int32_t sxe2_flowlist_add_tunnel_port(struct rte_eth_dev *dev,
+                       struct rte_flow *flow_list,
+                       struct rte_flow_error *error)
+{
+       struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+       struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+       enum sxe2_flow_tunnel_type tunnel_type = flow->meta.tunnel_type;
+       DECLARE_BITMAP(flow_type, SXE2_EXPANSION_MAX);
+       sxe2_bitmap_zero(flow_type, SXE2_EXPANSION_MAX);
+       sxe2_bitmap_copy(flow_type, flow->flow_type, SXE2_EXPANSION_MAX);
+       int32_t ret = 0;
+
+       if (flow->engine_type == SXE2_FLOW_ENGINE_FNAV)
+               return sxe2_flow_add_tunnel_port(dev, error, flow, flow_type, 
tunnel_type);
+
+       return ret;
+}
+
 static int32_t sxe2_flow_check_item_empty(uint8_t *item, uint16_t size)
 {
        uint16_t i = 0;
@@ -679,6 +724,10 @@ static int32_t sxe2_flow_post_proc(struct rte_eth_dev *dev,
 {
        int32_t ret = 0;
 
+       ret = sxe2_flowlist_add_tunnel_port(dev, flow_list, error);
+       if (ret)
+               goto l_end;
+
        ret = sxe2_flowlist_add_proto_type(dev, flow_list, error);
        if (ret)
                goto l_end;
@@ -1308,6 +1357,11 @@ int32_t sxe2_flow_init(struct rte_eth_dev *dev)
 
        adapter->flow_ctxt.fnav_inited = 1;
        rte_spinlock_init(&adapter->flow_ctxt.flow_list_lock);
+
+       ret = sxe2_flow_init_udp_tunnel_port(dev);
+       if (ret)
+               PMD_LOG_ERR(DRV, "Failed to init udp tunnel port, ret: %d.", 
ret);
+
        return ret;
 }
 
diff --git a/drivers/net/sxe2/sxe2_flow.h b/drivers/net/sxe2/sxe2_flow.h
index 9970fddcf0..daaeedd4dc 100644
--- a/drivers/net/sxe2/sxe2_flow.h
+++ b/drivers/net/sxe2/sxe2_flow.h
@@ -8,7 +8,6 @@
 #include "sxe2_osal.h"
 #include "sxe2_common.h"
 
-
 int32_t sxe2_flow_ops_get(struct rte_eth_dev *dev, const struct rte_flow_ops 
**ops);
 
 int32_t sxe2_flow_init(struct rte_eth_dev *dev);
@@ -26,4 +25,6 @@ int32_t sxe2_flow_query_mgr(struct sxe2_adapter *adapter,
                        struct sxe2_flow *flow,
                        struct sxe2_fnav_cid_mgr **mgr_ptr,
                        struct rte_flow_error *error);
+
+int32_t sxe2_flow_init_udp_tunnel_port(struct rte_eth_dev *dev);
 #endif /* __SXE2_FLOW_H__ */
diff --git a/drivers/net/sxe2/sxe2_flow_define.h 
b/drivers/net/sxe2/sxe2_flow_define.h
index d2f6000efa..263a573f04 100644
--- a/drivers/net/sxe2/sxe2_flow_define.h
+++ b/drivers/net/sxe2/sxe2_flow_define.h
@@ -119,6 +119,7 @@ struct sxe2_flow_context {
        struct rte_flow_list_t rte_flow_list;
        rte_spinlock_t flow_list_lock;
        struct sxe2_fnav_count_resource hw_res;
+       uint16_t tunnel_port_list[SXE2_FLOW_UDP_TUNNEL_MAX];
        uint32_t fnav_inited;
 };
 #define SXE2_INVALID_RSS_ATTR  \
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.c 
b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
index 189abb1a33..f5bf8922c6 100644
--- a/drivers/net/sxe2/sxe2_flow_parse_pattern.c
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
@@ -1637,6 +1637,119 @@ static int32_t sxe2_flow_parse_pattern_vxlan_gpe(const 
struct rte_flow_item *ite
        return ret;
 }
 
+static int32_t sxe2_flow_parse_pattern_ipip(struct sxe2_flow *flow, 
BITMAP_TYPE *flow_type)
+{
+       sxe2_set_bit(SXE2_EXPANSION_IPIP, flow_type);
+       if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4, flow_type)) {
+               sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, 
flow->pattern_outer.map_spec);
+               if (sxe2_test_bit(SXE2_EXPANSION_IPV4, flow_type))
+                       flow->pattern_outer.item_spec.ipv4.protocol = 
SXE2_FLOW_IP_PROTOCOL_IPV4;
+               if (sxe2_test_bit(SXE2_EXPANSION_IPV6, flow_type))
+                       flow->pattern_outer.item_spec.ipv4.protocol = 
SXE2_FLOW_IP_PROTOCOL_IPV6;
+       }
+       if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6, flow_type)) {
+               sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, 
flow->pattern_outer.map_spec);
+               if (sxe2_test_bit(SXE2_EXPANSION_ETH, flow_type)) {
+                       flow->pattern_outer.item_spec.ipv6.nexthdr = 
SXE2_FLOW_IP_PROTOCOL_ETH;
+               } else {
+                       if (sxe2_test_bit(SXE2_EXPANSION_IPV4, flow_type))
+                               flow->pattern_outer.item_spec.ipv6.nexthdr =
+                                       SXE2_FLOW_IP_PROTOCOL_IPV4;
+                       if (sxe2_test_bit(SXE2_EXPANSION_IPV6, flow_type))
+                               flow->pattern_outer.item_spec.ipv6.nexthdr =
+                                       SXE2_FLOW_IP_PROTOCOL_IPV6;
+               }
+       }
+       return 0;
+}
+
+static int32_t sxe2_flow_add_udp_tunnel_port(struct sxe2_adapter *adapter,
+                                        enum sxe2_flow_udp_tunnel_protocol 
proto,
+                                        struct sxe2_flow *flow,
+                                        BITMAP_TYPE *flow_type)
+{
+       int32_t ret = 0;
+       uint16_t tun_port;
+
+       tun_port = adapter->flow_ctxt.tunnel_port_list[proto];
+       if (tun_port == 0xffff || tun_port == 0) {
+               ret = -EINVAL;
+               PMD_LOG_ERR(DRV, "UDP tunnel port not initialized, proto: %d", 
proto);
+               goto l_end;
+       }
+       if (!sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow_type)) {
+               ret = -EINVAL;
+               PMD_LOG_ERR(DRV, "UDP must be over tunnel");
+               goto l_end;
+       }
+       sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, 
flow->pattern_outer.map_spec);
+       flow->pattern_outer.item_spec.udp.dest = rte_cpu_to_be_16(tun_port);
+l_end:
+       return ret;
+}
+
+int32_t sxe2_flow_add_tunnel_port(struct rte_eth_dev *dev,
+                       struct rte_flow_error *error,
+                       struct sxe2_flow *flow, BITMAP_TYPE *flow_type,
+                       enum sxe2_flow_tunnel_type tunnel_type)
+{
+       int32_t ret = 0;
+       enum sxe2_flow_udp_tunnel_protocol proto = SXE2_FLOW_UDP_TUNNEL_MAX;
+       struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+       struct sxe2_flow_pattern *pattern = &flow->pattern_outer;
+       switch (tunnel_type) {
+       case SXE2_FLOW_TUNNEL_TYPE_VXLAN:
+               if (sxe2_test_bit(SXE2_EXPANSION_ETH, flow_type)) {
+                       proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN;
+               } else if (sxe2_test_bit(SXE2_EXPANSION_IPV4, flow_type) ||
+                       sxe2_test_bit(SXE2_EXPANSION_IPV6, flow_type)) {
+                       proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN_GPE;
+               }
+               break;
+       case SXE2_FLOW_TUNNEL_TYPE_GTPU:
+               proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GTP_U;
+               break;
+       case SXE2_FLOW_TUNNEL_TYPE_GENEVE:
+               proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GENEVE;
+               break;
+       case SXE2_FLOW_TUNNEL_TYPE_GRE:
+               if (sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow_type)) {
+                       proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_NVGRE;
+               } else {
+                       if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4, 
flow_type)) {
+                               pattern->item_spec.ipv4.protocol = 
SXE2_FLOW_IP_PROTOCOL_GRE;
+                               sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, 
pattern->map_spec);
+                       }
+                       if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6, 
flow_type)) {
+                               pattern->item_spec.ipv6.nexthdr = 
SXE2_FLOW_IP_PROTOCOL_GRE;
+                               sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, 
pattern->map_spec);
+                       }
+               }
+               break;
+       case SXE2_FLOW_TUNNEL_TYPE_IPIP:
+               ret = sxe2_flow_parse_pattern_ipip(flow, flow_type);
+               break;
+       default:
+               break;
+       }
+       if (proto != SXE2_FLOW_UDP_TUNNEL_MAX) {
+               ret = sxe2_flow_add_udp_tunnel_port(adapter, proto, flow, 
flow_type);
+               if (ret != 0) {
+                       rte_flow_error_set(error, EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ITEM,
+                                       NULL, "Failed to add udp port for 
tunnel.");
+                       PMD_LOG_ERR(DRV, "Failed to add udp port for tunnel, 
ret %d.", ret);
+                       goto l_end;
+               }
+       }
+       if (tunnel_type != SXE2_FLOW_TUNNEL_TYPE_NONE) {
+               if (!sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow_type))
+                       sxe2_set_bit(SXE2_FLOW_HDR_IPV_OTHER, pattern->hdrs);
+       }
+l_end:
+       return ret;
+}
+
 struct sxe2_flow_parse_pattern_ops sxe2_flow_parse_pattern_list[] = {
        [SXE2_EXPANSION_OUTER_ETH] = {
                .is_inner = false,
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.h 
b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
index 69d83a6ea6..8442c35cae 100644
--- a/drivers/net/sxe2/sxe2_flow_parse_pattern.h
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
@@ -37,4 +37,10 @@ int32_t sxe2_flow_parse_pattern(struct rte_eth_dev *dev,
                            struct rte_flow_error *error,
                            struct sxe2_flow *flow);
 
+int32_t sxe2_flow_add_tunnel_port(struct rte_eth_dev *dev,
+                             struct rte_flow_error *error,
+                             struct sxe2_flow *flow,
+                             BITMAP_TYPE *flow_type,
+                             enum sxe2_flow_tunnel_type tunnel_type);
+
 #endif /* SXE2_FLOW_PARSE_PATTERN_H_ */
diff --git a/drivers/net/sxe2/sxe2_txrx_poll.c 
b/drivers/net/sxe2/sxe2_txrx_poll.c
index f3c4fa0d91..746f9cc2d5 100644
--- a/drivers/net/sxe2/sxe2_txrx_poll.c
+++ b/drivers/net/sxe2/sxe2_txrx_poll.c
@@ -234,6 +234,44 @@ sxe2_tx_pkt_data_desc_count(struct rte_mbuf *tx_pkt)
        return count;
 }
 
+static __rte_always_inline void sxe2_tx_desc_tunneling_params_fill(uint64_t 
offloads,
+                                       union sxe2_tx_offload_info ol_info,
+                                       uint32_t *desc_tunneling_params)
+{
+       if (offloads & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
+               *desc_tunneling_params |= SXE2_TX_CTXT_DESC_EIPT_IPV4;
+       else if (offloads & RTE_MBUF_F_TX_OUTER_IPV4)
+               *desc_tunneling_params |= SXE2_TX_CTXT_DESC_EIPT_IPV4_NO_CSUM;
+       else if (offloads & RTE_MBUF_F_TX_OUTER_IPV6)
+               *desc_tunneling_params |= SXE2_TX_CTXT_DESC_EIPT_IPV6;
+
+       *desc_tunneling_params |=
+                       SXE2_TX_CTXT_DESC_EIPLEN_VAL(ol_info.outer_l3_len);
+       switch (offloads & RTE_MBUF_F_TX_TUNNEL_MASK) {
+       case RTE_MBUF_F_TX_TUNNEL_IPIP:
+               break;
+       case RTE_MBUF_F_TX_TUNNEL_VXLAN:
+       case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+       case RTE_MBUF_F_TX_TUNNEL_GTP:
+       case RTE_MBUF_F_TX_TUNNEL_GENEVE:
+               *desc_tunneling_params |= SXE2_TX_CTXT_DESC_UDP_TUNNE;
+               break;
+       case RTE_MBUF_F_TX_TUNNEL_GRE:
+               *desc_tunneling_params |= SXE2_TX_CTXT_DESC_GRE_TUNNE;
+               break;
+       default:
+               PMD_LOG_ERR(TX, "Tunnel type [0x%" PRIx64 "] is not supported.",
+                           (uint64_t)(offloads & RTE_MBUF_F_TX_TUNNEL_MASK));
+               return;
+       }
+       *desc_tunneling_params |= SXE2_TX_CTXT_DESC_NATLEN_VAL(ol_info.l2_len);
+       if (!(*desc_tunneling_params & SXE2_TX_CTXT_DESC_EIPT_NONE) &&
+                       (*desc_tunneling_params & SXE2_TX_CTXT_DESC_UDP_TUNNE) 
&&
+                       (offloads & RTE_MBUF_F_TX_OUTER_UDP_CKSUM)) {
+               *desc_tunneling_params |= SXE2_TX_CTXT_DESC_L4T_CS_MASK;
+       }
+}
+
 static __rte_always_inline void
 sxe2_tx_desc_checksum_fill(uint64_t offloads, uint32_t *desc_cmd, uint32_t 
*desc_offset,
                union sxe2_tx_offload_info ol_info)
@@ -414,7 +452,13 @@ uint16_t sxe2_tx_pkts(void *tx_queue, struct rte_mbuf 
**tx_pkts, uint16_t nb_pkt
                        }
                }
 
-               desc_offset |= SXE2_TX_DATA_DESC_MACLEN_VAL(ol_info.l2_len);
+               if ((offloads & RTE_MBUF_F_TX_TUNNEL_MASK) && ctxt_desc_num) {
+                       desc_offset |= 
SXE2_TX_DATA_DESC_MACLEN_VAL(ol_info.outer_l2_len);
+                       sxe2_tx_desc_tunneling_params_fill(offloads, ol_info,
+                                               &desc_tunneling_params);
+               } else {
+                       desc_offset |= 
SXE2_TX_DATA_DESC_MACLEN_VAL(ol_info.l2_len);
+               }
 
                if (offloads & SXE2_TX_OFFLOAD_CKSUM_MASK) {
                        sxe2_tx_desc_checksum_fill(offloads, &desc_cmd,
-- 
2.47.3

Reply via email to