From 85bcf43f3c971870636e3dd2457351948c195731 Mon Sep 17 00:00:00 2001 From: Vivek Sharma Date: Sun, 30 Jun 2019 09:04:41 +0530 Subject: [PATCH] net/octeontx2: support VLAN filters Support setting up VLAN filters so as to allow tagged packet's reception after VLAN HW Filter offload is enabled. Signed-off-by: Vivek Sharma Acked-by: Jerin Jacob --- doc/guides/nics/features/octeontx2.ini | 1 + doc/guides/nics/features/octeontx2_vec.ini | 1 + doc/guides/nics/features/octeontx2_vf.ini | 1 + doc/guides/nics/octeontx2.rst | 2 +- drivers/net/octeontx2/otx2_ethdev.c | 2 + drivers/net/octeontx2/otx2_ethdev.h | 4 + drivers/net/octeontx2/otx2_vlan.c | 149 ++++++++++++++++++++- 7 files changed, 157 insertions(+), 3 deletions(-) diff --git a/doc/guides/nics/features/octeontx2.ini b/doc/guides/nics/features/octeontx2.ini index ac4712b0c1..37b8029995 100644 --- a/doc/guides/nics/features/octeontx2.ini +++ b/doc/guides/nics/features/octeontx2.ini @@ -21,6 +21,7 @@ RSS hash = Y RSS key update = Y RSS reta update = Y Inner RSS = Y +VLAN filter = Y Flow control = Y Flow API = Y VLAN offload = Y diff --git a/doc/guides/nics/features/octeontx2_vec.ini b/doc/guides/nics/features/octeontx2_vec.ini index e54c1babe4..ccedd13596 100644 --- a/doc/guides/nics/features/octeontx2_vec.ini +++ b/doc/guides/nics/features/octeontx2_vec.ini @@ -21,6 +21,7 @@ RSS hash = Y RSS key update = Y RSS reta update = Y Inner RSS = Y +VLAN filter = Y Flow control = Y Flow API = Y VLAN offload = Y diff --git a/doc/guides/nics/features/octeontx2_vf.ini b/doc/guides/nics/features/octeontx2_vf.ini index 769ab16ee6..24df147173 100644 --- a/doc/guides/nics/features/octeontx2_vf.ini +++ b/doc/guides/nics/features/octeontx2_vf.ini @@ -17,6 +17,7 @@ RSS hash = Y RSS key update = Y RSS reta update = Y Inner RSS = Y +VLAN filter = Y Flow API = Y VLAN offload = Y QinQ offload = Y diff --git a/doc/guides/nics/octeontx2.rst b/doc/guides/nics/octeontx2.rst index 9184a76b93..457980acfb 100644 --- a/doc/guides/nics/octeontx2.rst +++ b/doc/guides/nics/octeontx2.rst @@ -22,7 +22,7 @@ Features of the OCTEON TX2 Ethdev PMD are: - Lock-free Tx queue - Multiple queues for TX and RX - Receiver Side Scaling (RSS) -- MAC filtering +- MAC/VLAN filtering - Generic flow API - VLAN/QinQ stripping and insertion - Port hardware statistics diff --git a/drivers/net/octeontx2/otx2_ethdev.c b/drivers/net/octeontx2/otx2_ethdev.c index 2924d43a8b..34fab469da 100644 --- a/drivers/net/octeontx2/otx2_ethdev.c +++ b/drivers/net/octeontx2/otx2_ethdev.c @@ -1365,6 +1365,8 @@ static const struct eth_dev_ops otx2_eth_dev_ops = { .timesync_read_time = otx2_nix_timesync_read_time, .timesync_write_time = otx2_nix_timesync_write_time, .vlan_offload_set = otx2_nix_vlan_offload_set, + .vlan_filter_set = otx2_nix_vlan_filter_set, + .vlan_strip_queue_set = otx2_nix_vlan_strip_queue_set, }; static inline int diff --git a/drivers/net/octeontx2/otx2_ethdev.h b/drivers/net/octeontx2/otx2_ethdev.h index 50fd18b6e4..996ddec477 100644 --- a/drivers/net/octeontx2/otx2_ethdev.h +++ b/drivers/net/octeontx2/otx2_ethdev.h @@ -450,6 +450,10 @@ int otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev); int otx2_nix_vlan_fini(struct rte_eth_dev *eth_dev); int otx2_nix_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask); void otx2_nix_vlan_update_promisc(struct rte_eth_dev *eth_dev, int enable); +int otx2_nix_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id, + int on); +void otx2_nix_vlan_strip_queue_set(struct rte_eth_dev *dev, + uint16_t queue, int on); /* Lookup configuration */ void *otx2_nix_fastpath_lookup_mem_get(void); diff --git a/drivers/net/octeontx2/otx2_vlan.c b/drivers/net/octeontx2/otx2_vlan.c index 7cf4f3136e..6216d65451 100644 --- a/drivers/net/octeontx2/otx2_vlan.c +++ b/drivers/net/octeontx2/otx2_vlan.c @@ -22,8 +22,8 @@ enum vtag_cfg_dir { }; static int -__rte_unused nix_vlan_mcam_enb_dis(struct otx2_eth_dev *dev, - uint32_t entry, const int enable) +nix_vlan_mcam_enb_dis(struct otx2_eth_dev *dev, + uint32_t entry, const int enable) { struct npc_mcam_ena_dis_entry_req *req; struct otx2_mbox *mbox = dev->mbox; @@ -460,6 +460,8 @@ nix_vlan_hw_filter(struct rte_eth_dev *eth_dev, const uint8_t enable, uint16_t vlan_id) { struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct otx2_vlan_info *vlan = &dev->vlan_info; + struct vlan_entry *entry; int rc = -EINVAL; if (!vlan_id && enable) { @@ -473,6 +475,24 @@ nix_vlan_hw_filter(struct rte_eth_dev *eth_dev, const uint8_t enable, return 0; } + /* Enable/disable existing vlan filter entries */ + TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) { + if (vlan_id) { + if (entry->vlan_id == vlan_id) { + rc = nix_vlan_mcam_enb_dis(dev, + entry->mcam_idx, + enable); + if (rc) + return rc; + } + } else { + rc = nix_vlan_mcam_enb_dis(dev, entry->mcam_idx, + enable); + if (rc) + return rc; + } + } + if (!vlan_id && !enable) { rc = nix_vlan_handle_default_rx_entry(eth_dev, false, true, enable); @@ -487,6 +507,85 @@ nix_vlan_hw_filter(struct rte_eth_dev *eth_dev, const uint8_t enable, return 0; } +/* Enable/disable vlan filtering for the given vlan_id */ +int +otx2_nix_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id, + int on) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct otx2_vlan_info *vlan = &dev->vlan_info; + struct vlan_entry *entry; + int entry_exists = 0; + int rc = -EINVAL; + int mcam_idx; + + if (!vlan_id) { + otx2_err("Vlan Id can't be zero"); + return rc; + } + + if (!vlan->def_rx_mcam_idx) { + otx2_err("Vlan Filtering is disabled, enable it first"); + return rc; + } + + if (on) { + TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) { + if (entry->vlan_id == vlan_id) { + /* Vlan entry already exists */ + entry_exists = 1; + /* Mcam entry already allocated */ + if (entry->mcam_idx) { + rc = nix_vlan_hw_filter(eth_dev, on, + vlan_id); + return rc; + } + break; + } + } + + if (!entry_exists) { + entry = rte_zmalloc("otx2_nix_vlan_entry", + sizeof(struct vlan_entry), 0); + if (!entry) { + otx2_err("Failed to allocate memory"); + return -ENOMEM; + } + } + + /* Enables vlan_id & mac address based filtering */ + if (eth_dev->data->promiscuous) + mcam_idx = nix_vlan_mcam_config(eth_dev, vlan_id, + VLAN_ID_MATCH); + else + mcam_idx = nix_vlan_mcam_config(eth_dev, vlan_id, + VLAN_ID_MATCH | + MAC_ADDR_MATCH); + if (mcam_idx < 0) { + otx2_err("Failed to config vlan mcam"); + TAILQ_REMOVE(&vlan->fltr_tbl, entry, next); + rte_free(entry); + return mcam_idx; + } + + entry->mcam_idx = mcam_idx; + if (!entry_exists) { + entry->vlan_id = vlan_id; + TAILQ_INSERT_HEAD(&vlan->fltr_tbl, entry, next); + } + } else { + TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) { + if (entry->vlan_id == vlan_id) { + nix_vlan_mcam_free(dev, entry->mcam_idx); + TAILQ_REMOVE(&vlan->fltr_tbl, entry, next); + rte_free(entry); + break; + } + } + } + return 0; +} + /* Configure double vlan(qinq) on or off */ static int otx2_nix_config_double_vlan(struct rte_eth_dev *eth_dev, @@ -594,6 +693,13 @@ otx2_nix_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask) return rc; } +void otx2_nix_vlan_strip_queue_set(__rte_unused struct rte_eth_dev *dev, + __rte_unused uint16_t queue, + __rte_unused int on) +{ + otx2_err("Not Supported"); +} + static int nix_vlan_rx_mkex_offset(uint64_t mask) { @@ -646,6 +752,27 @@ nix_vlan_get_mkex_info(struct otx2_eth_dev *dev) return 0; } +static void nix_vlan_reinstall_vlan_filters(struct rte_eth_dev *eth_dev) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct vlan_entry *entry; + int rc; + + /* VLAN filters can't be set without setting filtern on */ + rc = nix_vlan_handle_default_rx_entry(eth_dev, false, true, true); + if (rc) { + otx2_err("Failed to reinstall vlan filters"); + return; + } + + TAILQ_FOREACH(entry, &dev->vlan_info.fltr_tbl, next) { + rc = otx2_nix_vlan_filter_set(eth_dev, entry->vlan_id, true); + if (rc) + otx2_err("Failed to reinstall filter for vlan:%d", + entry->vlan_id); + } +} + int otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev) { @@ -661,6 +788,11 @@ otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev) } TAILQ_INIT(&dev->vlan_info.fltr_tbl); + } else { + /* Reinstall all mcam entries now if filter offload is set */ + if (eth_dev->data->dev_conf.rxmode.offloads & + DEV_RX_OFFLOAD_VLAN_FILTER) + nix_vlan_reinstall_vlan_filters(eth_dev); } mask = @@ -679,8 +811,21 @@ otx2_nix_vlan_fini(struct rte_eth_dev *eth_dev) { struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); struct otx2_vlan_info *vlan = &dev->vlan_info; + struct vlan_entry *entry; int rc; + TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) { + if (!dev->configured) { + TAILQ_REMOVE(&vlan->fltr_tbl, entry, next); + rte_free(entry); + } else { + /* MCAM entries freed by flow_fini & lf_free on + * port stop. + */ + entry->mcam_idx = 0; + } + } + if (!dev->configured) { if (vlan->def_rx_mcam_idx) { rc = nix_vlan_mcam_free(dev, vlan->def_rx_mcam_idx);