Skip to content

Commit

Permalink
hv_netvsc: improve VF device matching
Browse files Browse the repository at this point in the history
The code to associate netvsc and VF devices can be made less error prone
by using a better matching algorithms.

On registration, use the permanent address which avoids any possible
issues caused by device MAC address being changed. For all other callbacks,
search by the netdevice pointer value to ensure getting the correct
network device.

Signed-off-by: Stephen Hemminger <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
shemminger authored and davem330 committed Sep 23, 2016
1 parent ee837a1 commit e8ff40d
Showing 1 changed file with 39 additions and 21 deletions.
60 changes: 39 additions & 21 deletions drivers/net/hyperv/netvsc_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1215,22 +1215,44 @@ static void netvsc_free_netdev(struct net_device *netdev)
free_netdev(netdev);
}

static struct net_device *get_netvsc_net_device(char *mac)
static struct net_device *get_netvsc_bymac(const u8 *mac)
{
struct net_device *dev, *found = NULL;
struct net_device *dev;

ASSERT_RTNL();

for_each_netdev(&init_net, dev) {
if (memcmp(dev->dev_addr, mac, ETH_ALEN) == 0) {
if (dev->netdev_ops != &device_ops)
continue;
found = dev;
break;
}
if (dev->netdev_ops != &device_ops)
continue; /* not a netvsc device */

if (ether_addr_equal(mac, dev->perm_addr))
return dev;
}

return NULL;
}

static struct net_device *get_netvsc_byref(const struct net_device *vf_netdev)
{
struct net_device *dev;

ASSERT_RTNL();

for_each_netdev(&init_net, dev) {
struct net_device_context *net_device_ctx;

if (dev->netdev_ops != &device_ops)
continue; /* not a netvsc device */

net_device_ctx = netdev_priv(dev);
if (net_device_ctx->nvdev == NULL)
continue; /* device is removed */

if (net_device_ctx->vf_netdev == vf_netdev)
return dev; /* a match */
}

return found;
return NULL;
}

static int netvsc_register_vf(struct net_device *vf_netdev)
Expand All @@ -1239,12 +1261,15 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
struct net_device_context *net_device_ctx;
struct netvsc_device *netvsc_dev;

if (vf_netdev->addr_len != ETH_ALEN)
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_net_device(vf_netdev->dev_addr);
ndev = get_netvsc_bymac(vf_netdev->perm_addr);
if (!ndev)
return NOTIFY_DONE;

Expand Down Expand Up @@ -1284,16 +1309,13 @@ static int netvsc_vf_up(struct net_device *vf_netdev)
struct netvsc_device *netvsc_dev;
struct net_device_context *net_device_ctx;

ndev = get_netvsc_net_device(vf_netdev->dev_addr);
ndev = get_netvsc_byref(vf_netdev);
if (!ndev)
return NOTIFY_DONE;

net_device_ctx = netdev_priv(ndev);
netvsc_dev = net_device_ctx->nvdev;

if (!netvsc_dev || !net_device_ctx->vf_netdev)
return NOTIFY_DONE;

netdev_info(ndev, "VF up: %s\n", vf_netdev->name);
netvsc_inject_enable(net_device_ctx);

Expand Down Expand Up @@ -1322,16 +1344,13 @@ static int netvsc_vf_down(struct net_device *vf_netdev)
struct netvsc_device *netvsc_dev;
struct net_device_context *net_device_ctx;

ndev = get_netvsc_net_device(vf_netdev->dev_addr);
ndev = get_netvsc_byref(vf_netdev);
if (!ndev)
return NOTIFY_DONE;

net_device_ctx = netdev_priv(ndev);
netvsc_dev = net_device_ctx->nvdev;

if (!netvsc_dev || !net_device_ctx->vf_netdev)
return NOTIFY_DONE;

netdev_info(ndev, "VF down: %s\n", vf_netdev->name);
netvsc_inject_disable(net_device_ctx);
netvsc_switch_datapath(ndev, false);
Expand All @@ -1351,14 +1370,13 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
struct netvsc_device *netvsc_dev;
struct net_device_context *net_device_ctx;

ndev = get_netvsc_net_device(vf_netdev->dev_addr);
ndev = get_netvsc_byref(vf_netdev);
if (!ndev)
return NOTIFY_DONE;

net_device_ctx = netdev_priv(ndev);
netvsc_dev = net_device_ctx->nvdev;
if (!netvsc_dev || !net_device_ctx->vf_netdev)
return NOTIFY_DONE;

netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
netvsc_inject_disable(net_device_ctx);
net_device_ctx->vf_netdev = NULL;
Expand Down

0 comments on commit e8ff40d

Please sign in to comment.