Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 435452aa authored by Vasundhara Volam's avatar Vasundhara Volam Committed by David S. Miller
Browse files

be2net: Prevent VFs from enabling VLAN promiscuous mode



Currently, a PF does not restrict its VF interface from enabling vlan
promiscuous mode. This breaks vlan isolation when a vlan
(transparent tagging) is configured on a VF.

This patch fixes this problem by disabling the vlan promisc capability
for VFs.

Reported-by: default avatarYoann Juet <veilletechno-irts@univ-nantes.fr>
Signed-off-by: default avatarVasundhara Volam <vasundhara.volam@emulex.com>
Signed-off-by: default avatarSathya Perla <sathya.perla@emulex.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d22e1537
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -354,6 +354,7 @@ struct be_vf_cfg {
	u16 vlan_tag;
	u16 vlan_tag;
	u32 tx_rate;
	u32 tx_rate;
	u32 plink_tracking;
	u32 plink_tracking;
	u32 privileges;
};
};


enum vf_state {
enum vf_state {
+2 −1
Original line number Original line Diff line number Diff line
@@ -1918,7 +1918,7 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,


/* Uses sycnhronous mcc */
/* Uses sycnhronous mcc */
int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
		       u32 num)
		       u32 num, u32 domain)
{
{
	struct be_mcc_wrb *wrb;
	struct be_mcc_wrb *wrb;
	struct be_cmd_req_vlan_config *req;
	struct be_cmd_req_vlan_config *req;
@@ -1936,6 +1936,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
	be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
	be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
			       OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req),
			       OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req),
			       wrb, NULL);
			       wrb, NULL);
	req->hdr.domain = domain;


	req->interface_id = if_id;
	req->interface_id = if_id;
	req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0;
	req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0;
+1 −1
Original line number Original line Diff line number Diff line
@@ -2256,7 +2256,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
int be_cmd_get_fw_ver(struct be_adapter *adapter);
int be_cmd_get_fw_ver(struct be_adapter *adapter);
int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *, int num);
int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *, int num);
int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
		       u32 num);
		       u32 num, u32 domain);
int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc);
int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc);
int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc);
int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc);
+76 −22
Original line number Original line Diff line number Diff line
@@ -1171,7 +1171,7 @@ static int be_vid_config(struct be_adapter *adapter)
	for_each_set_bit(i, adapter->vids, VLAN_N_VID)
	for_each_set_bit(i, adapter->vids, VLAN_N_VID)
		vids[num++] = cpu_to_le16(i);
		vids[num++] = cpu_to_le16(i);


	status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num);
	status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num, 0);
	if (status) {
	if (status) {
		dev_err(dev, "Setting HW VLAN filtering failed\n");
		dev_err(dev, "Setting HW VLAN filtering failed\n");
		/* Set to VLAN promisc mode as setting VLAN filter failed */
		/* Set to VLAN promisc mode as setting VLAN filter failed */
@@ -1380,11 +1380,67 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
	return 0;
	return 0;
}
}


static int be_set_vf_tvt(struct be_adapter *adapter, int vf, u16 vlan)
{
	struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
	u16 vids[BE_NUM_VLANS_SUPPORTED];
	int vf_if_id = vf_cfg->if_handle;
	int status;

	/* Enable Transparent VLAN Tagging */
	status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, vf_if_id, 0);
	if (status)
		return status;

	/* Clear pre-programmed VLAN filters on VF if any, if TVT is enabled */
	vids[0] = 0;
	status = be_cmd_vlan_config(adapter, vf_if_id, vids, 1, vf + 1);
	if (!status)
		dev_info(&adapter->pdev->dev,
			 "Cleared guest VLANs on VF%d", vf);

	/* After TVT is enabled, disallow VFs to program VLAN filters */
	if (vf_cfg->privileges & BE_PRIV_FILTMGMT) {
		status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges &
						  ~BE_PRIV_FILTMGMT, vf + 1);
		if (!status)
			vf_cfg->privileges &= ~BE_PRIV_FILTMGMT;
	}
	return 0;
}

static int be_clear_vf_tvt(struct be_adapter *adapter, int vf)
{
	struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
	struct device *dev = &adapter->pdev->dev;
	int status;

	/* Reset Transparent VLAN Tagging. */
	status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID, vf + 1,
				       vf_cfg->if_handle, 0);
	if (status)
		return status;

	/* Allow VFs to program VLAN filtering */
	if (!(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
		status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges |
						  BE_PRIV_FILTMGMT, vf + 1);
		if (!status) {
			vf_cfg->privileges |= BE_PRIV_FILTMGMT;
			dev_info(dev, "VF%d: FILTMGMT priv enabled", vf);
		}
	}

	dev_info(dev,
		 "Disable/re-enable i/f in VM to clear Transparent VLAN tag");
	return 0;
}

static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
{
{
	struct be_adapter *adapter = netdev_priv(netdev);
	struct be_adapter *adapter = netdev_priv(netdev);
	struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
	struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
	int status = 0;
	int status;


	if (!sriov_enabled(adapter))
	if (!sriov_enabled(adapter))
		return -EPERM;
		return -EPERM;
@@ -1394,24 +1450,19 @@ static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)


	if (vlan || qos) {
	if (vlan || qos) {
		vlan |= qos << VLAN_PRIO_SHIFT;
		vlan |= qos << VLAN_PRIO_SHIFT;
		if (vf_cfg->vlan_tag != vlan)
		status = be_set_vf_tvt(adapter, vf, vlan);
			status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
						       vf_cfg->if_handle, 0);
	} else {
	} else {
		/* Reset Transparent Vlan Tagging. */
		status = be_clear_vf_tvt(adapter, vf);
		status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
					       vf + 1, vf_cfg->if_handle, 0);
	}
	}


	if (status) {
	if (status) {
		dev_err(&adapter->pdev->dev,
		dev_err(&adapter->pdev->dev,
			"VLAN %d config on VF %d failed : %#x\n", vlan,
			"VLAN %d config on VF %d failed : %#x\n", vlan, vf,
			vf, status);
			status);
		return be_cmd_status(status);
		return be_cmd_status(status);
	}
	}


	vf_cfg->vlan_tag = vlan;
	vf_cfg->vlan_tag = vlan;

	return 0;
	return 0;
}
}


@@ -3339,7 +3390,6 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
			u32 cap_flags, u32 vf)
			u32 cap_flags, u32 vf)
{
{
	u32 en_flags;
	u32 en_flags;
	int status;


	en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
	en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
		   BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
		   BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
@@ -3347,10 +3397,7 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,


	en_flags &= cap_flags;
	en_flags &= cap_flags;


	status = be_cmd_if_create(adapter, cap_flags, en_flags,
	return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf);
				  if_handle, vf);

	return status;
}
}


static int be_vfs_if_create(struct be_adapter *adapter)
static int be_vfs_if_create(struct be_adapter *adapter)
@@ -3368,8 +3415,13 @@ static int be_vfs_if_create(struct be_adapter *adapter)
		if (!BE3_chip(adapter)) {
		if (!BE3_chip(adapter)) {
			status = be_cmd_get_profile_config(adapter, &res,
			status = be_cmd_get_profile_config(adapter, &res,
							   vf + 1);
							   vf + 1);
			if (!status)
			if (!status) {
				cap_flags = res.if_cap_flags;
				cap_flags = res.if_cap_flags;
				/* Prevent VFs from enabling VLAN promiscuous
				 * mode
				 */
				cap_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS;
			}
		}
		}


		status = be_if_create(adapter, &vf_cfg->if_handle,
		status = be_if_create(adapter, &vf_cfg->if_handle,
@@ -3403,7 +3455,6 @@ static int be_vf_setup(struct be_adapter *adapter)
	struct device *dev = &adapter->pdev->dev;
	struct device *dev = &adapter->pdev->dev;
	struct be_vf_cfg *vf_cfg;
	struct be_vf_cfg *vf_cfg;
	int status, old_vfs, vf;
	int status, old_vfs, vf;
	u32 privileges;


	old_vfs = pci_num_vf(adapter->pdev);
	old_vfs = pci_num_vf(adapter->pdev);


@@ -3433,16 +3484,19 @@ static int be_vf_setup(struct be_adapter *adapter)


	for_all_vfs(adapter, vf_cfg, vf) {
	for_all_vfs(adapter, vf_cfg, vf) {
		/* Allow VFs to programs MAC/VLAN filters */
		/* Allow VFs to programs MAC/VLAN filters */
		status = be_cmd_get_fn_privileges(adapter, &privileges, vf + 1);
		status = be_cmd_get_fn_privileges(adapter, &vf_cfg->privileges,
		if (!status && !(privileges & BE_PRIV_FILTMGMT)) {
						  vf + 1);
		if (!status && !(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
			status = be_cmd_set_fn_privileges(adapter,
			status = be_cmd_set_fn_privileges(adapter,
							  privileges |
							  vf_cfg->privileges |
							  BE_PRIV_FILTMGMT,
							  BE_PRIV_FILTMGMT,
							  vf + 1);
							  vf + 1);
			if (!status)
			if (!status) {
				vf_cfg->privileges |= BE_PRIV_FILTMGMT;
				dev_info(dev, "VF%d has FILTMGMT privilege\n",
				dev_info(dev, "VF%d has FILTMGMT privilege\n",
					 vf);
					 vf);
			}
			}
		}


		/* Allow full available bandwidth */
		/* Allow full available bandwidth */
		if (!old_vfs)
		if (!old_vfs)