Skip to content

Commit

Permalink
hyperv: Fix the carrier status setting
Browse files Browse the repository at this point in the history
Without this patch, the "cat /sys/class/net/ethN/operstate" shows
"unknown", and "ethtool ethN" shows "Link detected: yes", when VM
boots up with or without vNIC connected.

This patch fixed the problem.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Haiyang Zhang authored and David S. Miller committed Feb 17, 2014
1 parent 09db308 commit 891de74
Showing 1 changed file with 38 additions and 15 deletions.
53 changes: 38 additions & 15 deletions drivers/net/hyperv/netvsc_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,12 @@ static int netvsc_open(struct net_device *net)
{
struct net_device_context *net_device_ctx = netdev_priv(net);
struct hv_device *device_obj = net_device_ctx->device_ctx;
struct netvsc_device *nvdev;
struct rndis_device *rdev;
int ret = 0;

netif_carrier_off(net);

/* Open up the device */
ret = rndis_filter_open(device_obj);
if (ret != 0) {
Expand All @@ -99,6 +103,11 @@ static int netvsc_open(struct net_device *net)

netif_start_queue(net);

nvdev = hv_get_drvdata(device_obj);
rdev = nvdev->extension;
if (!rdev->link_state)
netif_carrier_on(net);

return ret;
}

Expand Down Expand Up @@ -229,23 +238,24 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
struct net_device *net;
struct net_device_context *ndev_ctx;
struct netvsc_device *net_device;
struct rndis_device *rdev;

net_device = hv_get_drvdata(device_obj);
rdev = net_device->extension;

rdev->link_state = status != 1;

net = net_device->ndev;

if (!net) {
netdev_err(net, "got link status but net device "
"not initialized yet\n");
if (!net || net->reg_state != NETREG_REGISTERED)
return;
}

ndev_ctx = netdev_priv(net);
if (status == 1) {
netif_carrier_on(net);
ndev_ctx = netdev_priv(net);
schedule_delayed_work(&ndev_ctx->dwork, 0);
schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
} else {
netif_carrier_off(net);
schedule_delayed_work(&ndev_ctx->dwork, 0);
}
}

Expand Down Expand Up @@ -388,17 +398,35 @@ static const struct net_device_ops device_ops = {
* current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
* another netif_notify_peers() into a delayed work, otherwise GARP packet
* will not be sent after quick migration, and cause network disconnection.
* Also, we update the carrier status here.
*/
static void netvsc_send_garp(struct work_struct *w)
static void netvsc_link_change(struct work_struct *w)
{
struct net_device_context *ndev_ctx;
struct net_device *net;
struct netvsc_device *net_device;
struct rndis_device *rdev;
bool notify;

rtnl_lock();

ndev_ctx = container_of(w, struct net_device_context, dwork.work);
net_device = hv_get_drvdata(ndev_ctx->device_ctx);
rdev = net_device->extension;
net = net_device->ndev;
netdev_notify_peers(net);

if (rdev->link_state) {
netif_carrier_off(net);
notify = false;
} else {
netif_carrier_on(net);
notify = true;
}

rtnl_unlock();

if (notify)
netdev_notify_peers(net);
}


Expand All @@ -414,13 +442,10 @@ static int netvsc_probe(struct hv_device *dev,
if (!net)
return -ENOMEM;

/* Set initial state */
netif_carrier_off(net);

net_device_ctx = netdev_priv(net);
net_device_ctx->device_ctx = dev;
hv_set_drvdata(dev, net);
INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp);
INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
INIT_WORK(&net_device_ctx->work, do_set_multicast);

net->netdev_ops = &device_ops;
Expand All @@ -443,8 +468,6 @@ static int netvsc_probe(struct hv_device *dev,
}
memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);

netif_carrier_on(net);

ret = register_netdev(net);
if (ret != 0) {
pr_err("Unable to register netdev.\n");
Expand Down

0 comments on commit 891de74

Please sign in to comment.