Commit 891de74d authored by Haiyang Zhang's avatar Haiyang Zhang Committed by David S. Miller

hyperv: Fix the carrier status setting

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: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Acked-by: default avatarJason Wang <jasowang@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 09db3080
...@@ -88,8 +88,12 @@ static int netvsc_open(struct net_device *net) ...@@ -88,8 +88,12 @@ static int netvsc_open(struct net_device *net)
{ {
struct net_device_context *net_device_ctx = netdev_priv(net); struct net_device_context *net_device_ctx = netdev_priv(net);
struct hv_device *device_obj = net_device_ctx->device_ctx; struct hv_device *device_obj = net_device_ctx->device_ctx;
struct netvsc_device *nvdev;
struct rndis_device *rdev;
int ret = 0; int ret = 0;
netif_carrier_off(net);
/* Open up the device */ /* Open up the device */
ret = rndis_filter_open(device_obj); ret = rndis_filter_open(device_obj);
if (ret != 0) { if (ret != 0) {
...@@ -99,6 +103,11 @@ static int netvsc_open(struct net_device *net) ...@@ -99,6 +103,11 @@ static int netvsc_open(struct net_device *net)
netif_start_queue(net); netif_start_queue(net);
nvdev = hv_get_drvdata(device_obj);
rdev = nvdev->extension;
if (!rdev->link_state)
netif_carrier_on(net);
return ret; return ret;
} }
...@@ -229,23 +238,24 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, ...@@ -229,23 +238,24 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
struct net_device *net; struct net_device *net;
struct net_device_context *ndev_ctx; struct net_device_context *ndev_ctx;
struct netvsc_device *net_device; struct netvsc_device *net_device;
struct rndis_device *rdev;
net_device = hv_get_drvdata(device_obj); net_device = hv_get_drvdata(device_obj);
rdev = net_device->extension;
rdev->link_state = status != 1;
net = net_device->ndev; net = net_device->ndev;
if (!net) { if (!net || net->reg_state != NETREG_REGISTERED)
netdev_err(net, "got link status but net device "
"not initialized yet\n");
return; return;
}
ndev_ctx = netdev_priv(net);
if (status == 1) { 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, 0);
schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20)); schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
} else { } else {
netif_carrier_off(net); schedule_delayed_work(&ndev_ctx->dwork, 0);
} }
} }
...@@ -388,17 +398,35 @@ static const struct net_device_ops device_ops = { ...@@ -388,17 +398,35 @@ static const struct net_device_ops device_ops = {
* current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
* another netif_notify_peers() into a delayed work, otherwise GARP packet * another netif_notify_peers() into a delayed work, otherwise GARP packet
* will not be sent after quick migration, and cause network disconnection. * 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_context *ndev_ctx;
struct net_device *net; struct net_device *net;
struct netvsc_device *net_device; struct netvsc_device *net_device;
struct rndis_device *rdev;
bool notify;
rtnl_lock();
ndev_ctx = container_of(w, struct net_device_context, dwork.work); ndev_ctx = container_of(w, struct net_device_context, dwork.work);
net_device = hv_get_drvdata(ndev_ctx->device_ctx); net_device = hv_get_drvdata(ndev_ctx->device_ctx);
rdev = net_device->extension;
net = net_device->ndev; 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);
} }
...@@ -414,13 +442,10 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -414,13 +442,10 @@ static int netvsc_probe(struct hv_device *dev,
if (!net) if (!net)
return -ENOMEM; return -ENOMEM;
/* Set initial state */
netif_carrier_off(net);
net_device_ctx = netdev_priv(net); net_device_ctx = netdev_priv(net);
net_device_ctx->device_ctx = dev; net_device_ctx->device_ctx = dev;
hv_set_drvdata(dev, net); 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); INIT_WORK(&net_device_ctx->work, do_set_multicast);
net->netdev_ops = &device_ops; net->netdev_ops = &device_ops;
...@@ -443,8 +468,6 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -443,8 +468,6 @@ static int netvsc_probe(struct hv_device *dev,
} }
memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
netif_carrier_on(net);
ret = register_netdev(net); ret = register_netdev(net);
if (ret != 0) { if (ret != 0) {
pr_err("Unable to register netdev.\n"); pr_err("Unable to register netdev.\n");
......
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