diff mbox

[dpdk-dev,v2,2/3] i40e: ctrl_pkt filter implementation in i40e pmd driver

Message ID 1413965977-15165-3-git-send-email-jingjing.wu@intel.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Jingjing Wu Oct. 22, 2014, 8:19 a.m. UTC
implement control packet filter, support add and delete operations.
It can assign packets to specific queue or vsi by filtering with mac
address and ethertype or only ethertype on both rx and tx directions.

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 138 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 136 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 3b75f0f..943b01a 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -186,6 +186,12 @@  static int i40e_dev_rss_hash_update(struct rte_eth_dev *dev,
 				    struct rte_eth_rss_conf *rss_conf);
 static int i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
 				      struct rte_eth_rss_conf *rss_conf);
+static int i40e_ctrl_pkt_filter_set(struct i40e_pf *pf,
+			struct rte_ctrl_pkt_filter *cp_filter,
+			bool add);
+static int i40e_ctrl_pkt_filter_handle(struct i40e_pf *pf,
+				enum rte_filter_op filter_op,
+				void *arg);
 static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_type filter_type,
 				enum rte_filter_op filter_op,
@@ -4145,20 +4151,148 @@  i40e_pf_config_mq_rx(struct i40e_pf *pf)
 	return 0;
 }
 
+/* Look up vsi by vsi_id */
+static struct i40e_vsi *
+i40e_vsi_lookup_by_id(struct i40e_vsi *uplink_vsi, uint16_t id)
+{
+	struct i40e_vsi *vsi = NULL;
+	struct i40e_vsi_list *vsi_list;
+
+	if (uplink_vsi == NULL)
+		return NULL;
+
+	if (uplink_vsi->vsi_id == id)
+		return vsi;
+
+	/* if VSI has child to attach*/
+	if (uplink_vsi->veb) {
+		TAILQ_FOREACH(vsi_list, &uplink_vsi->veb->head, list) {
+			vsi = i40e_vsi_lookup_by_id(vsi_list->vsi, id);
+			if (vsi)
+				return vsi;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Configure control packet filter, which can director packet by filtering
+ * with mac address and ether_type or only ether_type
+ */
+static int
+i40e_ctrl_pkt_filter_set(struct i40e_pf *pf,
+			struct rte_ctrl_pkt_filter *cp_filter,
+			bool add)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct i40e_control_filter_stats stats;
+	struct i40e_vsi *vsi = NULL;
+	uint16_t seid;
+	uint16_t flags = 0;
+	int ret;
+
+	if (cp_filter->ether_type == ETHER_TYPE_IPv4 ||
+		cp_filter->ether_type == ETHER_TYPE_IPv6) {
+		PMD_DRV_LOG(ERR, "unsupported ether_type(0x%04x) in"
+			" control packet filter.", cp_filter->ether_type);
+		return -EINVAL;
+	}
+	if (cp_filter->ether_type == ETHER_TYPE_VLAN)
+		PMD_DRV_LOG(WARNING, "filter vlan ether_type in first tag is"
+			" not supported.");
+
+	if (cp_filter->dest_id == 0)
+		/* Use LAN VSI Id if not programmed by user */
+		vsi = pf->main_vsi;
+	else {
+		vsi = i40e_vsi_lookup_by_id(pf->main_vsi, cp_filter->dest_id);
+		if (vsi == NULL || vsi->type == I40E_VSI_FDIR) {
+			PMD_DRV_LOG(ERR, "VSI arg is invalid\n");
+			return -EINVAL;
+		}
+	}
+
+	seid = vsi->seid;
+	memset(&stats, 0, sizeof(stats));
+
+	if (cp_filter->flags & RTE_CONTROL_PACKET_FLAGS_TX)
+		flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TX;
+	if (cp_filter->flags & RTE_CONTROL_PACKET_FLAGS_IGNORE_MAC)
+		flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC;
+	if (cp_filter->flags & RTE_CONTROL_PACKET_FLAGS_TO_QUEUE)
+		flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE;
+	if (cp_filter->flags & RTE_CONTROL_PACKET_FLAGS_DROP)
+		flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP;
+
+	ret = i40e_aq_add_rem_control_packet_filter(hw,
+			cp_filter->mac_addr.addr_bytes,
+			cp_filter->ether_type, flags,
+			seid, cp_filter->queue, add, &stats, NULL);
+
+	PMD_DRV_LOG(INFO, "add/rem control packet filter, return %d,"
+			 " mac_etype_used = %u, etype_used = %u,"
+			 " mac_etype_free = %u, etype_free = %u\n",
+			 ret, stats.mac_etype_used, stats.etype_used,
+			 stats.mac_etype_free, stats.etype_free);
+	if (ret < 0)
+		return -ENOSYS;
+	return 0;
+}
+
+/*
+ * Handle operations for control packte filter type.
+ */
+static int
+i40e_ctrl_pkt_filter_handle(struct i40e_pf *pf,
+				enum rte_filter_op filter_op,
+				void *arg)
+{
+	int ret = 0;
+
+	if (arg == NULL && filter_op != RTE_ETH_FILTER_NOP) {
+		PMD_DRV_LOG(ERR, "arg shouldn't be NULL for operation %u\n",
+			    filter_op);
+		return -EINVAL;
+	}
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_NOP:
+		ret = 0;
+		break;
+	case RTE_ETH_FILTER_ADD:
+		ret = i40e_ctrl_pkt_filter_set(pf,
+			(struct rte_ctrl_pkt_filter *)arg,
+			TRUE);
+		break;
+	case RTE_ETH_FILTER_DELETE:
+		ret = i40e_ctrl_pkt_filter_set(pf,
+			(struct rte_ctrl_pkt_filter *)arg,
+			FALSE);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "unsupported operation %u\n", filter_op);
+		ret = -ENOSYS;
+		break;
+	}
+	return ret;
+}
+
 static int
 i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg)
 {
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	int ret = 0;
-	(void)filter_op;
-	(void)arg;
 
 	if (dev == NULL)
 		return -EINVAL;
 
 	switch (filter_type) {
+	case RTE_ETH_FILTER_CTRL_PKT:
+		ret = i40e_ctrl_pkt_filter_handle(pf, filter_op, arg);
+		break;
 	default:
 		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
 							filter_type);