[v1,13/15] net/igc: implement TCP SYN filter

Message ID 1583742247-370386-13-git-send-email-alvinx.zhang@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series [v1,01/15] net/igc: add igc PMD |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

Alvin Zhang March 9, 2020, 8:24 a.m. UTC
  From: Alvin Zhang <alvinx.zhang@intel.com>

Support putting all TCP SYN packets into a specified queue.

Signed-off-by: Alvin Zhang <alvinx.zhang@intel.com>
---
 drivers/net/igc/igc_ethdev.h |  18 ++++++
 drivers/net/igc/igc_filter.c | 129 +++++++++++++++++++++++++++++++++++++++++++
 drivers/net/igc/igc_filter.h |   3 +
 3 files changed, 150 insertions(+)
  

Patch

diff --git a/drivers/net/igc/igc_ethdev.h b/drivers/net/igc/igc_ethdev.h
index 639782c..68237aa 100644
--- a/drivers/net/igc/igc_ethdev.h
+++ b/drivers/net/igc/igc_ethdev.h
@@ -102,6 +102,11 @@ 
 #define IGC_MAX_2TUPLE_FILTERS		8
 #define IGC_2TUPLE_MAX_PRI		7
 
+#define IGC_SYN_FILTER_ENABLE		0x01	/* syn filter enable field */
+#define IGC_SYN_FILTER_QUEUE_SHIFT	1	/* syn filter queue field */
+#define IGC_SYN_FILTER_QUEUE	0x0000000E	/* syn filter queue field */
+#define IGC_RFCTL_SYNQFP	0x00080000	/* SYNQFP in RFCTL register */
+
 /* structure for interrupt relative data */
 struct igc_interrupt {
 	uint32_t flags;
@@ -176,6 +181,18 @@  struct igc_2tuple_filter {
 	uint8_t queue;
 };
 
+/* Structure of TCP SYN filter */
+struct igc_syn_filter {
+	uint8_t queue;
+	/*
+	 * Defines the priority between SYNQF and 2 tuple filter
+	 * 0b = 2-tuple filter priority
+	 * 1b = SYN filter priority
+	 */
+	uint8_t priority:1,
+		enable:1;	/* 1-enable; 0-disable */
+};
+
 /*
  * Structure to store private data for each driver instance (for each port).
  */
@@ -192,6 +209,7 @@  struct igc_adapter {
 
 	struct igc_ethertype_filter ethertype_filters[IGC_MAX_ETQF_FILTERS];
 	struct igc_2tuple_filter tuple2_filters[IGC_MAX_2TUPLE_FILTERS];
+	struct igc_syn_filter syn_filter;
 };
 
 #define IGC_DEV_PRIVATE(_dev)	((_dev)->data->dev_private)
diff --git a/drivers/net/igc/igc_filter.c b/drivers/net/igc/igc_filter.c
index 340dbee..5203d82 100644
--- a/drivers/net/igc/igc_filter.c
+++ b/drivers/net/igc/igc_filter.c
@@ -546,11 +546,136 @@ 
 	return ret;
 }
 
+int
+igc_set_syn_filter(struct rte_eth_dev *dev,
+		const struct rte_eth_syn_filter *filter)
+{
+	struct igc_hw *hw;
+	struct igc_adapter *igc;
+	struct igc_syn_filter *syn_filter;
+	uint32_t synqf, rfctl;
+
+	if (filter->queue >= IGC_QUEUE_PAIRS_NUM) {
+		PMD_DRV_LOG(ERR, "out of range queue %u(max is %u)",
+			filter->queue, IGC_QUEUE_PAIRS_NUM);
+		return -EINVAL;
+	}
+
+	igc = IGC_DEV_PRIVATE(dev);
+	syn_filter = &igc->syn_filter;
+
+	if (syn_filter->enable) {
+		PMD_DRV_LOG(ERR, "SYN filter has been enabled before!");
+		return -EEXIST;
+	}
+
+	hw = IGC_DEV_PRIVATE_HW(dev);
+	synqf = (uint32_t)filter->queue << IGC_SYN_FILTER_QUEUE_SHIFT;
+	synqf |= IGC_SYN_FILTER_ENABLE;
+
+	rfctl = IGC_READ_REG(hw, IGC_RFCTL);
+	if (filter->hig_pri) {
+		syn_filter->priority = 1;
+		rfctl |= IGC_RFCTL_SYNQFP;
+	} else {
+		syn_filter->priority = 0;
+		rfctl &= ~IGC_RFCTL_SYNQFP;
+	}
+
+	syn_filter->enable = 1;
+	syn_filter->queue = filter->queue;
+	IGC_WRITE_REG(hw, IGC_RFCTL, rfctl);
+	IGC_WRITE_REG(hw, IGC_SYNQF(0), synqf);
+	IGC_WRITE_FLUSH(hw);
+	return 0;
+}
+
+int
+igc_del_syn_filter(struct rte_eth_dev *dev)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
+	struct igc_syn_filter *syn_filter = &igc->syn_filter;
+
+	if (syn_filter->enable == 0)
+		return 0;
+
+	syn_filter->enable = 0;
+
+	IGC_WRITE_REG(hw, IGC_SYNQF(0), 0);
+	IGC_WRITE_FLUSH(hw);
+	return 0;
+}
+
+static int
+igc_syn_filter_get(struct rte_eth_dev *dev, struct rte_eth_syn_filter *filter)
+{
+	struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
+	struct igc_syn_filter *syn_filter = &igc->syn_filter;
+
+	if (syn_filter->enable == 0) {
+		PMD_DRV_LOG(ERR, "syn filter not been set.\n");
+		return -ENOENT;
+	}
+
+	filter->hig_pri = syn_filter->priority;
+	filter->queue = syn_filter->queue;
+	return 0;
+}
+
+/* clear the SYN filter */
+static void
+igc_clear_syn_filter(struct rte_eth_dev *dev)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
+
+	IGC_WRITE_REG(hw, IGC_SYNQF(0), 0);
+	IGC_WRITE_FLUSH(hw);
+
+	memset(&igc->syn_filter, 0, sizeof(igc->syn_filter));
+}
+
+static int
+igc_syn_filter_handle(struct rte_eth_dev *dev, enum rte_filter_op filter_op,
+		struct rte_eth_syn_filter *filter)
+{
+	int ret;
+
+	if (filter_op == RTE_ETH_FILTER_NOP)
+		return 0;
+
+	if (filter == NULL) {
+		PMD_DRV_LOG(ERR, "filter shouldn't be NULL for operation %u",
+			    filter_op);
+		return -EINVAL;
+	}
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_ADD:
+		ret = igc_set_syn_filter(dev, filter);
+		break;
+	case RTE_ETH_FILTER_DELETE:
+		ret = igc_del_syn_filter(dev);
+		break;
+	case RTE_ETH_FILTER_GET:
+		ret = igc_syn_filter_get(dev, filter);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "unsupported operation %u", filter_op);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 void
 igc_clear_all_filter(struct rte_eth_dev *dev)
 {
 	igc_clear_all_ethertype_filter(dev);
 	igc_clear_all_ntuple_filter(dev);
+	igc_clear_syn_filter(dev);
 }
 
 int
@@ -568,6 +693,10 @@ 
 		ret = igc_ntuple_filter_handle(dev, filter_op,
 			(struct rte_eth_ntuple_filter *)arg);
 		break;
+	case RTE_ETH_FILTER_SYN:
+		ret = igc_syn_filter_handle(dev, filter_op,
+			(struct rte_eth_syn_filter *)arg);
+		break;
 	default:
 		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
 							filter_type);
diff --git a/drivers/net/igc/igc_filter.h b/drivers/net/igc/igc_filter.h
index 7c5e843..4fad8e0 100644
--- a/drivers/net/igc/igc_filter.h
+++ b/drivers/net/igc/igc_filter.h
@@ -20,6 +20,9 @@  int igc_del_ethertype_filter(struct rte_eth_dev *dev,
 int igc_add_del_ntuple_filter(struct rte_eth_dev *dev,
 			const struct rte_eth_ntuple_filter *ntuple,
 			bool add);
+int igc_set_syn_filter(struct rte_eth_dev *dev,
+		const struct rte_eth_syn_filter *filter);
+int igc_del_syn_filter(struct rte_eth_dev *dev);
 void
 igc_clear_all_filter(struct rte_eth_dev *dev);