Skip to content

Commit

Permalink
sfc: Change VF mac via PF as first preference if available.
Browse files Browse the repository at this point in the history
Changing a VF's mac address through the VF (rather than via the PF)
fails with EPERM because the latter part of efx_ef10_set_mac_address
attempts to change the vport mac address list as the VF.
Even with this fixed it still fails with EBUSY because the vadaptor
is still assigned on the VF - the vadaptor reassignment must be within
a section where the VF has torn down its state.

A major reason this has broken is because we have two functions that
ostensibly do the same thing - have a PF and VF cooperate to change a
VF mac address. Rather than do this, if we are changing the mac of a VF
that has a link to the PF in the same VM then simply call
sriov_set_vf_mac instead, which is a proven working function that does
that.

If there is no PF available, or that fails non-fatally, then attempt to
change the VF's mac address as we would a PF, without updating the PF's
data.

Test case:
Create a VF:
  echo 1 > /sys/class/net/<if>/device/sriov_numvfs
Set the mac address of the VF directly:
  ip link set <vf> addr 00:11:22:33:44:55
Set the MAC address of the VF via the PF:
  ip link set <pf> vf 0 mac 00:11:22:33:44:66
Without this patch the last command will fail with ENOENT.

Signed-off-by: Jonathan Cooper <[email protected]>
Reported-by: Íñigo Huguet <[email protected]>
Fixes: 910c878 ("set the MAC address using MC_CMD_VADAPTOR_SET_MAC")
Acked-by: Edward Cree <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
jco-xilinx authored and davem330 committed Oct 15, 2022
1 parent 0c93411 commit a8aed7b
Showing 1 changed file with 24 additions and 34 deletions.
58 changes: 24 additions & 34 deletions drivers/net/ethernet/sfc/ef10.c
Original file line number Diff line number Diff line change
Expand Up @@ -3277,6 +3277,30 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
bool was_enabled = efx->port_enabled;
int rc;

#ifdef CONFIG_SFC_SRIOV
/* If this function is a VF and we have access to the parent PF,
* then use the PF control path to attempt to change the VF MAC address.
*/
if (efx->pci_dev->is_virtfn && efx->pci_dev->physfn) {
struct efx_nic *efx_pf = pci_get_drvdata(efx->pci_dev->physfn);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
u8 mac[ETH_ALEN];

/* net_dev->dev_addr can be zeroed by efx_net_stop in
* efx_ef10_sriov_set_vf_mac, so pass in a copy.
*/
ether_addr_copy(mac, efx->net_dev->dev_addr);

rc = efx_ef10_sriov_set_vf_mac(efx_pf, nic_data->vf_index, mac);
if (!rc)
return 0;

netif_dbg(efx, drv, efx->net_dev,
"Updating VF mac via PF failed (%d), setting directly\n",
rc);
}
#endif

efx_device_detach_sync(efx);
efx_net_stop(efx->net_dev);

Expand All @@ -3297,40 +3321,6 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
efx_net_open(efx->net_dev);
efx_device_attach_if_not_resetting(efx);

#ifdef CONFIG_SFC_SRIOV
if (efx->pci_dev->is_virtfn && efx->pci_dev->physfn) {
struct efx_ef10_nic_data *nic_data = efx->nic_data;
struct pci_dev *pci_dev_pf = efx->pci_dev->physfn;

if (rc == -EPERM) {
struct efx_nic *efx_pf;

/* Switch to PF and change MAC address on vport */
efx_pf = pci_get_drvdata(pci_dev_pf);

rc = efx_ef10_sriov_set_vf_mac(efx_pf,
nic_data->vf_index,
efx->net_dev->dev_addr);
} else if (!rc) {
struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
struct efx_ef10_nic_data *nic_data = efx_pf->nic_data;
unsigned int i;

/* MAC address successfully changed by VF (with MAC
* spoofing) so update the parent PF if possible.
*/
for (i = 0; i < efx_pf->vf_count; ++i) {
struct ef10_vf *vf = nic_data->vf + i;

if (vf->efx == efx) {
ether_addr_copy(vf->mac,
efx->net_dev->dev_addr);
return 0;
}
}
}
} else
#endif
if (rc == -EPERM) {
netif_err(efx, drv, efx->net_dev,
"Cannot change MAC address; use sfboot to enable"
Expand Down

0 comments on commit a8aed7b

Please sign in to comment.