Commit e8379c79 authored by Yuval Mintz's avatar Yuval Mintz Committed by David S. Miller

bnx2x: fix VLAN configuration for VFs.

If the hypervisor configures a vlan for the VF via the PF, the expected
result is that only packets tagged by said vlan will be received by the VF
(and that vlan will be silently removed).
Due to an incorrect manipulation of vlan filters in the driver, the
VF can receive untagged traffic even if the hypervisor configured
some vlan for it.

This patch corrects the behaviour.
Signed-off-by: default avatarYuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: default avatarAriel Elior <ariele@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9dfef3ad
...@@ -2038,6 +2038,7 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp, ...@@ -2038,6 +2038,7 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
struct bnx2x_vlan_mac_ramrod_params p; struct bnx2x_vlan_mac_ramrod_params p;
struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; struct bnx2x_exe_queue_obj *exeq = &o->exe_queue;
struct bnx2x_exeq_elem *exeq_pos, *exeq_pos_n; struct bnx2x_exeq_elem *exeq_pos, *exeq_pos_n;
unsigned long flags;
int read_lock; int read_lock;
int rc = 0; int rc = 0;
...@@ -2046,8 +2047,9 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp, ...@@ -2046,8 +2047,9 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
spin_lock_bh(&exeq->lock); spin_lock_bh(&exeq->lock);
list_for_each_entry_safe(exeq_pos, exeq_pos_n, &exeq->exe_queue, link) { list_for_each_entry_safe(exeq_pos, exeq_pos_n, &exeq->exe_queue, link) {
if (exeq_pos->cmd_data.vlan_mac.vlan_mac_flags == flags = exeq_pos->cmd_data.vlan_mac.vlan_mac_flags;
*vlan_mac_flags) { if (BNX2X_VLAN_MAC_CMP_FLAGS(flags) ==
BNX2X_VLAN_MAC_CMP_FLAGS(*vlan_mac_flags)) {
rc = exeq->remove(bp, exeq->owner, exeq_pos); rc = exeq->remove(bp, exeq->owner, exeq_pos);
if (rc) { if (rc) {
BNX2X_ERR("Failed to remove command\n"); BNX2X_ERR("Failed to remove command\n");
...@@ -2080,7 +2082,9 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp, ...@@ -2080,7 +2082,9 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
return read_lock; return read_lock;
list_for_each_entry(pos, &o->head, link) { list_for_each_entry(pos, &o->head, link) {
if (pos->vlan_mac_flags == *vlan_mac_flags) { flags = pos->vlan_mac_flags;
if (BNX2X_VLAN_MAC_CMP_FLAGS(flags) ==
BNX2X_VLAN_MAC_CMP_FLAGS(*vlan_mac_flags)) {
p.user_req.vlan_mac_flags = pos->vlan_mac_flags; p.user_req.vlan_mac_flags = pos->vlan_mac_flags;
memcpy(&p.user_req.u, &pos->u, sizeof(pos->u)); memcpy(&p.user_req.u, &pos->u, sizeof(pos->u));
rc = bnx2x_config_vlan_mac(bp, &p); rc = bnx2x_config_vlan_mac(bp, &p);
......
...@@ -266,6 +266,13 @@ enum { ...@@ -266,6 +266,13 @@ enum {
BNX2X_DONT_CONSUME_CAM_CREDIT, BNX2X_DONT_CONSUME_CAM_CREDIT,
BNX2X_DONT_CONSUME_CAM_CREDIT_DEST, BNX2X_DONT_CONSUME_CAM_CREDIT_DEST,
}; };
/* When looking for matching filters, some flags are not interesting */
#define BNX2X_VLAN_MAC_CMP_MASK (1 << BNX2X_UC_LIST_MAC | \
1 << BNX2X_ETH_MAC | \
1 << BNX2X_ISCSI_ETH_MAC | \
1 << BNX2X_NETQ_ETH_MAC)
#define BNX2X_VLAN_MAC_CMP_FLAGS(flags) \
((flags) & BNX2X_VLAN_MAC_CMP_MASK)
struct bnx2x_vlan_mac_ramrod_params { struct bnx2x_vlan_mac_ramrod_params {
/* Object to run the command from */ /* Object to run the command from */
......
...@@ -1209,6 +1209,11 @@ static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf) ...@@ -1209,6 +1209,11 @@ static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf)
/* next state */ /* next state */
vfop->state = BNX2X_VFOP_RXMODE_DONE; vfop->state = BNX2X_VFOP_RXMODE_DONE;
/* record the accept flags in vfdb so hypervisor can modify them
* if necessary
*/
bnx2x_vfq(vf, ramrod->cl_id - vf->igu_base_id, accept_flags) =
ramrod->rx_accept_flags;
vfop->rc = bnx2x_config_rx_mode(bp, ramrod); vfop->rc = bnx2x_config_rx_mode(bp, ramrod);
bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE); bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
op_err: op_err:
...@@ -1224,26 +1229,18 @@ static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf) ...@@ -1224,26 +1229,18 @@ static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf)
return; return;
} }
int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp, static void bnx2x_vf_prep_rx_mode(struct bnx2x *bp, u8 qid,
struct bnx2x_rx_mode_ramrod_params *ramrod,
struct bnx2x_virtf *vf, struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd, unsigned long accept_flags)
int qid, unsigned long accept_flags)
{ {
struct bnx2x_vf_queue *vfq = vfq_get(vf, qid); struct bnx2x_vf_queue *vfq = vfq_get(vf, qid);
struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
if (vfop) {
struct bnx2x_rx_mode_ramrod_params *ramrod =
&vf->op_params.rx_mode;
memset(ramrod, 0, sizeof(*ramrod)); memset(ramrod, 0, sizeof(*ramrod));
/* Prepare ramrod parameters */
ramrod->cid = vfq->cid; ramrod->cid = vfq->cid;
ramrod->cl_id = vfq_cl_id(vf, vfq); ramrod->cl_id = vfq_cl_id(vf, vfq);
ramrod->rx_mode_obj = &bp->rx_mode_obj; ramrod->rx_mode_obj = &bp->rx_mode_obj;
ramrod->func_id = FW_VF_HANDLE(vf->abs_vfid); ramrod->func_id = FW_VF_HANDLE(vf->abs_vfid);
ramrod->rx_accept_flags = accept_flags; ramrod->rx_accept_flags = accept_flags;
ramrod->tx_accept_flags = accept_flags; ramrod->tx_accept_flags = accept_flags;
ramrod->pstate = &vf->filter_state; ramrod->pstate = &vf->filter_state;
...@@ -1253,10 +1250,22 @@ int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp, ...@@ -1253,10 +1250,22 @@ int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
set_bit(RAMROD_RX, &ramrod->ramrod_flags); set_bit(RAMROD_RX, &ramrod->ramrod_flags);
set_bit(RAMROD_TX, &ramrod->ramrod_flags); set_bit(RAMROD_TX, &ramrod->ramrod_flags);
ramrod->rdata = ramrod->rdata = bnx2x_vf_sp(bp, vf, rx_mode_rdata.e2);
bnx2x_vf_sp(bp, vf, rx_mode_rdata.e2); ramrod->rdata_mapping = bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
ramrod->rdata_mapping = }
bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
int qid, unsigned long accept_flags)
{
struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
if (vfop) {
struct bnx2x_rx_mode_ramrod_params *ramrod =
&vf->op_params.rx_mode;
bnx2x_vf_prep_rx_mode(bp, qid, ramrod, vf, accept_flags);
bnx2x_vfop_opset(BNX2X_VFOP_RXMODE_CONFIG, bnx2x_vfop_opset(BNX2X_VFOP_RXMODE_CONFIG,
bnx2x_vfop_rxmode, cmd->done); bnx2x_vfop_rxmode, cmd->done);
...@@ -3439,10 +3448,18 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac) ...@@ -3439,10 +3448,18 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
{ {
struct bnx2x_queue_state_params q_params = {NULL};
struct bnx2x_vlan_mac_ramrod_params ramrod_param;
struct bnx2x_queue_update_params *update_params;
struct pf_vf_bulletin_content *bulletin = NULL;
struct bnx2x_rx_mode_ramrod_params rx_ramrod;
struct bnx2x *bp = netdev_priv(dev); struct bnx2x *bp = netdev_priv(dev);
int rc, q_logical_state; struct bnx2x_vlan_mac_obj *vlan_obj;
unsigned long vlan_mac_flags = 0;
unsigned long ramrod_flags = 0;
struct bnx2x_virtf *vf = NULL; struct bnx2x_virtf *vf = NULL;
struct pf_vf_bulletin_content *bulletin = NULL; unsigned long accept_flags;
int rc;
/* sanity and init */ /* sanity and init */
rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin); rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
...@@ -3460,29 +3477,26 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) ...@@ -3460,29 +3477,26 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
/* update PF's copy of the VF's bulletin. No point in posting the vlan /* update PF's copy of the VF's bulletin. No point in posting the vlan
* to the VF since it doesn't have anything to do with it. But it useful * to the VF since it doesn't have anything to do with it. But it useful
* to store it here in case the VF is not up yet and we can only * to store it here in case the VF is not up yet and we can only
* configure the vlan later when it does. * configure the vlan later when it does. Treat vlan id 0 as remove the
* Host tag.
*/ */
if (vlan > 0)
bulletin->valid_bitmap |= 1 << VLAN_VALID; bulletin->valid_bitmap |= 1 << VLAN_VALID;
else
bulletin->valid_bitmap &= ~(1 << VLAN_VALID);
bulletin->vlan = vlan; bulletin->vlan = vlan;
/* is vf initialized and queue set up? */ /* is vf initialized and queue set up? */
q_logical_state = if (vf->state != VF_ENABLED ||
bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)); bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)) !=
if (vf->state == VF_ENABLED && BNX2X_Q_LOGICAL_STATE_ACTIVE)
q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) { return rc;
/* configure the vlan in device on this vf's queue */
unsigned long ramrod_flags = 0;
unsigned long vlan_mac_flags = 0;
struct bnx2x_vlan_mac_obj *vlan_obj =
&bnx2x_leading_vfq(vf, vlan_obj);
struct bnx2x_vlan_mac_ramrod_params ramrod_param;
struct bnx2x_queue_state_params q_params = {NULL};
struct bnx2x_queue_update_params *update_params;
/* configure the vlan in device on this vf's queue */
vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj);
rc = validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj)); rc = validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj));
if (rc) if (rc)
return rc; return rc;
memset(&ramrod_param, 0, sizeof(ramrod_param));
/* must lock vfpf channel to protect against vf flows */ /* must lock vfpf channel to protect against vf flows */
bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN); bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
...@@ -3497,6 +3511,34 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) ...@@ -3497,6 +3511,34 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
goto out; goto out;
} }
/* need to remove/add the VF's accept_any_vlan bit */
accept_flags = bnx2x_leading_vfq(vf, accept_flags);
if (vlan)
clear_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags);
else
set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags);
bnx2x_vf_prep_rx_mode(bp, LEADING_IDX, &rx_ramrod, vf,
accept_flags);
bnx2x_leading_vfq(vf, accept_flags) = accept_flags;
bnx2x_config_rx_mode(bp, &rx_ramrod);
/* configure the new vlan to device */
memset(&ramrod_param, 0, sizeof(ramrod_param));
__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
ramrod_param.vlan_mac_obj = vlan_obj;
ramrod_param.ramrod_flags = ramrod_flags;
set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
&ramrod_param.user_req.vlan_mac_flags);
ramrod_param.user_req.u.vlan.vlan = vlan;
ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_ADD;
rc = bnx2x_config_vlan_mac(bp, &ramrod_param);
if (rc) {
BNX2X_ERR("failed to configure vlan\n");
rc = -EINVAL;
goto out;
}
/* send queue update ramrod to configure default vlan and silent /* send queue update ramrod to configure default vlan and silent
* vlan removal * vlan removal
*/ */
...@@ -3508,7 +3550,6 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) ...@@ -3508,7 +3550,6 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
&update_params->update_flags); &update_params->update_flags);
__set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG, __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG,
&update_params->update_flags); &update_params->update_flags);
if (vlan == 0) { if (vlan == 0) {
/* if vlan is 0 then we want to leave the VF traffic /* if vlan is 0 then we want to leave the VF traffic
* untagged, and leave the incoming traffic untouched * untagged, and leave the incoming traffic untouched
...@@ -3519,28 +3560,17 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) ...@@ -3519,28 +3560,17 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
__clear_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, __clear_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM,
&update_params->update_flags); &update_params->update_flags);
} else { } else {
/* configure the new vlan to device */
__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
ramrod_param.vlan_mac_obj = vlan_obj;
ramrod_param.ramrod_flags = ramrod_flags;
ramrod_param.user_req.u.vlan.vlan = vlan;
ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_ADD;
rc = bnx2x_config_vlan_mac(bp, &ramrod_param);
if (rc) {
BNX2X_ERR("failed to configure vlan\n");
rc = -EINVAL;
goto out;
}
/* configure default vlan to vf queue and set silent /* configure default vlan to vf queue and set silent
* vlan removal (the vf remains unaware of this vlan). * vlan removal (the vf remains unaware of this vlan).
*/ */
update_params = &q_params.params.update;
__set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN, __set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN,
&update_params->update_flags); &update_params->update_flags);
__set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM,
&update_params->update_flags); &update_params->update_flags);
update_params->def_vlan = vlan; update_params->def_vlan = vlan;
update_params->silent_removal_value =
vlan & VLAN_VID_MASK;
update_params->silent_removal_mask = VLAN_VID_MASK;
} }
/* Update the Queue state */ /* Update the Queue state */
...@@ -3550,6 +3580,7 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) ...@@ -3550,6 +3580,7 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
goto out; goto out;
} }
/* clear the flag indicating that this VF needs its vlan /* clear the flag indicating that this VF needs its vlan
* (will only be set if the HV configured the Vlan before vf was * (will only be set if the HV configured the Vlan before vf was
* up and we were called because the VF came up later * up and we were called because the VF came up later
...@@ -3557,7 +3588,7 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) ...@@ -3557,7 +3588,7 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
out: out:
vf->cfg_flags &= ~VF_CFG_VLAN; vf->cfg_flags &= ~VF_CFG_VLAN;
bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN); bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
}
return rc; return rc;
} }
......
...@@ -74,6 +74,7 @@ struct bnx2x_vf_queue { ...@@ -74,6 +74,7 @@ struct bnx2x_vf_queue {
/* VLANs object */ /* VLANs object */
struct bnx2x_vlan_mac_obj vlan_obj; struct bnx2x_vlan_mac_obj vlan_obj;
atomic_t vlan_count; /* 0 means vlan-0 is set ~ untagged */ atomic_t vlan_count; /* 0 means vlan-0 is set ~ untagged */
unsigned long accept_flags; /* last accept flags configured */
/* Queue Slow-path State object */ /* Queue Slow-path State object */
struct bnx2x_queue_sp_obj sp_obj; struct bnx2x_queue_sp_obj sp_obj;
......
...@@ -1598,6 +1598,8 @@ static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf) ...@@ -1598,6 +1598,8 @@ static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) { if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
unsigned long accept = 0; unsigned long accept = 0;
struct pf_vf_bulletin_content *bulletin =
BP_VF_BULLETIN(bp, vf->index);
/* covert VF-PF if mask to bnx2x accept flags */ /* covert VF-PF if mask to bnx2x accept flags */
if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST) if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST)
...@@ -1617,8 +1619,10 @@ static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf) ...@@ -1617,8 +1619,10 @@ static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
__set_bit(BNX2X_ACCEPT_BROADCAST, &accept); __set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
/* A packet arriving the vf's mac should be accepted /* A packet arriving the vf's mac should be accepted
* with any vlan * with any vlan, unless a vlan has already been
* configured.
*/ */
if (!(bulletin->valid_bitmap & (1 << VLAN_VALID)))
__set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept); __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
/* set rx-mode */ /* set rx-mode */
...@@ -1710,6 +1714,21 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp, ...@@ -1710,6 +1714,21 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
goto response; goto response;
} }
} }
/* if vlan was set by hypervisor we don't allow guest to config vlan */
if (bulletin->valid_bitmap & 1 << VLAN_VALID) {
int i;
/* search for vlan filters */
for (i = 0; i < filters->n_mac_vlan_filters; i++) {
if (filters->filters[i].flags &
VFPF_Q_FILTER_VLAN_TAG_VALID) {
BNX2X_ERR("VF[%d] attempted to configure vlan but one was already set by Hypervisor. Aborting request\n",
vf->abs_vfid);
vf->op_rc = -EPERM;
goto response;
}
}
}
/* verify vf_qid */ /* verify vf_qid */
if (filters->vf_qid > vf_rxq_count(vf)) if (filters->vf_qid > vf_rxq_count(vf))
......
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