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

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
...@@ -354,6 +354,7 @@ struct be_vf_cfg { ...@@ -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 {
......
...@@ -1918,7 +1918,7 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd, ...@@ -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, ...@@ -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;
......
...@@ -2256,7 +2256,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter, ...@@ -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);
......
...@@ -1171,7 +1171,7 @@ static int be_vid_config(struct be_adapter *adapter) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment