All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jingjing Wu <jingjing.wu@intel.com>
To: dev@dpdk.org
Subject: [PATCH 3/3] i40e: enable mirror functionality in i40e driver
Date: Wed, 13 May 2015 16:47:04 +0800	[thread overview]
Message-ID: <1431506824-23032-4-git-send-email-jingjing.wu@intel.com> (raw)
In-Reply-To: <1431506824-23032-1-git-send-email-jingjing.wu@intel.com>

enable mirror functionality in i40e driver
.mirror_rule_set
.mirror_rule_reset

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 334 ++++++++++++++++++++++++++++++++++++++
 lib/librte_pmd_i40e/i40e_ethdev.h |  23 +++
 2 files changed, 357 insertions(+)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 43762f2..981e7ac 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -211,6 +211,10 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				void *arg);
 static void i40e_configure_registers(struct i40e_hw *hw);
 static void i40e_hw_init(struct i40e_hw *hw);
+static int i40e_mirror_rule_set(struct rte_eth_dev *dev,
+			struct rte_eth_mirror_conf *mirror_conf,
+			uint8_t sw_id, uint8_t on);
+static int i40e_mirror_rule_reset(struct rte_eth_dev *dev, uint8_t sw_id);
 
 static const struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -262,6 +266,8 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.udp_tunnel_add               = i40e_dev_udp_tunnel_add,
 	.udp_tunnel_del               = i40e_dev_udp_tunnel_del,
 	.filter_ctrl                  = i40e_dev_filter_ctrl,
+	.mirror_rule_set              = i40e_mirror_rule_set,
+	.mirror_rule_reset            = i40e_mirror_rule_reset,
 };
 
 static struct eth_driver rte_i40e_pmd = {
@@ -563,6 +569,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
 	/* enable uio intr after callback register */
 	rte_intr_enable(&(pci_dev->intr_handle));
 
+	/* initialize mirror rule list */
+	TAILQ_INIT(&pf->mirror_list);
+
 	return 0;
 
 err_mac_alloc:
@@ -925,6 +934,7 @@ i40e_dev_stop(struct rte_eth_dev *dev)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct i40e_vsi *main_vsi = pf->main_vsi;
+	struct i40e_mirror_rule *p_mirror;
 	int i;
 
 	/* Disable all queues */
@@ -949,6 +959,13 @@ i40e_dev_stop(struct rte_eth_dev *dev)
 	/* Set link down */
 	i40e_dev_set_link_down(dev);
 
+	/* Remove all mirror rules */
+	while ((p_mirror = TAILQ_FIRST(&pf->mirror_list))) {
+		TAILQ_REMOVE(&pf->mirror_list, p_mirror, rules);
+		rte_free(p_mirror);
+	}
+	pf->nb_mirror_rule = 0;
+
 }
 
 static void
@@ -5714,3 +5731,320 @@ i40e_configure_registers(struct i40e_hw *hw)
 			"0x%"PRIx32, reg_table[i].val, reg_table[i].addr);
 	}
 }
+
+/**
+ * i40e_aq_add_mirror_rule
+ * @hw: pointer to the hardware structure
+ * @seid: VEB seid to add mirror rule to
+ * @dst_id: destination vsi seid
+ * @entries: Buffer which contains the entities to be mirrored
+ * @count: number of entities contained in the buffer
+ * @rule_id:the rule_id of the rule to be added
+ *
+ * Add a mirror rule for a given veb.
+ *
+ **/
+static enum
+i40e_status_code i40e_aq_add_mirror_rule(struct i40e_hw *hw,
+			uint16_t seid, uint16_t dst_id,
+			uint16_t rule_type, uint16_t *entries,
+			uint16_t count, uint16_t *rule_id)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_add_delete_mirror_rule *cmd =
+		(struct i40e_aqc_add_delete_mirror_rule *)&desc.params.raw;
+	struct i40e_aqc_add_delete_mirror_rule_completion *resp =
+		(struct i40e_aqc_add_delete_mirror_rule_completion *)
+		&desc.params.raw;
+	uint16_t buff_len;
+	enum i40e_status_code status;
+
+	i40e_fill_default_direct_cmd_desc(&desc,
+					  i40e_aqc_opc_add_mirror_rule);
+
+	buff_len = sizeof(uint16_t) * count;
+	desc.datalen = rte_cpu_to_le_16(buff_len);
+	if (buff_len > 0)
+		desc.flags |= rte_cpu_to_le_16(
+			(uint16_t)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
+	cmd->rule_type = rte_cpu_to_le_16(rule_type <<
+				I40E_AQC_MIRROR_RULE_TYPE_SHIFT);
+	cmd->num_entries = rte_cpu_to_le_16(count);
+	cmd->seid = rte_cpu_to_le_16(seid);
+	cmd->destination = rte_cpu_to_le_16(dst_id);
+
+	status = i40e_asq_send_command(hw, &desc, entries, buff_len, NULL);
+	PMD_DRV_LOG(INFO, "i40e_aq_add_mirror_rule, aq_status %d,"
+			 "rule_id = %u"
+			 " mirror_rules_used = %u, mirror_rules_free = %u,",
+			 hw->aq.asq_last_status, resp->rule_id,
+			 resp->mirror_rules_used, resp->mirror_rules_free);
+	*rule_id = rte_le_to_cpu_16(resp->rule_id);
+
+	return status;
+}
+
+/**
+ * i40e_aq_del_mirror_rule
+ * @hw: pointer to the hardware structure
+ * @seid: VEB seid to add mirror rule to
+ * @entries: Buffer which contains the entities to be mirrored
+ * @count: number of entities contained in the buffer
+ * @rule_id:the rule_id of the rule to be delete
+ *
+ * Delete a mirror rule for a given veb.
+ *
+ **/
+static enum
+i40e_status_code i40e_aq_del_mirror_rule(struct i40e_hw *hw,
+		uint16_t seid, uint16_t rule_type, uint16_t *entries,
+		uint16_t count, uint16_t rule_id)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_add_delete_mirror_rule *cmd =
+		(struct i40e_aqc_add_delete_mirror_rule *)&desc.params.raw;
+	uint16_t buff_len = 0;
+	enum i40e_status_code status;
+	void *buff = NULL;
+
+	i40e_fill_default_direct_cmd_desc(&desc,
+					  i40e_aqc_opc_delete_mirror_rule);
+
+	if (rule_type == I40E_AQC_MIRROR_RULE_TYPE_VLAN) {
+		desc.flags |= rte_cpu_to_le_16((uint16_t)(I40E_AQ_FLAG_BUF |
+							  I40E_AQ_FLAG_RD));
+		cmd->num_entries = count;
+		buff_len = sizeof(uint16_t) * count;
+		desc.datalen = rte_cpu_to_le_16(buff_len);
+		buff = (void *)entries;
+	} else
+		/* rule id is filled in destination field for deleting mirror rule */
+		cmd->destination = rte_cpu_to_le_16(rule_id);
+
+	cmd->rule_type = rte_cpu_to_le_16(rule_type <<
+				I40E_AQC_MIRROR_RULE_TYPE_SHIFT);
+	cmd->seid = rte_cpu_to_le_16(seid);
+
+	status = i40e_asq_send_command(hw, &desc, buff, buff_len, NULL);
+
+	return status;
+}
+
+/**
+ * i40e_mirror_rule_set
+ * @dev: pointer to the hardware structure
+ * @mirror_conf: mirror rule info
+ * @sw_id: mirror rule's sw_id
+ * @on: enable/disable
+ *
+ * set a mirror rule.
+ *
+ **/
+static int
+i40e_mirror_rule_set(struct rte_eth_dev *dev,
+			struct rte_eth_mirror_conf *mirror_conf,
+			uint8_t sw_id, uint8_t on)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_mirror_rule *it, *mirr_rule = NULL;
+	struct i40e_mirror_rule *parent = NULL;
+	uint16_t seid, dst_seid, rule_id;
+	uint16_t i, j = 0;
+	int ret;
+
+	PMD_DRV_LOG(DEBUG, "i40e_mirror_rule_set: sw_id = %d.", sw_id);
+
+	if (pf->main_vsi->veb == NULL || pf->vfs == NULL) {
+		PMD_DRV_LOG(ERR, "mirror rule can not be configured"
+			" without veb or vfs.");
+		return -ENOSYS;
+	}
+	if (pf->nb_mirror_rule > I40E_MAX_NUM_MIRROR_RULE) {
+		PMD_DRV_LOG(ERR, "mirror table is full.");
+		return -ENOSYS;
+	}
+	if (mirror_conf->dst_pool > pf->vf_num) {
+		PMD_DRV_LOG(ERR, "invalid destination pool %u.",
+				 mirror_conf->dst_pool);
+		return -EINVAL;
+	}
+
+	seid = pf->main_vsi->veb->seid;
+
+	TAILQ_FOREACH(it, &pf->mirror_list, rules) {
+		if (sw_id <= it->index) {
+			mirr_rule = it;
+			break;
+		}
+		parent = it;
+	}
+	if (mirr_rule && sw_id == mirr_rule->index) {
+		if (on) {
+			PMD_DRV_LOG(ERR, "mirror rule exists.");
+			return -EEXIST;
+		} else {
+			ret = i40e_aq_del_mirror_rule(hw, seid,
+					mirr_rule->rule_type,
+					mirr_rule->entries,
+					mirr_rule->num_entries, mirr_rule->id);
+			if (ret < 0) {
+				PMD_DRV_LOG(ERR, "failed to remove mirror rule:"
+						   " ret = %d, aq_err = %d.",
+						   ret, hw->aq.asq_last_status);
+				return -ENOSYS;
+			}
+			TAILQ_REMOVE(&pf->mirror_list, mirr_rule, rules);
+			rte_free(mirr_rule);
+			pf->nb_mirror_rule--;
+			return 0;
+		}
+	} else if (!on) {
+		PMD_DRV_LOG(ERR, "mirror rule doesn't exist.");
+		return -ENOENT;
+	}
+
+	mirr_rule = rte_zmalloc("i40e_mirror_rule",
+				sizeof(struct i40e_mirror_rule) , 0);
+	if (!mirr_rule) {
+		PMD_DRV_LOG(ERR, "failed to allocate memory");
+		return I40E_ERR_NO_MEMORY;
+	}
+	switch (mirror_conf->rule_type) {
+	case ETH_MIRROR_VLAN:
+		for (i = 0, j = 0; i < ETH_MIRROR_MAX_NUM_VLANS; i++) {
+			if (mirror_conf->vlan.vlan_mask & (1ULL << i)) {
+				mirr_rule->entries[j] =
+					mirror_conf->vlan.vlan_id[i];
+				j++;
+			}
+		}
+		if (j == 0) {
+			PMD_DRV_LOG(ERR, "vlan is not specified.");
+			rte_free(mirr_rule);
+			return -EINVAL;
+		}
+		mirr_rule->rule_type = I40E_AQC_MIRROR_RULE_TYPE_VLAN;
+		break;
+	case ETH_MIRROR_VIRTUAL_POOL_UP:
+	case ETH_MIRROR_VIRTUAL_POOL_DOWN:
+		/* check if the specified pool bit is out of range */
+		if (mirror_conf->pool_mask > (uint64_t)(1ULL << (pf->vf_num + 1))) {
+			PMD_DRV_LOG(ERR, "pool mask is out of range.");
+			rte_free(mirr_rule);
+			return -EINVAL;
+		}
+		for (i = 0, j = 0; i < pf->vf_num; i++) {
+			if (mirror_conf->pool_mask & (1ULL << i)) {
+				mirr_rule->entries[j] = pf->vfs[i].vsi->seid;
+				j++;
+			}
+		}
+		if (mirror_conf->pool_mask & (1ULL << pf->vf_num)) {
+			/* add pf vsi to entries */
+			mirr_rule->entries[j] = pf->main_vsi_seid;
+			j++;
+		}
+		if (j == 0) {
+			PMD_DRV_LOG(ERR, "pool is not specified.");
+			rte_free(mirr_rule);
+			return -EINVAL;
+		}
+		/* egress and ingress in aq commands means from switch but not port */
+		mirr_rule->rule_type =
+			(mirror_conf->rule_type == ETH_MIRROR_VIRTUAL_POOL_UP) ?
+			I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS :
+			I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS;
+		break;
+	case ETH_MIRROR_UPLINK_PORT:
+		/* egress and ingress in aq commands means from switch but not port*/
+		mirr_rule->rule_type = I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS;
+		break;
+	case ETH_MIRROR_DOWNLINK_PORT:
+		mirr_rule->rule_type = I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "unsupported mirror type %d.",
+			mirror_conf->rule_type);
+		rte_free(mirr_rule);
+		return -EINVAL;
+	}
+
+	/* If the dst_pool is equal to vf_num, consider it as PF */
+	if (mirror_conf->dst_pool == pf->vf_num)
+		dst_seid = pf->main_vsi_seid;
+	else
+		dst_seid = pf->vfs[mirror_conf->dst_pool].vsi->seid;
+
+	ret = i40e_aq_add_mirror_rule(hw, seid, dst_seid,
+				      mirr_rule->rule_type, mirr_rule->entries,
+				      j, &rule_id);
+	if (ret < 0) {
+		PMD_DRV_LOG(ERR, "failed to add mirror rule:"
+				   " ret = %d, aq_err = %d.",
+				   ret, hw->aq.asq_last_status);
+		rte_free(mirr_rule);
+		return -ENOSYS;
+	}
+
+	mirr_rule->index = sw_id;
+	mirr_rule->num_entries = j;
+	mirr_rule->id = rule_id;
+	mirr_rule->dst_vsi_seid = dst_seid;
+
+	if (parent)
+		TAILQ_INSERT_AFTER(&pf->mirror_list, parent, mirr_rule, rules);
+	else
+		TAILQ_INSERT_HEAD(&pf->mirror_list, mirr_rule, rules);
+
+	pf->nb_mirror_rule++;
+	return 0;
+}
+
+/**
+ * i40e_mirror_rule_reset
+ * @dev: pointer to the device
+ * @sw_id: mirror rule's sw_id
+ *
+ * reset a mirror rule.
+ *
+ **/
+static int
+i40e_mirror_rule_reset(struct rte_eth_dev *dev, uint8_t sw_id)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_mirror_rule *it, *mirr_rule = NULL;
+	uint16_t seid;
+	int ret;
+
+	PMD_DRV_LOG(DEBUG, "i40e_mirror_rule_reset: sw_id = %d.", sw_id);
+
+	seid = pf->main_vsi->veb->seid;
+
+	TAILQ_FOREACH(it, &pf->mirror_list, rules) {
+		if (sw_id == it->index) {
+			mirr_rule = it;
+			break;
+		}
+	}
+	if (mirr_rule) {
+		ret = i40e_aq_del_mirror_rule(hw, seid,
+				mirr_rule->rule_type,
+				mirr_rule->entries,
+				mirr_rule->num_entries, mirr_rule->id);
+		if (ret < 0) {
+			PMD_DRV_LOG(ERR, "failed to remove mirror rule:"
+					   " status = %d, aq_err = %d.",
+					   ret, hw->aq.asq_last_status);
+			return -ENOSYS;
+		}
+		TAILQ_REMOVE(&pf->mirror_list, mirr_rule, rules);
+		rte_free(mirr_rule);
+		pf->nb_mirror_rule--;
+	} else {
+		PMD_DRV_LOG(ERR, "mirror rule doesn't exist.");
+		return -ENOENT;
+	}
+	return 0;
+}
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h
index b9bed5a..ffd70d3 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.h
+++ b/lib/librte_pmd_i40e/i40e_ethdev.h
@@ -323,6 +323,27 @@ struct i40e_fdir_info {
 	struct i40e_fdir_flex_mask flex_mask[I40E_FILTER_PCTYPE_MAX];
 };
 
+#define I40E_MIRROR_MAX_ENTRIES_PER_RULE   64
+#define I40E_MAX_NUM_MIRROR_RULE           32
+/*
+ * Mirror rule structure
+ */
+struct i40e_mirror_rule {
+	TAILQ_ENTRY(i40e_mirror_rule) rules;
+	uint8_t rule_type;
+	uint16_t index;          /* the sw index of mirror rule */
+	uint16_t id;             /* the rule id assigned by firmware */
+	uint16_t dst_vsi_seid;   /* destination vsi for this mirror rule. */
+	uint16_t num_entries;
+	/* the info stores depend on the rule type.
+	    If type is I40E_MIRROR_TYPE_VLAN, vlan ids are stored here.
+	    If type is I40E_MIRROR_TYPE_VPORT_*, vsi's seid are stored.
+	 */
+	uint16_t entries[I40E_MIRROR_MAX_ENTRIES_PER_RULE];
+};
+
+TAILQ_HEAD(i40e_mirror_rule_list, i40e_mirror_rule);
+
 /*
  * Structure to store private data specific for PF instance.
  */
@@ -362,6 +383,8 @@ struct i40e_pf {
 	struct i40e_vmdq_info *vmdq;
 
 	struct i40e_fdir_info fdir; /* flow director info */
+	struct i40e_mirror_rule_list mirror_list;
+	uint16_t nb_mirror_rule;   /* The number of mirror rules */
 };
 
 enum pending_msg {
-- 
1.9.3

  parent reply	other threads:[~2015-05-13  8:47 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-13  8:47 [PATCH 0/3] enable mirror functionality in i40e driver Jingjing Wu
2015-05-13  8:47 ` [PATCH 1/3] ethdev: rename rte_eth_vmdq_mirror_conf Jingjing Wu
2015-06-02  2:50   ` Liu, Jijiang
2015-05-13  8:47 ` [PATCH 2/3] ethdev: redefine the mirror type Jingjing Wu
2015-05-13  8:47 ` Jingjing Wu [this message]
2015-06-02  7:55 ` [PATCH v2 0/4] enable mirror functionality in i40e driver Jingjing Wu
2015-06-02  7:55   ` [PATCH v2 1/4] ethdev: rename rte_eth_vmdq_mirror_conf Jingjing Wu
2015-06-02  7:55   ` [PATCH v2 2/4] ethdev: redefine the mirror type Jingjing Wu
2015-06-02  7:55   ` [PATCH v2 3/4] i40e: enable mirror functionality in i40e driver Jingjing Wu
2015-06-02  7:56   ` [PATCH v2 4/4] doc: modify the command about mirror in testpmd guide Jingjing Wu
2015-06-05  8:16   ` [PATCH v3 0/4] enable mirror functionality in i40e driver Jingjing Wu
2015-06-05  8:16     ` [PATCH v3 1/4] ethdev: rename rte_eth_vmdq_mirror_conf Jingjing Wu
2015-06-05  8:16     ` [PATCH v3 2/4] ethdev: redefine the mirror type Jingjing Wu
2015-06-05  8:16     ` [PATCH v3 3/4] i40e: enable mirror functionality in i40e driver Jingjing Wu
2015-06-05  8:16     ` [PATCH v3 4/4] doc: modify the command about mirror in testpmd guide Jingjing Wu
2015-06-10  6:24     ` [PATCH v4 0/4] enable mirror functionality in i40e driver Jingjing Wu
2015-06-10  6:24       ` [PATCH v4 1/4] ethdev: rename rte_eth_vmdq_mirror_conf Jingjing Wu
2015-06-26  7:03         ` Wu, Jingjing
2015-07-06  1:27           ` Wu, Jingjing
2015-07-07 14:51           ` Thomas Monjalon
2015-07-08  0:58             ` Wu, Jingjing
2015-07-08 10:31             ` Mcnamara, John
2015-07-08 10:35               ` Bruce Richardson
2015-06-10  6:24       ` [PATCH v4 2/4] ethdev: rename and extend the mirror type Jingjing Wu
2015-06-10  6:24       ` [PATCH v4 3/4] i40e: enable mirror functionality in i40e driver Jingjing Wu
2015-06-10  6:24       ` [PATCH v4 4/4] doc: modify the command about mirror in testpmd guide Jingjing Wu
2015-06-10  8:33       ` [PATCH v4 0/4] enable mirror functionality in i40e driver Jiajia, SunX
2015-06-12  8:18       ` Liu, Jijiang
2015-06-12  8:44       ` Zhang, Helin
2015-07-07 15:46         ` Thomas Monjalon
  -- strict thread matches above, loose matches on Subject: below --
2015-05-13  8:38 Jingjing Wu
2015-05-13  8:38 ` [PATCH 3/3] i40e: " Jingjing Wu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1431506824-23032-4-git-send-email-jingjing.wu@intel.com \
    --to=jingjing.wu@intel.com \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.