Skip to content

Commit

Permalink
Merge branch 'qed-Use-trust-mode-to-override-forced-MAC'
Browse files Browse the repository at this point in the history
Shahed Shaikh says:

====================
qed* : Use trust mode to override forced MAC

This patchset adds a support to override forced MAC (MAC set by PF for a VF)
when trust mode is enabled using

First patch adds a real change to use .ndo_set_vf_trust to override forced MAC
and allow user to change VFs from VF interface itself.

Second patch takes care of a corner case, where MAC change from VF won't
take effect when VF interface is down, by introducing a new TLV
(a way to send message from VF to PF) to give a hint to PF to update
its bulletin board.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Apr 20, 2018
2 parents 2ed0212 + 809c45a commit 26d6804
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 18 deletions.
19 changes: 19 additions & 0 deletions drivers/net/ethernet/qlogic/qed/qed_l2.c
Original file line number Diff line number Diff line change
Expand Up @@ -2850,6 +2850,24 @@ static int qed_fp_cqe_completion(struct qed_dev *dev,
cqe);
}

static int qed_req_bulletin_update_mac(struct qed_dev *cdev, u8 *mac)
{
int i, ret;

if (IS_PF(cdev))
return 0;

for_each_hwfn(cdev, i) {
struct qed_hwfn *p_hwfn = &cdev->hwfns[i];

ret = qed_vf_pf_bulletin_update_mac(p_hwfn, mac);
if (ret)
return ret;
}

return 0;
}

#ifdef CONFIG_QED_SRIOV
extern const struct qed_iov_hv_ops qed_iov_ops_pass;
#endif
Expand Down Expand Up @@ -2887,6 +2905,7 @@ static const struct qed_eth_ops qed_eth_ops_pass = {
.ntuple_filter_config = &qed_ntuple_arfs_filter_config,
.configure_arfs_searcher = &qed_configure_arfs_searcher,
.get_coalesce = &qed_get_coalesce,
.req_bulletin_update_mac = &qed_req_bulletin_update_mac,
};

const struct qed_eth_ops *qed_get_eth_ops(void)
Expand Down
247 changes: 231 additions & 16 deletions drivers/net/ethernet/qlogic/qed/qed_sriov.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn,
u8 opcode,
__le16 echo,
union event_ring_data *data, u8 fw_return_code);

static int qed_iov_bulletin_set_mac(struct qed_hwfn *p_hwfn, u8 *mac, int vfid);

static u8 qed_vf_calculate_legacy(struct qed_vf_info *p_vf)
{
Expand Down Expand Up @@ -1790,7 +1790,8 @@ static int qed_iov_configure_vport_forced(struct qed_hwfn *p_hwfn,
if (!p_vf->vport_instance)
return -EINVAL;

if (events & BIT(MAC_ADDR_FORCED)) {
if ((events & BIT(MAC_ADDR_FORCED)) ||
p_vf->p_vf_info.is_trusted_configured) {
/* Since there's no way [currently] of removing the MAC,
* we can always assume this means we need to force it.
*/
Expand All @@ -1809,8 +1810,12 @@ static int qed_iov_configure_vport_forced(struct qed_hwfn *p_hwfn,
"PF failed to configure MAC for VF\n");
return rc;
}

p_vf->configured_features |= 1 << MAC_ADDR_FORCED;
if (p_vf->p_vf_info.is_trusted_configured)
p_vf->configured_features |=
BIT(VFPF_BULLETIN_MAC_ADDR);
else
p_vf->configured_features |=
BIT(MAC_ADDR_FORCED);
}

if (events & BIT(VLAN_ADDR_FORCED)) {
Expand Down Expand Up @@ -3170,6 +3175,10 @@ static int qed_iov_vf_update_mac_shadow(struct qed_hwfn *p_hwfn,
if (p_vf->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED))
return 0;

/* Don't keep track of shadow copy since we don't intend to restore. */
if (p_vf->p_vf_info.is_trusted_configured)
return 0;

/* First remove entries and then add new ones */
if (p_params->opcode == QED_FILTER_REMOVE) {
for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) {
Expand Down Expand Up @@ -3244,9 +3253,17 @@ static int qed_iov_chk_ucast(struct qed_hwfn *hwfn,

/* No real decision to make; Store the configured MAC */
if (params->type == QED_FILTER_MAC ||
params->type == QED_FILTER_MAC_VLAN)
params->type == QED_FILTER_MAC_VLAN) {
ether_addr_copy(vf->mac, params->mac);

if (vf->is_trusted_configured) {
qed_iov_bulletin_set_mac(hwfn, vf->mac, vfid);

/* Update and post bulleitin again */
qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG);
}
}

return 0;
}

Expand Down Expand Up @@ -3803,6 +3820,40 @@ static void qed_iov_get_link(struct qed_hwfn *p_hwfn,
__qed_vf_get_link_caps(p_hwfn, p_caps, p_bulletin);
}

static int
qed_iov_vf_pf_bulletin_update_mac(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct qed_vf_info *p_vf)
{
struct qed_bulletin_content *p_bulletin = p_vf->bulletin.p_virt;
struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx;
struct vfpf_bulletin_update_mac_tlv *p_req;
u8 status = PFVF_STATUS_SUCCESS;
int rc = 0;

if (!p_vf->p_vf_info.is_trusted_configured) {
DP_VERBOSE(p_hwfn,
QED_MSG_IOV,
"Blocking bulletin update request from untrusted VF[%d]\n",
p_vf->abs_vf_id);
status = PFVF_STATUS_NOT_SUPPORTED;
rc = -EINVAL;
goto send_status;
}

p_req = &mbx->req_virt->bulletin_update_mac;
ether_addr_copy(p_bulletin->mac, p_req->mac);
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
"Updated bulletin of VF[%d] with requested MAC[%pM]\n",
p_vf->abs_vf_id, p_req->mac);

send_status:
qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf,
CHANNEL_TLV_BULLETIN_UPDATE_MAC,
sizeof(struct pfvf_def_resp_tlv), status);
return rc;
}

static void qed_iov_process_mbx_req(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, int vfid)
{
Expand Down Expand Up @@ -3882,6 +3933,9 @@ static void qed_iov_process_mbx_req(struct qed_hwfn *p_hwfn,
case CHANNEL_TLV_COALESCE_READ:
qed_iov_vf_pf_get_coalesce(p_hwfn, p_ptt, p_vf);
break;
case CHANNEL_TLV_BULLETIN_UPDATE_MAC:
qed_iov_vf_pf_bulletin_update_mac(p_hwfn, p_ptt, p_vf);
break;
}
} else if (qed_iov_tlv_supported(mbx->first_tlv.tl.type)) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
Expand Down Expand Up @@ -4081,16 +4135,60 @@ static void qed_iov_bulletin_set_forced_mac(struct qed_hwfn *p_hwfn,
return;
}

feature = 1 << MAC_ADDR_FORCED;
if (vf_info->p_vf_info.is_trusted_configured) {
feature = BIT(VFPF_BULLETIN_MAC_ADDR);
/* Trust mode will disable Forced MAC */
vf_info->bulletin.p_virt->valid_bitmap &=
~BIT(MAC_ADDR_FORCED);
} else {
feature = BIT(MAC_ADDR_FORCED);
/* Forced MAC will disable MAC_ADDR */
vf_info->bulletin.p_virt->valid_bitmap &=
~BIT(VFPF_BULLETIN_MAC_ADDR);
}

memcpy(vf_info->bulletin.p_virt->mac, mac, ETH_ALEN);

vf_info->bulletin.p_virt->valid_bitmap |= feature;
/* Forced MAC will disable MAC_ADDR */
vf_info->bulletin.p_virt->valid_bitmap &= ~BIT(VFPF_BULLETIN_MAC_ADDR);

qed_iov_configure_vport_forced(p_hwfn, vf_info, feature);
}

static int qed_iov_bulletin_set_mac(struct qed_hwfn *p_hwfn, u8 *mac, int vfid)
{
struct qed_vf_info *vf_info;
u64 feature;

vf_info = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true);
if (!vf_info) {
DP_NOTICE(p_hwfn->cdev, "Can not set MAC, invalid vfid [%d]\n",
vfid);
return -EINVAL;
}

if (vf_info->b_malicious) {
DP_NOTICE(p_hwfn->cdev, "Can't set MAC to malicious VF [%d]\n",
vfid);
return -EINVAL;
}

if (vf_info->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED)) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
"Can not set MAC, Forced MAC is configured\n");
return -EINVAL;
}

feature = BIT(VFPF_BULLETIN_MAC_ADDR);
ether_addr_copy(vf_info->bulletin.p_virt->mac, mac);

vf_info->bulletin.p_virt->valid_bitmap |= feature;

if (vf_info->p_vf_info.is_trusted_configured)
qed_iov_configure_vport_forced(p_hwfn, vf_info, feature);

return 0;
}

static void qed_iov_bulletin_set_forced_vlan(struct qed_hwfn *p_hwfn,
u16 pvid, int vfid)
{
Expand Down Expand Up @@ -4204,6 +4302,21 @@ static int qed_iov_spoofchk_set(struct qed_hwfn *p_hwfn, int vfid, bool val)
return rc;
}

static u8 *qed_iov_bulletin_get_mac(struct qed_hwfn *p_hwfn, u16 rel_vf_id)
{
struct qed_vf_info *p_vf;

p_vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true);
if (!p_vf || !p_vf->bulletin.p_virt)
return NULL;

if (!(p_vf->bulletin.p_virt->valid_bitmap &
BIT(VFPF_BULLETIN_MAC_ADDR)))
return NULL;

return p_vf->bulletin.p_virt->mac;
}

static u8 *qed_iov_bulletin_get_forced_mac(struct qed_hwfn *p_hwfn,
u16 rel_vf_id)
{
Expand Down Expand Up @@ -4493,8 +4606,12 @@ static int qed_sriov_pf_set_mac(struct qed_dev *cdev, u8 *mac, int vfid)
if (!vf_info)
continue;

/* Set the forced MAC, and schedule the IOV task */
ether_addr_copy(vf_info->forced_mac, mac);
/* Set the MAC, and schedule the IOV task */
if (vf_info->is_trusted_configured)
ether_addr_copy(vf_info->mac, mac);
else
ether_addr_copy(vf_info->forced_mac, mac);

qed_schedule_iov(hwfn, QED_IOV_WQ_SET_UNICAST_FILTER_FLAG);
}

Expand Down Expand Up @@ -4802,6 +4919,33 @@ static void qed_handle_vf_msg(struct qed_hwfn *hwfn)
qed_ptt_release(hwfn, ptt);
}

static bool qed_pf_validate_req_vf_mac(struct qed_hwfn *hwfn,
u8 *mac,
struct qed_public_vf_info *info)
{
if (info->is_trusted_configured) {
if (is_valid_ether_addr(info->mac) &&
(!mac || !ether_addr_equal(mac, info->mac)))
return true;
} else {
if (is_valid_ether_addr(info->forced_mac) &&
(!mac || !ether_addr_equal(mac, info->forced_mac)))
return true;
}

return false;
}

static void qed_set_bulletin_mac(struct qed_hwfn *hwfn,
struct qed_public_vf_info *info,
int vfid)
{
if (info->is_trusted_configured)
qed_iov_bulletin_set_mac(hwfn, info->mac, vfid);
else
qed_iov_bulletin_set_forced_mac(hwfn, info->forced_mac, vfid);
}

static void qed_handle_pf_set_vf_unicast(struct qed_hwfn *hwfn)
{
int i;
Expand All @@ -4816,18 +4960,20 @@ static void qed_handle_pf_set_vf_unicast(struct qed_hwfn *hwfn)
continue;

/* Update data on bulletin board */
mac = qed_iov_bulletin_get_forced_mac(hwfn, i);
if (is_valid_ether_addr(info->forced_mac) &&
(!mac || !ether_addr_equal(mac, info->forced_mac))) {
if (info->is_trusted_configured)
mac = qed_iov_bulletin_get_mac(hwfn, i);
else
mac = qed_iov_bulletin_get_forced_mac(hwfn, i);

if (qed_pf_validate_req_vf_mac(hwfn, mac, info)) {
DP_VERBOSE(hwfn,
QED_MSG_IOV,
"Handling PF setting of VF MAC to VF 0x%02x [Abs 0x%02x]\n",
i,
hwfn->cdev->p_iov_info->first_vf_in_pf + i);

/* Update bulletin board with forced MAC */
qed_iov_bulletin_set_forced_mac(hwfn,
info->forced_mac, i);
/* Update bulletin board with MAC */
qed_set_bulletin_mac(hwfn, info, i);
update = true;
}

Expand Down Expand Up @@ -4867,6 +5013,72 @@ static void qed_handle_bulletin_post(struct qed_hwfn *hwfn)
qed_ptt_release(hwfn, ptt);
}

static void qed_update_mac_for_vf_trust_change(struct qed_hwfn *hwfn, int vf_id)
{
struct qed_public_vf_info *vf_info;
struct qed_vf_info *vf;
u8 *force_mac;
int i;

vf_info = qed_iov_get_public_vf_info(hwfn, vf_id, true);
vf = qed_iov_get_vf_info(hwfn, vf_id, true);

if (!vf_info || !vf)
return;

/* Force MAC converted to generic MAC in case of VF trust on */
if (vf_info->is_trusted_configured &&
(vf->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED))) {
force_mac = qed_iov_bulletin_get_forced_mac(hwfn, vf_id);

if (force_mac) {
/* Clear existing shadow copy of MAC to have a clean
* slate.
*/
for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) {
if (ether_addr_equal(vf->shadow_config.macs[i],
vf_info->mac)) {
memset(vf->shadow_config.macs[i], 0,
ETH_ALEN);
DP_VERBOSE(hwfn, QED_MSG_IOV,
"Shadow MAC %pM removed for VF 0x%02x, VF trust mode is ON\n",
vf_info->mac, vf_id);
break;
}
}

ether_addr_copy(vf_info->mac, force_mac);
memset(vf_info->forced_mac, 0, ETH_ALEN);
vf->bulletin.p_virt->valid_bitmap &=
~BIT(MAC_ADDR_FORCED);
qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG);
}
}

/* Update shadow copy with VF MAC when trust mode is turned off */
if (!vf_info->is_trusted_configured) {
u8 empty_mac[ETH_ALEN];

memset(empty_mac, 0, ETH_ALEN);
for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) {
if (ether_addr_equal(vf->shadow_config.macs[i],
empty_mac)) {
ether_addr_copy(vf->shadow_config.macs[i],
vf_info->mac);
DP_VERBOSE(hwfn, QED_MSG_IOV,
"Shadow is updated with %pM for VF 0x%02x, VF trust mode is OFF\n",
vf_info->mac, vf_id);
break;
}
}
/* Clear bulletin when trust mode is turned off,
* to have a clean slate for next (normal) operations.
*/
qed_iov_bulletin_set_mac(hwfn, empty_mac, vf_id);
qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG);
}
}

static void qed_iov_handle_trust_change(struct qed_hwfn *hwfn)
{
struct qed_sp_vport_update_params params;
Expand All @@ -4890,6 +5102,9 @@ static void qed_iov_handle_trust_change(struct qed_hwfn *hwfn)
continue;
vf_info->is_trusted_configured = vf_info->is_trusted_request;

/* Handle forced MAC mode */
qed_update_mac_for_vf_trust_change(hwfn, i);

/* Validate that the VF has a configured vport */
vf = qed_iov_get_vf_info(hwfn, i, true);
if (!vf->vport_instance)
Expand Down
Loading

0 comments on commit 26d6804

Please sign in to comment.