From 3a494e710367c0a233d86bcde9853781859fc008 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Thu, 19 Jun 2014 18:34:36 -0700 Subject: hyperv: Add handler for RNDIS_STATUS_NETWORK_CHANGE event The RNDIS_STATUS_NETWORK_CHANGE event is received after the Hyper-V host sleep or hibernation. We refresh network at this time. MS-TFS: 135162 Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 3 ++- drivers/net/hyperv/netvsc_drv.c | 30 ++++++++++++++++++++++++++---- drivers/net/hyperv/rndis_filter.c | 21 +-------------------- 3 files changed, 29 insertions(+), 25 deletions(-) (limited to 'drivers/net/hyperv') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 6cc37c15e0bf..24441ae832d1 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -170,6 +170,7 @@ struct rndis_device { enum rndis_device_state state; bool link_state; + bool link_change; atomic_t new_req_id; spinlock_t request_lock; @@ -185,7 +186,7 @@ int netvsc_device_remove(struct hv_device *device); int netvsc_send(struct hv_device *device, struct hv_netvsc_packet *packet); void netvsc_linkstatus_callback(struct hv_device *device_obj, - unsigned int status); + struct rndis_message *resp); int netvsc_recv_callback(struct hv_device *device_obj, struct hv_netvsc_packet *packet, struct ndis_tcp_ip_checksum_info *csum_info); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 4fd71b75e666..9b27ca8c1d39 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -579,8 +579,9 @@ drop: * netvsc_linkstatus_callback - Link up/down notification */ void netvsc_linkstatus_callback(struct hv_device *device_obj, - unsigned int status) + struct rndis_message *resp) { + struct rndis_indicate_status *indicate = &resp->msg.indicate_status; struct net_device *net; struct net_device_context *ndev_ctx; struct netvsc_device *net_device; @@ -589,7 +590,19 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, net_device = hv_get_drvdata(device_obj); rdev = net_device->extension; - rdev->link_state = status != 1; + switch (indicate->status) { + case RNDIS_STATUS_MEDIA_CONNECT: + rdev->link_state = false; + break; + case RNDIS_STATUS_MEDIA_DISCONNECT: + rdev->link_state = true; + break; + case RNDIS_STATUS_NETWORK_CHANGE: + rdev->link_change = true; + break; + default: + return; + } net = net_device->ndev; @@ -597,7 +610,7 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, return; ndev_ctx = netdev_priv(net); - if (status == 1) { + if (!rdev->link_state) { schedule_delayed_work(&ndev_ctx->dwork, 0); schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20)); } else { @@ -767,7 +780,9 @@ static void netvsc_link_change(struct work_struct *w) struct net_device *net; struct netvsc_device *net_device; struct rndis_device *rdev; - bool notify; + bool notify, refresh = false; + char *argv[] = { "/etc/init.d/network", "restart", NULL }; + char *envp[] = { "HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; rtnl_lock(); @@ -782,10 +797,17 @@ static void netvsc_link_change(struct work_struct *w) } else { netif_carrier_on(net); notify = true; + if (rdev->link_change) { + rdev->link_change = false; + refresh = true; + } } rtnl_unlock(); + if (refresh) + call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); + if (notify) netdev_notify_peers(net); } diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 99c527adae5b..2b86f0b6f6d1 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -320,25 +320,6 @@ static void rndis_filter_receive_response(struct rndis_device *dev, } } -static void rndis_filter_receive_indicate_status(struct rndis_device *dev, - struct rndis_message *resp) -{ - struct rndis_indicate_status *indicate = - &resp->msg.indicate_status; - - if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) { - netvsc_linkstatus_callback( - dev->net_dev->dev, 1); - } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) { - netvsc_linkstatus_callback( - dev->net_dev->dev, 0); - } else { - /* - * TODO: - */ - } -} - /* * Get the Per-Packet-Info with the specified type * return NULL if not found. @@ -464,7 +445,7 @@ int rndis_filter_receive(struct hv_device *dev, case RNDIS_MSG_INDICATE: /* notification msgs */ - rndis_filter_receive_indicate_status(rndis_dev, rndis_msg); + netvsc_linkstatus_callback(dev, rndis_msg); break; default: netdev_err(ndev, -- cgit v1.2.3 From bd4578bc84a8c8a390cf6002539e75447e78e935 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 28 Jun 2014 20:44:19 +0200 Subject: drivers/net/hyperv/netvsc.c: remove unnecessary null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Cc: Haiyang Zhang Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/hyperv') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 4ed38eaecea8..f13e0acc8a69 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1094,9 +1094,7 @@ close: vmbus_close(device->channel); cleanup: - - if (net_device) - kfree(net_device); + kfree(net_device); return ret; } -- cgit v1.2.3 From 316158feff0078b266d6e423adb016d12eb96a5a Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 9 Jul 2014 16:23:59 +0200 Subject: hyperv: Add netpoll support In order to have at least a netconsole to debug kernel issues on Windows Azure this patch implements netpoll support. Sending packets is easy, netvsc_start_xmit() does already everything needed. Signed-off-by: Richard Weinberger Acked-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net/hyperv') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 9b27ca8c1d39..a9c5eaadc426 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -749,6 +749,14 @@ static int netvsc_set_mac_addr(struct net_device *ndev, void *p) return err; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void netvsc_poll_controller(struct net_device *net) +{ + /* As netvsc_start_xmit() works synchronous we don't have to + * trigger anything here. + */ +} +#endif static const struct ethtool_ops ethtool_ops = { .get_drvinfo = netvsc_get_drvinfo, @@ -764,6 +772,9 @@ static const struct net_device_ops device_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = netvsc_set_mac_addr, .ndo_select_queue = netvsc_select_queue, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = netvsc_poll_controller, +#endif }; /* -- cgit v1.2.3 From 06b47aac4924180d63aad50727a11230d876c348 Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Sat, 2 Aug 2014 10:42:02 -0700 Subject: Drivers: net-next: hyperv: Increase the size of the sendbuf region Intel did some benchmarking on our network throughput when Linux on Hyper-V is as used as a gateway. This fix gave us almost a 1 Gbps additional throughput on about 5Gbps base throughput we hadi, prior to increasing the sendbuf size. The sendbuf mechanism is a copy based transport that we have which is clearly more optimal than the copy-free page flipping mechanism (for small packets). In the forwarding scenario, we deal only with MTU sized packets, and increasing the size of the senbuf area gave us the additional performance. For what it is worth, Windows guests on Hyper-V, I am told use similar sendbuf size as well. The exact value of sendbuf I think is less important than the fact that it needs to be larger than what Linux can allocate as physically contiguous memory. Thus the change over to allocating via vmalloc(). We currently allocate 16MB receive buffer and we use vmalloc there for allocation. Also the low level channel code has already been modified to deal with physically dis-contiguous memory in the ringbuffer setup. Based on experimentation Intel did, they say there was some improvement in throughput as the sendbuf size was increased up to 16MB and there was no effect on throughput beyond 16MB. Thus I have chosen 16MB here. Increasing the sendbuf value makes a material difference in small packet handling In this version of the patch, based on David's feedback, I have added additional details in the commit log. Signed-off-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 2 +- drivers/net/hyperv/netvsc.c | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net/hyperv') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 24441ae832d1..02a3ee282eee 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -585,7 +585,7 @@ struct nvsp_message { #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ #define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ -#define NETVSC_SEND_BUFFER_SIZE (1024 * 1024) /* 1MB */ +#define NETVSC_SEND_BUFFER_SIZE (1024 * 1024 * 16) /* 16MB */ #define NETVSC_INVALID_INDEX -1 diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 592977a6547c..66979cf7fca6 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -193,8 +193,7 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) } if (net_device->send_buf) { /* Free up the receive buffer */ - free_pages((unsigned long)net_device->send_buf, - get_order(net_device->send_buf_size)); + vfree(net_device->send_buf); net_device->send_buf = NULL; } kfree(net_device->send_section_map); @@ -303,9 +302,7 @@ static int netvsc_init_buf(struct hv_device *device) /* Now setup the send buffer. */ - net_device->send_buf = - (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, - get_order(net_device->send_buf_size)); + net_device->send_buf = vzalloc(net_device->send_buf_size); if (!net_device->send_buf) { netdev_err(ndev, "unable to allocate send " "buffer of size %d\n", net_device->send_buf_size); -- cgit v1.2.3 From be136ed30a4345e42ad846c1b9d925932dab303b Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Wed, 6 Aug 2014 11:11:00 -0700 Subject: hyperv: Adjust the size of sendbuf region to support ws2008r2 WS2008R2 is a supported platform and it turns out that the maximum sendbuf size that ws2008R2 can support is only 15MB. Make the necessary adjustment. Signed-off-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/hyperv') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 02a3ee282eee..d5e07def6a59 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -585,7 +585,7 @@ struct nvsp_message { #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ #define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ -#define NETVSC_SEND_BUFFER_SIZE (1024 * 1024 * 16) /* 16MB */ +#define NETVSC_SEND_BUFFER_SIZE (1024 * 1024 * 15) /* 15MB */ #define NETVSC_INVALID_INDEX -1 -- cgit v1.2.3 From dedb845ded56ded1c62f5398a94ffa8615d4592d Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Sun, 28 Sep 2014 22:16:43 -0700 Subject: hyperv: Fix a bug in netvsc_start_xmit() After the packet is successfully sent, we should not touch the skb as it may have been freed. This patch is based on the work done by Long Li . In this version of the patch I have fixed issues pointed out by David. David, please queue this up for stable. Signed-off-by: K. Y. Srinivasan Tested-by: Long Li Tested-by: Sitsofe Wheeler Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/hyperv') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index a9c5eaadc426..0fcb5e7eb073 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -387,6 +387,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) int hdr_offset; u32 net_trans_info; u32 hash; + u32 skb_length = skb->len; /* We will atmost need two pages to describe the rndis @@ -562,7 +563,7 @@ do_send: drop: if (ret == 0) { - net->stats.tx_bytes += skb->len; + net->stats.tx_bytes += skb_length; net->stats.tx_packets++; } else { kfree(packet); -- cgit v1.2.3