[dpdk-dev] [PATCH v15 1/2] i40e: add floating VEB support

Zhe Tao zhe.tao at intel.com
Wed Jun 29 15:06:02 CEST 2016


The standard Virtual Ethernet Bridge(VEB) definition in 1Qbg is a bridge
which has an uplink port to the outside world (maybe another bridge),
but a "floating" VEB is a special VEB without an uplink port to the
outside. Instead, traffic can be sent from one VF to another using the
floating VEB - even when the physical link on the NIC port is down.

VFs VSIs connect either to the standard VEB/VEPA or to the floating VEB,
they cannot connect to both of them. The PF, VMDQ and FD VSIs still
connect to the normal VEB/VEPA.

Signed-off-by: Zhe Tao <zhe.tao at intel.com>
---
 drivers/net/i40e/i40e_ethdev.c | 113 +++++++++++++++++++++++++++++++++--------
 drivers/net/i40e/i40e_ethdev.h |   7 +++
 drivers/net/i40e/i40e_pf.c     |  12 ++++-
 3 files changed, 108 insertions(+), 24 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index f94ad87..5efcbc2 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -3768,21 +3768,27 @@ i40e_veb_release(struct i40e_veb *veb)
 	struct i40e_vsi *vsi;
 	struct i40e_hw *hw;
 
-	if (veb == NULL || veb->associate_vsi == NULL)
+	if (veb == NULL)
 		return -EINVAL;
 
 	if (!TAILQ_EMPTY(&veb->head)) {
 		PMD_DRV_LOG(ERR, "VEB still has VSI attached, can't remove");
 		return -EACCES;
 	}
+	/* associate_vsi field is NULL for floating VEB */
+	if (veb->associate_vsi != NULL) {
+		vsi = veb->associate_vsi;
+		hw = I40E_VSI_TO_HW(vsi);
 
-	vsi = veb->associate_vsi;
-	hw = I40E_VSI_TO_HW(vsi);
+		vsi->uplink_seid = veb->uplink_seid;
+		vsi->veb = NULL;
+	} else {
+		veb->associate_pf->main_vsi->floating_veb = NULL;
+		hw = I40E_VSI_TO_HW(veb->associate_pf->main_vsi);
+	}
 
-	vsi->uplink_seid = veb->uplink_seid;
 	i40e_aq_delete_element(hw, veb->seid, NULL);
 	rte_free(veb);
-	vsi->veb = NULL;
 	return I40E_SUCCESS;
 }
 
@@ -3794,9 +3800,9 @@ i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi)
 	int ret;
 	struct i40e_hw *hw;
 
-	if (NULL == pf || vsi == NULL) {
-		PMD_DRV_LOG(ERR, "veb setup failed, "
-			    "associated VSI shouldn't null");
+	if (pf == NULL) {
+		PMD_DRV_LOG(ERR,
+			    "veb setup failed, associated PF shouldn't null");
 		return NULL;
 	}
 	hw = I40E_PF_TO_HW(pf);
@@ -3808,11 +3814,19 @@ i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi)
 	}
 
 	veb->associate_vsi = vsi;
+	veb->associate_pf = pf;
 	TAILQ_INIT(&veb->head);
-	veb->uplink_seid = vsi->uplink_seid;
+	veb->uplink_seid = vsi ? vsi->uplink_seid : 0;
 
-	ret = i40e_aq_add_veb(hw, veb->uplink_seid, vsi->seid,
-		I40E_DEFAULT_TCMAP, false, &veb->seid, false, NULL);
+	/* create floating veb if vsi is NULL */
+	if (vsi != NULL) {
+		ret = i40e_aq_add_veb(hw, veb->uplink_seid, vsi->seid,
+				      I40E_DEFAULT_TCMAP, false,
+				      &veb->seid, false, NULL);
+	} else {
+		ret = i40e_aq_add_veb(hw, 0, 0, I40E_DEFAULT_TCMAP,
+				      true, &veb->seid, false, NULL);
+	}
 
 	if (ret != I40E_SUCCESS) {
 		PMD_DRV_LOG(ERR, "Add veb failed, aq_err: %d",
@@ -3828,10 +3842,10 @@ i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi)
 			    hw->aq.asq_last_status);
 		goto fail;
 	}
-
 	/* Get VEB bandwidth, to be implemented */
 	/* Now associated vsi binding to the VEB, set uplink to this VEB */
-	vsi->uplink_seid = veb->seid;
+	if (vsi)
+		vsi->uplink_seid = veb->seid;
 
 	return veb;
 fail:
@@ -3847,6 +3861,7 @@ i40e_vsi_release(struct i40e_vsi *vsi)
 	struct i40e_vsi_list *vsi_list;
 	int ret;
 	struct i40e_mac_filter *f;
+	uint16_t user_param = vsi->user_param;
 
 	if (!vsi)
 		return I40E_SUCCESS;
@@ -3864,12 +3879,22 @@ i40e_vsi_release(struct i40e_vsi *vsi)
 		i40e_veb_release(vsi->veb);
 	}
 
+	if (vsi->floating_veb) {
+		TAILQ_FOREACH(vsi_list, &vsi->floating_veb->head, list) {
+			if (i40e_vsi_release(vsi_list->vsi) != I40E_SUCCESS)
+				return -1;
+			TAILQ_REMOVE(&vsi->floating_veb->head, vsi_list, list);
+		}
+	}
+
 	/* Remove all macvlan filters of the VSI */
 	i40e_vsi_remove_all_macvlan_filter(vsi);
 	TAILQ_FOREACH(f, &vsi->mac_list, next)
 		rte_free(f);
 
-	if (vsi->type != I40E_VSI_MAIN) {
+	if (vsi->type != I40E_VSI_MAIN &&
+	    ((vsi->type != I40E_VSI_SRIOV) ||
+	    !pf->floating_veb_list[user_param])) {
 		/* Remove vsi from parent's sibling list */
 		if (vsi->parent_vsi == NULL || vsi->parent_vsi->veb == NULL) {
 			PMD_DRV_LOG(ERR, "VSI's parent VSI is NULL");
@@ -3883,6 +3908,24 @@ i40e_vsi_release(struct i40e_vsi *vsi)
 		if (ret != I40E_SUCCESS)
 			PMD_DRV_LOG(ERR, "Failed to delete element");
 	}
+
+	if ((vsi->type == I40E_VSI_SRIOV) &&
+	    pf->floating_veb_list[user_param]) {
+		/* Remove vsi from parent's sibling list */
+		if (vsi->parent_vsi == NULL ||
+		    vsi->parent_vsi->floating_veb == NULL) {
+			PMD_DRV_LOG(ERR, "VSI's parent VSI is NULL");
+			return I40E_ERR_PARAM;
+		}
+		TAILQ_REMOVE(&vsi->parent_vsi->floating_veb->head,
+			     &vsi->sib_vsi_list, list);
+
+		/* Remove all switch element of the VSI */
+		ret = i40e_aq_delete_element(hw, vsi->seid, NULL);
+		if (ret != I40E_SUCCESS)
+			PMD_DRV_LOG(ERR, "Failed to delete element");
+	}
+
 	i40e_res_pool_free(&pf->qp_pool, vsi->base_queue);
 
 	if (vsi->type != I40E_VSI_SRIOV)
@@ -4051,7 +4094,8 @@ i40e_vsi_setup(struct i40e_pf *pf,
 	struct ether_addr broadcast =
 		{.addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
 
-	if (type != I40E_VSI_MAIN && uplink_vsi == NULL) {
+	if (type != I40E_VSI_MAIN && type != I40E_VSI_SRIOV &&
+	    uplink_vsi == NULL) {
 		PMD_DRV_LOG(ERR, "VSI setup failed, "
 			    "VSI link shouldn't be NULL");
 		return NULL;
@@ -4063,11 +4107,18 @@ i40e_vsi_setup(struct i40e_pf *pf,
 		return NULL;
 	}
 
-	/* If uplink vsi didn't setup VEB, create one first */
-	if (type != I40E_VSI_MAIN && uplink_vsi->veb == NULL) {
+	/* two situations
+	 * 1.type is not MAIN and uplink vsi is not NULL
+	 * If uplink vsi didn't setup VEB, create one first under veb field
+	 * 2.type is SRIOV and the uplink is NULL
+	 * If floating VEB is NULL, create one veb under floating veb field
+	 */
+
+	if (type != I40E_VSI_MAIN && uplink_vsi != NULL &&
+	    uplink_vsi->veb == NULL) {
 		uplink_vsi->veb = i40e_veb_setup(pf, uplink_vsi);
 
-		if (NULL == uplink_vsi->veb) {
+		if (uplink_vsi->veb == NULL) {
 			PMD_DRV_LOG(ERR, "VEB setup failed");
 			return NULL;
 		}
@@ -4075,6 +4126,16 @@ i40e_vsi_setup(struct i40e_pf *pf,
 		i40e_enable_pf_lb(pf);
 	}
 
+	if (type == I40E_VSI_SRIOV && uplink_vsi == NULL &&
+	    pf->main_vsi->floating_veb == NULL) {
+		pf->main_vsi->floating_veb = i40e_veb_setup(pf, uplink_vsi);
+
+		if (pf->main_vsi->floating_veb == NULL) {
+			PMD_DRV_LOG(ERR, "VEB setup failed");
+			return NULL;
+		}
+	}
+
 	vsi = rte_zmalloc("i40e_vsi", sizeof(struct i40e_vsi), 0);
 	if (!vsi) {
 		PMD_DRV_LOG(ERR, "Failed to allocate memory for vsi");
@@ -4084,7 +4145,7 @@ i40e_vsi_setup(struct i40e_pf *pf,
 	vsi->type = type;
 	vsi->adapter = I40E_PF_TO_ADAPTER(pf);
 	vsi->max_macaddrs = I40E_NUM_MACADDR_MAX;
-	vsi->parent_vsi = uplink_vsi;
+	vsi->parent_vsi = uplink_vsi ? uplink_vsi : pf->main_vsi;
 	vsi->user_param = user_param;
 	/* Allocate queues */
 	switch (vsi->type) {
@@ -4238,7 +4299,10 @@ i40e_vsi_setup(struct i40e_pf *pf,
 		 * For other VSI, the uplink_seid equals to uplink VSI's
 		 * uplink_seid since they share same VEB
 		 */
-		vsi->uplink_seid = uplink_vsi->uplink_seid;
+		if (uplink_vsi == NULL)
+			vsi->uplink_seid = pf->main_vsi->floating_veb->seid;
+		else
+			vsi->uplink_seid = uplink_vsi->uplink_seid;
 		ctxt.pf_num = hw->pf_id;
 		ctxt.vf_num = hw->func_caps.vf_base_id + user_param;
 		ctxt.uplink_seid = vsi->uplink_seid;
@@ -4346,8 +4410,13 @@ i40e_vsi_setup(struct i40e_pf *pf,
 		vsi->seid = ctxt.seid;
 		vsi->vsi_id = ctxt.vsi_number;
 		vsi->sib_vsi_list.vsi = vsi;
-		TAILQ_INSERT_TAIL(&uplink_vsi->veb->head,
-				&vsi->sib_vsi_list, list);
+		if (vsi->type == I40E_VSI_SRIOV && uplink_vsi == NULL) {
+			TAILQ_INSERT_TAIL(&pf->main_vsi->floating_veb->head,
+					  &vsi->sib_vsi_list, list);
+		} else {
+			TAILQ_INSERT_TAIL(&uplink_vsi->veb->head,
+					  &vsi->sib_vsi_list, list);
+		}
 	}
 
 	/* MAC/VLAN configuration */
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index cfd2399..19c9dea 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -55,6 +55,8 @@
 #define I40E_VFTA_SIZE            (4096 / I40E_UINT32_BIT_SIZE)
 /* Maximun number of MAC addresses */
 #define I40E_NUM_MACADDR_MAX       64
+/* Maximum number of VFs */
+#define I40E_MAX_VF               128
 
 /*
  * vlan_id is a 12 bit number.
@@ -219,6 +221,7 @@ struct i40e_bw_info {
 struct i40e_veb {
 	struct i40e_vsi_list_head head;
 	struct i40e_vsi *associate_vsi; /* Associate VSI who owns the VEB */
+	struct i40e_pf *associate_pf; /* Associate PF who owns the VEB */
 	uint16_t seid; /* The seid of VEB itself */
 	uint16_t uplink_seid; /* The uplink seid of this VEB */
 	uint16_t stats_idx;
@@ -259,6 +262,7 @@ struct i40e_vsi {
 	struct i40e_vsi_list sib_vsi_list; /* sibling vsi list */
 	struct i40e_vsi *parent_vsi;
 	struct i40e_veb *veb;    /* Associated veb, could be null */
+	struct i40e_veb *floating_veb; /* Associated floating veb */
 	bool offset_loaded;
 	enum i40e_vsi_type type; /* VSI types */
 	uint16_t vlan_num;       /* Total VLAN number */
@@ -450,6 +454,9 @@ struct i40e_pf {
 	struct i40e_fc_conf fc_conf; /* Flow control conf */
 	struct i40e_mirror_rule_list mirror_list;
 	uint16_t nb_mirror_rule;   /* The number of mirror rules */
+	bool floating_veb; /* The flag to use the floating VEB */
+	/* The floating enable flag for the specific VF */
+	bool floating_veb_list[I40E_MAX_VF];
 };
 
 enum pending_msg {
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 5afd61a..dc5b079 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -124,6 +124,7 @@ i40e_pf_host_vf_reset(struct i40e_pf_vf *vf, bool do_hw_reset)
 {
 	uint32_t val, i;
 	struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
+	struct i40e_pf *pf;
 	uint16_t vf_id, abs_vf_id, vf_msix_num;
 	int ret;
 	struct i40e_virtchnl_queue_select qsel;
@@ -131,6 +132,7 @@ i40e_pf_host_vf_reset(struct i40e_pf_vf *vf, bool do_hw_reset)
 	if (vf == NULL)
 		return -EINVAL;
 
+	pf = vf->pf;
 	vf_id = vf->vf_idx;
 	abs_vf_id = vf_id + hw->func_caps.vf_base_id;
 
@@ -224,8 +226,14 @@ i40e_pf_host_vf_reset(struct i40e_pf_vf *vf, bool do_hw_reset)
 	I40E_WRITE_FLUSH(hw);
 
 	/* Allocate resource again */
-	vf->vsi = i40e_vsi_setup(vf->pf, I40E_VSI_SRIOV,
-			vf->pf->main_vsi, vf->vf_idx);
+	if (pf->floating_veb && pf->floating_veb_list[vf_id]) {
+		vf->vsi = i40e_vsi_setup(vf->pf, I40E_VSI_SRIOV,
+					 NULL, vf->vf_idx);
+	} else {
+		vf->vsi = i40e_vsi_setup(vf->pf, I40E_VSI_SRIOV,
+					 vf->pf->main_vsi, vf->vf_idx);
+	}
+
 	if (vf->vsi == NULL) {
 		PMD_DRV_LOG(ERR, "Add vsi failed");
 		return -EFAULT;
-- 
2.1.4



More information about the dev mailing list