Commit 00d7ddba authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

hv_netvsc: pair VF based on serial number

Matching network device based on MAC address is problematic
since a non VF network device can be creted with a duplicate MAC
address causing confusion and problems.  The VMBus API does provide
a serial number that is a better matching method.
Signed-off-by: default avatarStephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a15f2c08
...@@ -1203,6 +1203,9 @@ static void netvsc_send_vf(struct net_device *ndev, ...@@ -1203,6 +1203,9 @@ static void netvsc_send_vf(struct net_device *ndev,
net_device_ctx->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated; net_device_ctx->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated;
net_device_ctx->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial; net_device_ctx->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial;
netdev_info(ndev, "VF slot %u %s\n",
net_device_ctx->vf_serial,
net_device_ctx->vf_alloc ? "added" : "removed");
} }
static void netvsc_receive_inband(struct net_device *ndev, static void netvsc_receive_inband(struct net_device *ndev,
......
...@@ -1894,20 +1894,6 @@ static void netvsc_link_change(struct work_struct *w) ...@@ -1894,20 +1894,6 @@ static void netvsc_link_change(struct work_struct *w)
rtnl_unlock(); rtnl_unlock();
} }
static struct net_device *get_netvsc_bymac(const u8 *mac)
{
struct net_device_context *ndev_ctx;
list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) {
struct net_device *dev = hv_get_drvdata(ndev_ctx->device_ctx);
if (ether_addr_equal(mac, dev->perm_addr))
return dev;
}
return NULL;
}
static struct net_device *get_netvsc_byref(struct net_device *vf_netdev) static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
{ {
struct net_device_context *net_device_ctx; struct net_device_context *net_device_ctx;
...@@ -2036,26 +2022,48 @@ static void netvsc_vf_setup(struct work_struct *w) ...@@ -2036,26 +2022,48 @@ static void netvsc_vf_setup(struct work_struct *w)
rtnl_unlock(); rtnl_unlock();
} }
/* Find netvsc by VMBus serial number.
* The PCI hyperv controller records the serial number as the slot.
*/
static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev)
{
struct device *parent = vf_netdev->dev.parent;
struct net_device_context *ndev_ctx;
struct pci_dev *pdev;
if (!parent || !dev_is_pci(parent))
return NULL; /* not a PCI device */
pdev = to_pci_dev(parent);
if (!pdev->slot) {
netdev_notice(vf_netdev, "no PCI slot information\n");
return NULL;
}
list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) {
if (!ndev_ctx->vf_alloc)
continue;
if (ndev_ctx->vf_serial == pdev->slot->number)
return hv_get_drvdata(ndev_ctx->device_ctx);
}
netdev_notice(vf_netdev,
"no netdev found for slot %u\n", pdev->slot->number);
return NULL;
}
static int netvsc_register_vf(struct net_device *vf_netdev) static int netvsc_register_vf(struct net_device *vf_netdev)
{ {
struct net_device *ndev;
struct net_device_context *net_device_ctx; struct net_device_context *net_device_ctx;
struct device *pdev = vf_netdev->dev.parent;
struct netvsc_device *netvsc_dev; struct netvsc_device *netvsc_dev;
struct net_device *ndev;
int ret; int ret;
if (vf_netdev->addr_len != ETH_ALEN) if (vf_netdev->addr_len != ETH_ALEN)
return NOTIFY_DONE; return NOTIFY_DONE;
if (!pdev || !dev_is_pci(pdev) || dev_is_pf(pdev)) ndev = get_netvsc_byslot(vf_netdev);
return NOTIFY_DONE;
/*
* We will use the MAC address to locate the synthetic interface to
* associate with the VF interface. If we don't find a matching
* synthetic interface, move on.
*/
ndev = get_netvsc_bymac(vf_netdev->perm_addr);
if (!ndev) if (!ndev)
return NOTIFY_DONE; return NOTIFY_DONE;
......
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