From patchwork Thu Jan 15 01:45:59 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jingjing Wu X-Patchwork-Id: 2272 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 2A97C5A80; Thu, 15 Jan 2015 02:46:31 +0100 (CET) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id 042345A1F for ; Thu, 15 Jan 2015 02:46:15 +0100 (CET) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP; 14 Jan 2015 17:46:14 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.09,400,1418112000"; d="scan'208";a="637493600" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by orsmga001.jf.intel.com with ESMTP; 14 Jan 2015 17:46:13 -0800 Received: from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com [10.239.29.89]) by shvmail01.sh.intel.com with ESMTP id t0F1kBwo016879; Thu, 15 Jan 2015 09:46:11 +0800 Received: from shecgisg004.sh.intel.com (localhost [127.0.0.1]) by shecgisg004.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id t0F1k9RR011559; Thu, 15 Jan 2015 09:46:11 +0800 Received: (from wujingji@localhost) by shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id t0F1k9B7011555; Thu, 15 Jan 2015 09:46:09 +0800 From: Jingjing Wu To: dev@dpdk.org Date: Thu, 15 Jan 2015 09:45:59 +0800 Message-Id: <1421286361-11504-4-git-send-email-jingjing.wu@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1421286361-11504-1-git-send-email-jingjing.wu@intel.com> References: <1421286361-11504-1-git-send-email-jingjing.wu@intel.com> Subject: [dpdk-dev] [PATCH 3/5] e1000: ntuple filter functions replace old ones for 2tuple and 5tuple filter X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch defines new functions dealing with ntuple filters which is corresponding to 2tuple filter for 82580 and i350 in HW, and to 5tuple filter for 82576 in HW. It removes old functions which deal with 2tuple and 5tuple filters in igb driver. It also defines eth_igb_filter_ctrl which is binding to filter_ctrl API, and ntuple filter can be dealt with through this new entrance. Signed-off-by: Jingjing Wu --- lib/librte_pmd_e1000/e1000_ethdev.h | 79 +++- lib/librte_pmd_e1000/igb_ethdev.c | 892 +++++++++++++++++++++++++----------- 2 files changed, 680 insertions(+), 291 deletions(-) diff --git a/lib/librte_pmd_e1000/e1000_ethdev.h b/lib/librte_pmd_e1000/e1000_ethdev.h index 71eb5fb..2433759 100644 --- a/lib/librte_pmd_e1000/e1000_ethdev.h +++ b/lib/librte_pmd_e1000/e1000_ethdev.h @@ -67,14 +67,6 @@ #define E1000_IMIR_DSTPORT 0x0000FFFF #define E1000_IMIR_PRIORITY 0xE0000000 -#define E1000_IMIR_EXT_SIZE_BP 0x00001000 -#define E1000_IMIR_EXT_CTRL_UGR 0x00002000 -#define E1000_IMIR_EXT_CTRL_ACK 0x00004000 -#define E1000_IMIR_EXT_CTRL_PSH 0x00008000 -#define E1000_IMIR_EXT_CTRL_RST 0x00010000 -#define E1000_IMIR_EXT_CTRL_SYN 0x00020000 -#define E1000_IMIR_EXT_CTRL_FIN 0x00040000 -#define E1000_IMIR_EXT_CTRL_BP 0x00080000 #define E1000_MAX_TTQF_FILTERS 8 #define E1000_2TUPLE_MAX_PRI 7 @@ -96,11 +88,6 @@ #define E1000_MAX_FTQF_FILTERS 8 #define E1000_FTQF_PROTOCOL_MASK 0x000000FF #define E1000_FTQF_5TUPLE_MASK_SHIFT 28 -#define E1000_FTQF_PROTOCOL_COMP_MASK 0x10000000 -#define E1000_FTQF_SOURCE_ADDR_MASK 0x20000000 -#define E1000_FTQF_DEST_ADDR_MASK 0x40000000 -#define E1000_FTQF_SOURCE_PORT_MASK 0x80000000 -#define E1000_FTQF_VF_MASK_EN 0x00008000 #define E1000_FTQF_QUEUE_MASK 0x03ff0000 #define E1000_FTQF_QUEUE_SHIFT 16 #define E1000_FTQF_QUEUE_ENABLE 0x00000100 @@ -131,6 +118,68 @@ struct e1000_vf_info { uint16_t tx_rate; }; +TAILQ_HEAD(e1000_5tuple_filter_list, e1000_5tuple_filter); +TAILQ_HEAD(e1000_2tuple_filter_list, e1000_2tuple_filter); + +struct e1000_5tuple_filter_info { + uint32_t dst_ip; + uint32_t src_ip; + uint16_t dst_port; + uint16_t src_port; + uint8_t proto; /* l4 protocol. */ + /* the packet matched above 5tuple and contain any set bit will hit this filter. */ + uint8_t tcp_flags; + uint8_t priority; /* seven levels (001b-111b), 111b is highest, + used when more than one filter matches. */ + uint8_t dst_ip_mask:1, /* if mask is 1b, do not compare dst ip. */ + src_ip_mask:1, /* if mask is 1b, do not compare src ip. */ + dst_port_mask:1, /* if mask is 1b, do not compare dst port. */ + src_port_mask:1, /* if mask is 1b, do not compare src port. */ + proto_mask:1; /* if mask is 1b, do not compare protocol. */ +}; + +struct e1000_2tuple_filter_info { + uint16_t dst_port; + uint8_t proto; /* l4 protocol. */ + /* the packet matched above 2tuple and contain any set bit will hit this filter. */ + uint8_t tcp_flags; + uint8_t priority; /* seven levels (001b-111b), 111b is highest, + used when more than one filter matches. */ + uint8_t dst_ip_mask:1, /* if mask is 1b, do not compare dst ip. */ + src_ip_mask:1, /* if mask is 1b, do not compare src ip. */ + dst_port_mask:1, /* if mask is 1b, do not compare dst port. */ + src_port_mask:1, /* if mask is 1b, do not compare src port. */ + proto_mask:1; /* if mask is 1b, do not compare protocol. */ +}; + +/* 5tuple filter structure */ +struct e1000_5tuple_filter { + TAILQ_ENTRY(e1000_5tuple_filter) entries; + uint16_t index; /* the index of 5tuple filter */ + struct e1000_5tuple_filter_info filter_info; + uint16_t queue; /* rx queue assigned to */ +}; + +/* 2tuple filter structure */ +struct e1000_2tuple_filter { + TAILQ_ENTRY(e1000_2tuple_filter) entries; + uint16_t index; /* the index of 2tuple filter */ + struct e1000_2tuple_filter_info filter_info; + uint16_t queue; /* rx queue assigned to */ +}; + +/* + * Structure to store filters' info. + */ +struct e1000_filter_info { + /* Bit mask for every used 5tuple filter */ + uint8_t fivetuple_mask; + struct e1000_5tuple_filter_list fivetuple_list; + /* Bit mask for every used 2tuple filter */ + uint8_t twotuple_mask; + struct e1000_2tuple_filter_list twotuple_list; +}; + /* * Structure to store private data for each driver instance (for each port). */ @@ -140,6 +189,7 @@ struct e1000_adapter { struct e1000_interrupt intr; struct e1000_vfta shadow_vfta; struct e1000_vf_info *vfdata; + struct e1000_filter_info filter; }; #define E1000_DEV_PRIVATE_TO_HW(adapter) \ @@ -157,6 +207,9 @@ struct e1000_adapter { #define E1000_DEV_PRIVATE_TO_P_VFDATA(adapter) \ (&((struct e1000_adapter *)adapter)->vfdata) +#define E1000_DEV_PRIVATE_TO_FILTER_INFO(adapter) \ + (&((struct e1000_adapter *)adapter)->filter) + /* * RX/TX IGB function prototypes */ diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c index 873d65e..551283e 100644 --- a/lib/librte_pmd_e1000/igb_ethdev.c +++ b/lib/librte_pmd_e1000/igb_ethdev.c @@ -162,14 +162,10 @@ static int eth_igb_remove_ethertype_filter(struct rte_eth_dev *dev, static int eth_igb_get_ethertype_filter(struct rte_eth_dev *dev, uint16_t index, struct rte_ethertype_filter *filter, uint16_t *rx_queue); -static int eth_igb_add_2tuple_filter(struct rte_eth_dev *dev, - uint16_t index, - struct rte_2tuple_filter *filter, uint16_t rx_queue); -static int eth_igb_remove_2tuple_filter(struct rte_eth_dev *dev, - uint16_t index); -static int eth_igb_get_2tuple_filter(struct rte_eth_dev *dev, - uint16_t index, - struct rte_2tuple_filter *filter, uint16_t *rx_queue); +static int igb_add_2tuple_filter(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter); +static int igb_remove_2tuple_filter(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter); static int eth_igb_add_flex_filter(struct rte_eth_dev *dev, uint16_t index, struct rte_flex_filter *filter, uint16_t rx_queue); @@ -178,14 +174,22 @@ static int eth_igb_remove_flex_filter(struct rte_eth_dev *dev, static int eth_igb_get_flex_filter(struct rte_eth_dev *dev, uint16_t index, struct rte_flex_filter *filter, uint16_t *rx_queue); -static int eth_igb_add_5tuple_filter(struct rte_eth_dev *dev, - uint16_t index, - struct rte_5tuple_filter *filter, uint16_t rx_queue); -static int eth_igb_remove_5tuple_filter(struct rte_eth_dev *dev, - uint16_t index); -static int eth_igb_get_5tuple_filter(struct rte_eth_dev *dev, - uint16_t index, - struct rte_5tuple_filter *filter, uint16_t *rx_queue); +static int igb_add_5tuple_filter_82576(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter); +static int igb_remove_5tuple_filter_82576(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter); +static int igb_add_del_ntuple_filter(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *filter, + bool add); +static int igb_get_ntuple_filter(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *filter); +static int igb_ntuple_filter_handle(struct rte_eth_dev *dev, + enum rte_filter_op filter_op, + void *arg); +static int eth_igb_filter_ctrl(struct rte_eth_dev *dev, + enum rte_filter_type filter_type, + enum rte_filter_op filter_op, + void *arg); /* * Define VF Stats MACRO for Non "cleared on read" register @@ -267,15 +271,10 @@ static struct eth_dev_ops eth_igb_ops = { .add_ethertype_filter = eth_igb_add_ethertype_filter, .remove_ethertype_filter = eth_igb_remove_ethertype_filter, .get_ethertype_filter = eth_igb_get_ethertype_filter, - .add_2tuple_filter = eth_igb_add_2tuple_filter, - .remove_2tuple_filter = eth_igb_remove_2tuple_filter, - .get_2tuple_filter = eth_igb_get_2tuple_filter, .add_flex_filter = eth_igb_add_flex_filter, .remove_flex_filter = eth_igb_remove_flex_filter, .get_flex_filter = eth_igb_get_flex_filter, - .add_5tuple_filter = eth_igb_add_5tuple_filter, - .remove_5tuple_filter = eth_igb_remove_5tuple_filter, - .get_5tuple_filter = eth_igb_get_5tuple_filter, + .filter_ctrl = eth_igb_filter_ctrl, }; /* @@ -468,6 +467,8 @@ eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); struct e1000_vfta * shadow_vfta = E1000_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(eth_dev->data->dev_private); uint32_t ctrl_ext; pci_dev = eth_dev->pci_dev; @@ -599,6 +600,12 @@ eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, /* enable support intr */ igb_intr_enable(eth_dev); + /* initialize ntuple filter list */ + TAILQ_INIT(&filter_info->twotuple_list); + filter_info->twotuple_mask = 0; + TAILQ_INIT(&filter_info->fivetuple_list); + filter_info->fivetuple_mask = 0; + return 0; err_late: @@ -924,7 +931,11 @@ static void eth_igb_stop(struct rte_eth_dev *dev) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); struct rte_eth_link link; + struct e1000_5tuple_filter *p_5tuple, *p_5tuple_next; + struct e1000_2tuple_filter *p_2tuple, *p_2tuple_next; igb_intr_disable(hw); igb_pf_reset_hw(hw); @@ -947,6 +958,24 @@ eth_igb_stop(struct rte_eth_dev *dev) /* clear the recorded link status */ memset(&link, 0, sizeof(link)); rte_igb_dev_atomic_write_link_status(dev, &link); + + /* Remove all ntuple filters of the device */ + for (p_5tuple = TAILQ_FIRST(&filter_info->fivetuple_list); + p_5tuple != NULL; p_5tuple = p_5tuple_next) { + p_5tuple_next = TAILQ_NEXT(p_5tuple, entries); + TAILQ_REMOVE(&filter_info->fivetuple_list, + p_5tuple, entries); + rte_free(p_5tuple); + } + filter_info->fivetuple_mask = 0; + for (p_2tuple = TAILQ_FIRST(&filter_info->twotuple_list); + p_2tuple != NULL; p_2tuple = p_2tuple_next) { + p_2tuple_next = TAILQ_NEXT(p_2tuple, entries); + TAILQ_REMOVE(&filter_info->twotuple_list, + p_2tuple, entries); + rte_free(p_2tuple); + } + filter_info->twotuple_mask = 0; } static void @@ -2388,7 +2417,7 @@ eth_igb_rss_reta_query(struct rte_eth_dev *dev, #define MAC_TYPE_FILTER_SUP(type) do {\ if ((type) != e1000_82580 && (type) != e1000_i350 &&\ (type) != e1000_82576)\ - return -ENOSYS;\ + return -ENOTSUP;\ } while (0) /* @@ -2595,165 +2624,209 @@ eth_igb_get_ethertype_filter(struct rte_eth_dev *dev, uint16_t index, return -ENOSYS; \ } while (0) -/* - * add a 2tuple filter - * - * @param - * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. - * filter: ponter to the filter that will be added. - * rx_queue: the queue id the filter assigned to. - * - * @return - * - On success, zero. - * - On failure, a negative value. - */ -static int -eth_igb_add_2tuple_filter(struct rte_eth_dev *dev, uint16_t index, - struct rte_2tuple_filter *filter, uint16_t rx_queue) +/* translate elements in struct rte_eth_ntuple_filter to struct e1000_2tuple_filter_info*/ +static inline int +ntuple_filter_to_2tuple(struct rte_eth_ntuple_filter *filter, + struct e1000_2tuple_filter_info *filter_info) { - struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t ttqf, imir = 0; - uint32_t imir_ext = 0; - - MAC_TYPE_FILTER_SUP_EXT(hw->mac.type); - - if (index >= E1000_MAX_TTQF_FILTERS || - rx_queue >= IGB_MAX_RX_QUEUE_NUM || - filter->priority > E1000_2TUPLE_MAX_PRI) + if (filter->queue >= IGB_MAX_RX_QUEUE_NUM) + return -EINVAL; + if (filter->priority > E1000_2TUPLE_MAX_PRI) return -EINVAL; /* filter index is out of range. */ - if (filter->tcp_flags > TCP_FLAG_ALL) + if (filter->tcp_flags > TCP_FLAG_ALL) return -EINVAL; /* flags is invalid. */ - ttqf = E1000_READ_REG(hw, E1000_TTQF(index)); - if (ttqf & E1000_TTQF_QUEUE_ENABLE) - return -EINVAL; /* filter index is in use. */ - - imir = (uint32_t)(filter->dst_port & E1000_IMIR_DSTPORT); - if (filter->dst_port_mask == 1) /* 1b means not compare. */ - imir |= E1000_IMIR_PORT_BP; - else - imir &= ~E1000_IMIR_PORT_BP; + switch (filter->dst_port_mask) { + case UINT16_MAX: + filter_info->dst_port_mask = 0; + filter_info->dst_port = filter->dst_port; + break; + case 0: + filter_info->dst_port_mask = 1; + break; + default: + PMD_DRV_LOG(ERR, "invalid dst_port mask."); + return -EINVAL; + } - imir |= filter->priority << E1000_IMIR_PRIORITY_SHIFT; + switch (filter->proto_mask) { + case UINT8_MAX: + filter_info->proto_mask = 0; + filter_info->proto = filter->proto; + break; + case 0: + filter_info->proto_mask = 1; + break; + default: + PMD_DRV_LOG(ERR, "invalid protocol mask."); + return -EINVAL; + } - ttqf = 0; - ttqf |= E1000_TTQF_QUEUE_ENABLE; - ttqf |= (uint32_t)(rx_queue << E1000_TTQF_QUEUE_SHIFT); - ttqf |= (uint32_t)(filter->protocol & E1000_TTQF_PROTOCOL_MASK); - if (filter->protocol_mask == 1) - ttqf |= E1000_TTQF_MASK_ENABLE; + filter_info->priority = (uint8_t)filter->priority; + if (filter->flags & RTE_NTUPLE_FLAGS_TCP_FLAG) + filter_info->tcp_flags = filter->tcp_flags; else - ttqf &= ~E1000_TTQF_MASK_ENABLE; + filter_info->tcp_flags = 0; - imir_ext |= E1000_IMIR_EXT_SIZE_BP; - /* tcp flags bits setting. */ - if (filter->tcp_flags & TCP_FLAG_ALL) { - if (filter->tcp_flags & TCP_UGR_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_UGR; - if (filter->tcp_flags & TCP_ACK_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_ACK; - if (filter->tcp_flags & TCP_PSH_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_PSH; - if (filter->tcp_flags & TCP_RST_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_RST; - if (filter->tcp_flags & TCP_SYN_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_SYN; - if (filter->tcp_flags & TCP_FIN_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_FIN; - imir_ext &= ~E1000_IMIR_EXT_CTRL_BP; - } else - imir_ext |= E1000_IMIR_EXT_CTRL_BP; - E1000_WRITE_REG(hw, E1000_IMIR(index), imir); - E1000_WRITE_REG(hw, E1000_TTQF(index), ttqf); - E1000_WRITE_REG(hw, E1000_IMIREXT(index), imir_ext); return 0; } +static inline struct e1000_2tuple_filter * +igb_2tuple_filter_lookup(struct e1000_2tuple_filter_list *filter_list, + struct e1000_2tuple_filter_info *key) +{ + struct e1000_2tuple_filter *it; + + TAILQ_FOREACH(it, filter_list, entries) { + if (memcmp(key, &it->filter_info, + sizeof(struct e1000_2tuple_filter_info)) == 0) { + return it; + } + } + return NULL; +} + /* - * remove a 2tuple filter + * igb_add_2tuple_filter - add a 2tuple filter * * @param * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. + * ntuple_filter: ponter to the filter that will be added. * * @return * - On success, zero. * - On failure, a negative value. */ static int -eth_igb_remove_2tuple_filter(struct rte_eth_dev *dev, - uint16_t index) +igb_add_2tuple_filter(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); + struct e1000_2tuple_filter *filter; + uint32_t ttqf = E1000_TTQF_DISABLE_MASK; + uint32_t imir, imir_ext = E1000_IMIREXT_SIZE_BP; + int i, ret; + + filter = rte_zmalloc("e1000_2tuple_filter", + sizeof(struct e1000_2tuple_filter), 0); + if (filter == NULL) + return -ENOMEM; - MAC_TYPE_FILTER_SUP_EXT(hw->mac.type); + ret = ntuple_filter_to_2tuple(ntuple_filter, + &filter->filter_info); + if (ret < 0) { + rte_free(filter); + return ret; + } + if (igb_2tuple_filter_lookup(&filter_info->twotuple_list, + &filter->filter_info) != NULL) { + PMD_DRV_LOG(ERR, "filter exists."); + rte_free(filter); + return -EEXIST; + } + filter->queue = ntuple_filter->queue; + + /* + * look for an unused 2tuple filter index, + * and insert the filter to list. + */ + for (i = 0; i < E1000_MAX_TTQF_FILTERS; i++) { + if (!(filter_info->twotuple_mask & (1 << i))) { + filter_info->twotuple_mask |= 1 << i; + filter->index = i; + TAILQ_INSERT_TAIL(&filter_info->twotuple_list, + filter, + entries); + break; + } + } + if (i >= E1000_MAX_TTQF_FILTERS) { + PMD_DRV_LOG(ERR, "2tuple filters are full."); + rte_free(filter); + return -ENOSYS; + } - if (index >= E1000_MAX_TTQF_FILTERS) - return -EINVAL; /* filter index is out of range */ + imir = (uint32_t)(filter->filter_info.dst_port & E1000_IMIR_DSTPORT); + if (filter->filter_info.dst_port_mask == 1) /* 1b means not compare. */ + imir |= E1000_IMIR_PORT_BP; + else + imir &= ~E1000_IMIR_PORT_BP; + + imir |= filter->filter_info.priority << E1000_IMIR_PRIORITY_SHIFT; + + ttqf |= E1000_TTQF_QUEUE_ENABLE; + ttqf |= (uint32_t)(filter->queue << E1000_TTQF_QUEUE_SHIFT); + ttqf |= (uint32_t)(filter->filter_info.proto & E1000_TTQF_PROTOCOL_MASK); + if (filter->filter_info.proto_mask == 0) + ttqf &= ~E1000_TTQF_MASK_ENABLE; - E1000_WRITE_REG(hw, E1000_TTQF(index), 0); - E1000_WRITE_REG(hw, E1000_IMIR(index), 0); - E1000_WRITE_REG(hw, E1000_IMIREXT(index), 0); + /* tcp flags bits setting. */ + if (filter->filter_info.tcp_flags & TCP_FLAG_ALL) { + if (filter->filter_info.tcp_flags & TCP_URG_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_URG; + if (filter->filter_info.tcp_flags & TCP_ACK_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_ACK; + if (filter->filter_info.tcp_flags & TCP_PSH_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_PSH; + if (filter->filter_info.tcp_flags & TCP_RST_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_RST; + if (filter->filter_info.tcp_flags & TCP_SYN_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_SYN; + if (filter->filter_info.tcp_flags & TCP_FIN_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_FIN; + } else + imir_ext |= E1000_IMIREXT_CTRL_BP; + E1000_WRITE_REG(hw, E1000_IMIR(i), imir); + E1000_WRITE_REG(hw, E1000_TTQF(i), ttqf); + E1000_WRITE_REG(hw, E1000_IMIREXT(i), imir_ext); return 0; } /* - * get a 2tuple filter + * igb_remove_2tuple_filter - remove a 2tuple filter * * @param * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. - * filter: ponter to the filter that returns. - * *rx_queue: pointer of the queue id the filter assigned to. + * ntuple_filter: ponter to the filter that will be removed. * * @return * - On success, zero. * - On failure, a negative value. */ static int -eth_igb_get_2tuple_filter(struct rte_eth_dev *dev, uint16_t index, - struct rte_2tuple_filter *filter, uint16_t *rx_queue) +igb_remove_2tuple_filter(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t imir, ttqf, imir_ext; - - MAC_TYPE_FILTER_SUP_EXT(hw->mac.type); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); + struct e1000_2tuple_filter_info filter_2tuple; + struct e1000_2tuple_filter *filter; + int ret; - if (index >= E1000_MAX_TTQF_FILTERS) - return -EINVAL; /* filter index is out of range. */ + memset(&filter_2tuple, 0, sizeof(struct e1000_2tuple_filter_info)); + ret = ntuple_filter_to_2tuple(ntuple_filter, + &filter_2tuple); + if (ret < 0) + return ret; - ttqf = E1000_READ_REG(hw, E1000_TTQF(index)); - if (ttqf & E1000_TTQF_QUEUE_ENABLE) { - imir = E1000_READ_REG(hw, E1000_IMIR(index)); - filter->protocol = ttqf & E1000_TTQF_PROTOCOL_MASK; - filter->protocol_mask = (ttqf & E1000_TTQF_MASK_ENABLE) ? 1 : 0; - *rx_queue = (ttqf & E1000_TTQF_RX_QUEUE_MASK) >> - E1000_TTQF_QUEUE_SHIFT; - filter->dst_port = (uint16_t)(imir & E1000_IMIR_DSTPORT); - filter->dst_port_mask = (imir & E1000_IMIR_PORT_BP) ? 1 : 0; - filter->priority = (imir & E1000_IMIR_PRIORITY) >> - E1000_IMIR_PRIORITY_SHIFT; - - imir_ext = E1000_READ_REG(hw, E1000_IMIREXT(index)); - if (!(imir_ext & E1000_IMIR_EXT_CTRL_BP)) { - if (imir_ext & E1000_IMIR_EXT_CTRL_UGR) - filter->tcp_flags |= TCP_UGR_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_ACK) - filter->tcp_flags |= TCP_ACK_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_PSH) - filter->tcp_flags |= TCP_PSH_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_RST) - filter->tcp_flags |= TCP_RST_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_SYN) - filter->tcp_flags |= TCP_SYN_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_FIN) - filter->tcp_flags |= TCP_FIN_FLAG; - } else - filter->tcp_flags = 0; - return 0; + filter = igb_2tuple_filter_lookup(&filter_info->twotuple_list, + &filter_2tuple); + if (filter == NULL) { + PMD_DRV_LOG(ERR, "filter doesn't exist."); + return -ENOENT; } - return -ENOENT; + + filter_info->twotuple_mask &= ~(1 << filter->index); + TAILQ_REMOVE(&filter_info->twotuple_list, filter, entries); + rte_free(filter); + + E1000_WRITE_REG(hw, E1000_TTQF(filter->index), E1000_TTQF_DISABLE_MASK); + E1000_WRITE_REG(hw, E1000_IMIR(filter->index), 0); + E1000_WRITE_REG(hw, E1000_IMIREXT(filter->index), 0); + return 0; } /* @@ -2911,192 +2984,265 @@ eth_igb_get_flex_filter(struct rte_eth_dev *dev, uint16_t index, return -ENOENT; } -/* - * add a 5tuple filter - * - * @param - * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. - * filter: ponter to the filter that will be added. - * rx_queue: the queue id the filter assigned to. - * - * @return - * - On success, zero. - * - On failure, a negative value. - */ -static int -eth_igb_add_5tuple_filter(struct rte_eth_dev *dev, uint16_t index, - struct rte_5tuple_filter *filter, uint16_t rx_queue) +/* translate elements in struct rte_eth_ntuple_filter to struct e1000_5tuple_filter_info*/ +static inline int +ntuple_filter_to_5tuple_82576(struct rte_eth_ntuple_filter *filter, + struct e1000_5tuple_filter_info *filter_info) { - struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t ftqf, spqf = 0; - uint32_t imir = 0; - uint32_t imir_ext = 0; + if (filter->queue >= IGB_MAX_RX_QUEUE_NUM_82576) + return -EINVAL; + if (filter->priority > E1000_2TUPLE_MAX_PRI) + return -EINVAL; /* filter index is out of range. */ + if (filter->tcp_flags > TCP_FLAG_ALL) + return -EINVAL; /* flags is invalid. */ - if (hw->mac.type != e1000_82576) - return -ENOSYS; + switch (filter->dst_ip_mask) { + case UINT32_MAX: + filter_info->dst_ip_mask = 0; + filter_info->dst_ip = filter->dst_ip; + break; + case 0: + filter_info->dst_ip_mask = 1; + break; + default: + PMD_DRV_LOG(ERR, "invalid dst_ip mask."); + return -EINVAL; + } - if (index >= E1000_MAX_FTQF_FILTERS || - rx_queue >= IGB_MAX_RX_QUEUE_NUM_82576) - return -EINVAL; /* filter index is out of range. */ + switch (filter->src_ip_mask) { + case UINT32_MAX: + filter_info->src_ip_mask = 0; + filter_info->src_ip = filter->src_ip; + break; + case 0: + filter_info->src_ip_mask = 1; + break; + default: + PMD_DRV_LOG(ERR, "invalid src_ip mask."); + return -EINVAL; + } - ftqf = E1000_READ_REG(hw, E1000_FTQF(index)); - if (ftqf & E1000_FTQF_QUEUE_ENABLE) - return -EINVAL; /* filter index is in use. */ + switch (filter->dst_port_mask) { + case UINT16_MAX: + filter_info->dst_port_mask = 0; + filter_info->dst_port = filter->dst_port; + break; + case 0: + filter_info->dst_port_mask = 1; + break; + default: + PMD_DRV_LOG(ERR, "invalid dst_port mask."); + return -EINVAL; + } - ftqf = 0; - ftqf |= filter->protocol & E1000_FTQF_PROTOCOL_MASK; - if (filter->src_ip_mask == 1) /* 1b means not compare. */ - ftqf |= E1000_FTQF_SOURCE_ADDR_MASK; - if (filter->dst_ip_mask == 1) - ftqf |= E1000_FTQF_DEST_ADDR_MASK; - if (filter->src_port_mask == 1) - ftqf |= E1000_FTQF_SOURCE_PORT_MASK; - if (filter->protocol_mask == 1) - ftqf |= E1000_FTQF_PROTOCOL_COMP_MASK; - ftqf |= (rx_queue << E1000_FTQF_QUEUE_SHIFT) & E1000_FTQF_QUEUE_MASK; - ftqf |= E1000_FTQF_VF_MASK_EN; - ftqf |= E1000_FTQF_QUEUE_ENABLE; - E1000_WRITE_REG(hw, E1000_FTQF(index), ftqf); - E1000_WRITE_REG(hw, E1000_DAQF(index), filter->dst_ip); - E1000_WRITE_REG(hw, E1000_SAQF(index), filter->src_ip); + switch (filter->src_port_mask) { + case UINT16_MAX: + filter_info->src_port_mask = 0; + filter_info->src_port = filter->src_port; + break; + case 0: + filter_info->src_port_mask = 1; + break; + default: + PMD_DRV_LOG(ERR, "invalid src_port mask."); + return -EINVAL; + } - spqf |= filter->src_port & E1000_SPQF_SRCPORT; - E1000_WRITE_REG(hw, E1000_SPQF(index), spqf); + switch (filter->proto_mask) { + case UINT8_MAX: + filter_info->proto_mask = 0; + filter_info->proto = filter->proto; + break; + case 0: + filter_info->proto_mask = 1; + break; + default: + PMD_DRV_LOG(ERR, "invalid protocol mask."); + return -EINVAL; + } - imir |= (uint32_t)(filter->dst_port & E1000_IMIR_DSTPORT); - if (filter->dst_port_mask == 1) /* 1b means not compare. */ - imir |= E1000_IMIR_PORT_BP; + filter_info->priority = (uint8_t)filter->priority; + if (filter->flags & RTE_NTUPLE_FLAGS_TCP_FLAG) + filter_info->tcp_flags = filter->tcp_flags; else - imir &= ~E1000_IMIR_PORT_BP; - imir |= filter->priority << E1000_IMIR_PRIORITY_SHIFT; + filter_info->tcp_flags = 0; - imir_ext |= E1000_IMIR_EXT_SIZE_BP; - /* tcp flags bits setting. */ - if (filter->tcp_flags & TCP_FLAG_ALL) { - if (filter->tcp_flags & TCP_UGR_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_UGR; - if (filter->tcp_flags & TCP_ACK_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_ACK; - if (filter->tcp_flags & TCP_PSH_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_PSH; - if (filter->tcp_flags & TCP_RST_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_RST; - if (filter->tcp_flags & TCP_SYN_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_SYN; - if (filter->tcp_flags & TCP_FIN_FLAG) - imir_ext |= E1000_IMIR_EXT_CTRL_FIN; - } else - imir_ext |= E1000_IMIR_EXT_CTRL_BP; - E1000_WRITE_REG(hw, E1000_IMIR(index), imir); - E1000_WRITE_REG(hw, E1000_IMIREXT(index), imir_ext); return 0; } +static inline struct e1000_5tuple_filter * +igb_5tuple_filter_lookup_82576(struct e1000_5tuple_filter_list *filter_list, + struct e1000_5tuple_filter_info *key) +{ + struct e1000_5tuple_filter *it; + + TAILQ_FOREACH(it, filter_list, entries) { + if (memcmp(key, &it->filter_info, + sizeof(struct e1000_5tuple_filter_info)) == 0) { + return it; + } + } + return NULL; +} + /* - * remove a 5tuple filter + * igb_add_5tuple_filter_82576 - add a 5tuple filter * * @param * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates + * ntuple_filter: ponter to the filter that will be added. * * @return * - On success, zero. * - On failure, a negative value. */ static int -eth_igb_remove_5tuple_filter(struct rte_eth_dev *dev, - uint16_t index) +igb_add_5tuple_filter_82576(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); + struct e1000_5tuple_filter *filter; + uint32_t ftqf = E1000_FTQF_VF_BP | E1000_FTQF_MASK; + uint32_t spqf, imir, imir_ext = E1000_IMIREXT_SIZE_BP; + uint8_t i; + int ret; - if (hw->mac.type != e1000_82576) + filter = rte_zmalloc("e1000_5tuple_filter", + sizeof(struct e1000_5tuple_filter), 0); + if (filter == NULL) + return -ENOMEM; + + ret = ntuple_filter_to_5tuple_82576(ntuple_filter, + &filter->filter_info); + if (ret < 0) { + rte_free(filter); + return ret; + } + + if (igb_5tuple_filter_lookup_82576(&filter_info->fivetuple_list, + &filter->filter_info) != NULL) { + PMD_DRV_LOG(ERR, "filter exists."); + rte_free(filter); + return -EEXIST; + } + filter->queue = ntuple_filter->queue; + + /* + * look for an unused 5tuple filter index, + * and insert the filter to list. + */ + for (i = 0; i < E1000_MAX_FTQF_FILTERS; i++) { + if (!(filter_info->fivetuple_mask & (1 << i))) { + filter_info->fivetuple_mask |= 1 << i; + filter->index = i; + TAILQ_INSERT_TAIL(&filter_info->fivetuple_list, + filter, + entries); + break; + } + } + if (i >= E1000_MAX_FTQF_FILTERS) { + PMD_DRV_LOG(ERR, "5tuple filters are full."); + rte_free(filter); return -ENOSYS; + } - if (index >= E1000_MAX_FTQF_FILTERS) - return -EINVAL; /* filter index is out of range. */ + ftqf |= filter->filter_info.proto & E1000_FTQF_PROTOCOL_MASK; + if (filter->filter_info.src_ip_mask == 0) /* 0b means compare. */ + ftqf &= ~E1000_FTQF_MASK_SOURCE_ADDR_BP; + if (filter->filter_info.dst_ip_mask == 0) + ftqf &= ~E1000_FTQF_MASK_DEST_ADDR_BP; + if (filter->filter_info.src_port_mask == 0) + ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP; + if (filter->filter_info.proto_mask == 0) + ftqf &= ~E1000_FTQF_MASK_PROTO_BP; + ftqf |= (filter->queue << E1000_FTQF_QUEUE_SHIFT) & + E1000_FTQF_QUEUE_MASK; + ftqf |= E1000_FTQF_QUEUE_ENABLE; + E1000_WRITE_REG(hw, E1000_FTQF(i), ftqf); + E1000_WRITE_REG(hw, E1000_DAQF(i), filter->filter_info.dst_ip); + E1000_WRITE_REG(hw, E1000_SAQF(i), filter->filter_info.src_ip); + + spqf = filter->filter_info.src_port & E1000_SPQF_SRCPORT; + E1000_WRITE_REG(hw, E1000_SPQF(i), spqf); - E1000_WRITE_REG(hw, E1000_FTQF(index), 0); - E1000_WRITE_REG(hw, E1000_DAQF(index), 0); - E1000_WRITE_REG(hw, E1000_SAQF(index), 0); - E1000_WRITE_REG(hw, E1000_SPQF(index), 0); - E1000_WRITE_REG(hw, E1000_IMIR(index), 0); - E1000_WRITE_REG(hw, E1000_IMIREXT(index), 0); + imir = (uint32_t)(filter->filter_info.dst_port & E1000_IMIR_DSTPORT); + if (filter->filter_info.dst_port_mask == 1) /* 1b means not compare. */ + imir |= E1000_IMIR_PORT_BP; + else + imir &= ~E1000_IMIR_PORT_BP; + imir |= filter->filter_info.priority << E1000_IMIR_PRIORITY_SHIFT; + + /* tcp flags bits setting. */ + if (filter->filter_info.tcp_flags & TCP_FLAG_ALL) { + if (filter->filter_info.tcp_flags & TCP_URG_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_URG; + if (filter->filter_info.tcp_flags & TCP_ACK_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_ACK; + if (filter->filter_info.tcp_flags & TCP_PSH_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_PSH; + if (filter->filter_info.tcp_flags & TCP_RST_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_RST; + if (filter->filter_info.tcp_flags & TCP_SYN_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_SYN; + if (filter->filter_info.tcp_flags & TCP_FIN_FLAG) + imir_ext |= E1000_IMIREXT_CTRL_FIN; + } else + imir_ext |= E1000_IMIREXT_CTRL_BP; + E1000_WRITE_REG(hw, E1000_IMIR(i), imir); + E1000_WRITE_REG(hw, E1000_IMIREXT(i), imir_ext); return 0; } /* - * get a 5tuple filter + * igb_remove_5tuple_filter_82576 - remove a 5tuple filter * * @param * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates - * filter: ponter to the filter that returns - * *rx_queue: pointer of the queue id the filter assigned to + * ntuple_filter: ponter to the filter that will be removed. * * @return * - On success, zero. * - On failure, a negative value. */ static int -eth_igb_get_5tuple_filter(struct rte_eth_dev *dev, uint16_t index, - struct rte_5tuple_filter *filter, uint16_t *rx_queue) +igb_remove_5tuple_filter_82576(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t spqf, ftqf, imir, imir_ext; - - if (hw->mac.type != e1000_82576) - return -ENOSYS; + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); + struct e1000_5tuple_filter_info filter_5tuple; + struct e1000_5tuple_filter *filter; + int ret; - if (index >= E1000_MAX_FTQF_FILTERS) - return -EINVAL; /* filter index is out of range. */ + memset(&filter_5tuple, 0, sizeof(struct e1000_5tuple_filter_info)); + ret = ntuple_filter_to_5tuple_82576(ntuple_filter, + &filter_5tuple); + if (ret < 0) + return ret; - ftqf = E1000_READ_REG(hw, E1000_FTQF(index)); - if (ftqf & E1000_FTQF_QUEUE_ENABLE) { - filter->src_ip_mask = - (ftqf & E1000_FTQF_SOURCE_ADDR_MASK) ? 1 : 0; - filter->dst_ip_mask = - (ftqf & E1000_FTQF_DEST_ADDR_MASK) ? 1 : 0; - filter->src_port_mask = - (ftqf & E1000_FTQF_SOURCE_PORT_MASK) ? 1 : 0; - filter->protocol_mask = - (ftqf & E1000_FTQF_PROTOCOL_COMP_MASK) ? 1 : 0; - filter->protocol = - (uint8_t)ftqf & E1000_FTQF_PROTOCOL_MASK; - *rx_queue = (uint16_t)((ftqf & E1000_FTQF_QUEUE_MASK) >> - E1000_FTQF_QUEUE_SHIFT); - - spqf = E1000_READ_REG(hw, E1000_SPQF(index)); - filter->src_port = spqf & E1000_SPQF_SRCPORT; - - filter->dst_ip = E1000_READ_REG(hw, E1000_DAQF(index)); - filter->src_ip = E1000_READ_REG(hw, E1000_SAQF(index)); - - imir = E1000_READ_REG(hw, E1000_IMIR(index)); - filter->dst_port_mask = (imir & E1000_IMIR_PORT_BP) ? 1 : 0; - filter->dst_port = (uint16_t)(imir & E1000_IMIR_DSTPORT); - filter->priority = (imir & E1000_IMIR_PRIORITY) >> - E1000_IMIR_PRIORITY_SHIFT; - - imir_ext = E1000_READ_REG(hw, E1000_IMIREXT(index)); - if (!(imir_ext & E1000_IMIR_EXT_CTRL_BP)) { - if (imir_ext & E1000_IMIR_EXT_CTRL_UGR) - filter->tcp_flags |= TCP_UGR_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_ACK) - filter->tcp_flags |= TCP_ACK_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_PSH) - filter->tcp_flags |= TCP_PSH_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_RST) - filter->tcp_flags |= TCP_RST_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_SYN) - filter->tcp_flags |= TCP_SYN_FLAG; - if (imir_ext & E1000_IMIR_EXT_CTRL_FIN) - filter->tcp_flags |= TCP_FIN_FLAG; - } else - filter->tcp_flags = 0; - return 0; + filter = igb_5tuple_filter_lookup_82576(&filter_info->fivetuple_list, + &filter_5tuple); + if (filter == NULL) { + PMD_DRV_LOG(ERR, "filter doesn't exist."); + return -ENOENT; } - return -ENOENT; + + filter_info->fivetuple_mask &= ~(1 << filter->index); + TAILQ_REMOVE(&filter_info->fivetuple_list, filter, entries); + rte_free(filter); + + E1000_WRITE_REG(hw, E1000_FTQF(filter->index), + E1000_FTQF_VF_BP | E1000_FTQF_MASK); + E1000_WRITE_REG(hw, E1000_DAQF(filter->index), 0); + E1000_WRITE_REG(hw, E1000_SAQF(filter->index), 0); + E1000_WRITE_REG(hw, E1000_SPQF(filter->index), 0); + E1000_WRITE_REG(hw, E1000_IMIR(filter->index), 0); + E1000_WRITE_REG(hw, E1000_IMIREXT(filter->index), 0); + return 0; } static int @@ -3149,6 +3295,196 @@ eth_igb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) return 0; } +/* + * igb_add_del_ntuple_filter - add or delete a ntuple filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * ntuple_filter: Pointer to struct rte_eth_ntuple_filter + * add: if true, add filter, if false, remove filter + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +igb_add_del_ntuple_filter(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter, + bool add) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int ret; + + switch (ntuple_filter->flags) { + case RTE_5TUPLE_FLAGS: + case (RTE_5TUPLE_FLAGS | RTE_NTUPLE_FLAGS_TCP_FLAG): + if (hw->mac.type != e1000_82576) + return -ENOTSUP; + if (add) + ret = igb_add_5tuple_filter_82576(dev, + ntuple_filter); + else + ret = igb_remove_5tuple_filter_82576(dev, + ntuple_filter); + break; + case RTE_2TUPLE_FLAGS: + case (RTE_2TUPLE_FLAGS | RTE_NTUPLE_FLAGS_TCP_FLAG): + if (hw->mac.type != e1000_82580 && hw->mac.type != e1000_i350) + return -ENOTSUP; + if (add) + ret = igb_add_2tuple_filter(dev, ntuple_filter); + else + ret = igb_remove_2tuple_filter(dev, ntuple_filter); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/* + * igb_get_ntuple_filter - get a ntuple filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * ntuple_filter: Pointer to struct rte_eth_ntuple_filter + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +igb_get_ntuple_filter(struct rte_eth_dev *dev, + struct rte_eth_ntuple_filter *ntuple_filter) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); + struct e1000_5tuple_filter_info filter_5tuple; + struct e1000_2tuple_filter_info filter_2tuple; + struct e1000_5tuple_filter *p_5tuple_filter; + struct e1000_2tuple_filter *p_2tuple_filter; + int ret; + + switch (ntuple_filter->flags) { + case RTE_5TUPLE_FLAGS: + case (RTE_5TUPLE_FLAGS | RTE_NTUPLE_FLAGS_TCP_FLAG): + if (hw->mac.type != e1000_82576) + return -ENOTSUP; + memset(&filter_5tuple, + 0, + sizeof(struct e1000_5tuple_filter_info)); + ret = ntuple_filter_to_5tuple_82576(ntuple_filter, + &filter_5tuple); + if (ret < 0) + return ret; + p_5tuple_filter = igb_5tuple_filter_lookup_82576( + &filter_info->fivetuple_list, + &filter_5tuple); + if (p_5tuple_filter == NULL) { + PMD_DRV_LOG(ERR, "filter doesn't exist."); + return -ENOENT; + } + ntuple_filter->queue = p_5tuple_filter->queue; + break; + case RTE_2TUPLE_FLAGS: + case (RTE_2TUPLE_FLAGS | RTE_NTUPLE_FLAGS_TCP_FLAG): + if (hw->mac.type != e1000_82580 && hw->mac.type != e1000_i350) + return -ENOTSUP; + memset(&filter_2tuple, + 0, + sizeof(struct e1000_2tuple_filter_info)); + ret = ntuple_filter_to_2tuple(ntuple_filter, &filter_2tuple); + if (ret < 0) + return ret; + p_2tuple_filter = igb_2tuple_filter_lookup( + &filter_info->twotuple_list, + &filter_2tuple); + if (p_2tuple_filter == NULL) { + PMD_DRV_LOG(ERR, "filter doesn't exist."); + return -ENOENT; + } + ntuple_filter->queue = p_2tuple_filter->queue; + break; + default: + ret = -EINVAL; + break; + } + + return 0; +} + +/* + * igb_ntuple_filter_handle - Handle operations for ntuple filter. + * @dev: pointer to rte_eth_dev structure + * @filter_op:operation will be taken. + * @arg: a pointer to specific structure corresponding to the filter_op + */ +static int +igb_ntuple_filter_handle(struct rte_eth_dev *dev, + enum rte_filter_op filter_op, + void *arg) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int ret; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (filter_op == RTE_ETH_FILTER_NOP) + return 0; + + if (arg == NULL) { + PMD_DRV_LOG(ERR, "arg shouldn't be NULL for operation %u.", + filter_op); + return -EINVAL; + } + + switch (filter_op) { + case RTE_ETH_FILTER_ADD: + ret = igb_add_del_ntuple_filter(dev, + (struct rte_eth_ntuple_filter *)arg, + TRUE); + break; + case RTE_ETH_FILTER_DELETE: + ret = igb_add_del_ntuple_filter(dev, + (struct rte_eth_ntuple_filter *)arg, + FALSE); + break; + case RTE_ETH_FILTER_GET: + ret = igb_get_ntuple_filter(dev, + (struct rte_eth_ntuple_filter *)arg); + break; + default: + PMD_DRV_LOG(ERR, "unsupported operation %u.", filter_op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +eth_igb_filter_ctrl(struct rte_eth_dev *dev, + enum rte_filter_type filter_type, + enum rte_filter_op filter_op, + void *arg) +{ + int ret = -EINVAL; + + switch (filter_type) { + case RTE_ETH_FILTER_NTUPLE: + ret = igb_ntuple_filter_handle(dev, filter_op, arg); + break; + default: + PMD_DRV_LOG(WARNING, "Filter type (%d) not supported", + filter_type); + break; + } + + return ret; +} + static struct rte_driver pmd_igb_drv = { .type = PMD_PDEV, .init = rte_igb_pmd_init,