All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/7] hv_netvsc changes
@ 2016-09-22 23:56 sthemmin
  2016-09-22 23:56 ` [PATCH 1/7] hv_netvsc: use consume_skb sthemmin
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: sthemmin @ 2016-09-22 23:56 UTC (permalink / raw)
  To: K. Y. Srinivasan, Haiyang Zhang, davem; +Cc: netdev, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

These are mostly about improving the handling of interaction between
the virtual network device (netvsc) and the SR-IOV VF network device.

Stephen Hemminger (7):
  hv_netvsc: use consume_skb
  hv_netvsc: dev hold/put reference to VF
  hv_netvsc: simplify callback event code
  hv_netvsc: improve VF device matching
  hv_netvsc: use RCU to protect vf_netdev
  hv_netvsc: remove VF in flight counters
  hv_netvsc: count multicast packets received

 drivers/net/hyperv/hyperv_net.h |    7 +-
 drivers/net/hyperv/netvsc.c     |    4 +-
 drivers/net/hyperv/netvsc_drv.c |  188 +++++++++++++++++---------------------
 3 files changed, 90 insertions(+), 109 deletions(-)

-- 
1.7.4.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/7] hv_netvsc: use consume_skb
  2016-09-22 23:56 [PATCH net-next 0/7] hv_netvsc changes sthemmin
@ 2016-09-22 23:56 ` sthemmin
  2016-09-22 23:56 ` [PATCH 2/7] hv_netvsc: dev hold/put reference to VF sthemmin
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: sthemmin @ 2016-09-22 23:56 UTC (permalink / raw)
  To: K. Y. Srinivasan, Haiyang Zhang, davem; +Cc: netdev, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Packets that are transmitted in normal path should use consume_skb
instead of kfree_skb. This allows for better tracing of packet drops.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 drivers/net/hyperv/netvsc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index ff05b9b..720b5fa 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -635,7 +635,7 @@ static void netvsc_send_tx_complete(struct netvsc_device *net_device,
 		q_idx = nvsc_packet->q_idx;
 		channel = incoming_channel;
 
-		dev_kfree_skb_any(skb);
+		dev_consume_skb_any(skb);
 	}
 
 	num_outstanding_sends =
@@ -944,7 +944,7 @@ int netvsc_send(struct hv_device *device,
 		}
 
 		if (msdp->skb)
-			dev_kfree_skb_any(msdp->skb);
+			dev_consume_skb_any(msdp->skb);
 
 		if (xmit_more && !packet->cp_partial) {
 			msdp->skb = skb;
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/7] hv_netvsc: dev hold/put reference to VF
  2016-09-22 23:56 [PATCH net-next 0/7] hv_netvsc changes sthemmin
  2016-09-22 23:56 ` [PATCH 1/7] hv_netvsc: use consume_skb sthemmin
@ 2016-09-22 23:56 ` sthemmin
  2016-09-22 23:56 ` [PATCH 3/7] hv_netvsc: simplify callback event code sthemmin
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: sthemmin @ 2016-09-22 23:56 UTC (permalink / raw)
  To: K. Y. Srinivasan, Haiyang Zhang, davem; +Cc: netdev, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

The netvsc driver holds a pointer to the virtual function network device if
managing SR-IOV association. In order to ensure that the VF network device
does not disappear, it should be using dev_hold/dev_put to get a reference
count.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 drivers/net/hyperv/netvsc_drv.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 2360e70..e74dbcc 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1262,6 +1262,8 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
 	 * Take a reference on the module.
 	 */
 	try_module_get(THIS_MODULE);
+
+	dev_hold(vf_netdev);
 	net_device_ctx->vf_netdev = vf_netdev;
 	return NOTIFY_OK;
 }
@@ -1376,6 +1378,7 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
 	netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
 	netvsc_inject_disable(net_device_ctx);
 	net_device_ctx->vf_netdev = NULL;
+	dev_put(vf_netdev);
 	module_put(THIS_MODULE);
 	return NOTIFY_OK;
 }
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/7] hv_netvsc: simplify callback event code
  2016-09-22 23:56 [PATCH net-next 0/7] hv_netvsc changes sthemmin
  2016-09-22 23:56 ` [PATCH 1/7] hv_netvsc: use consume_skb sthemmin
  2016-09-22 23:56 ` [PATCH 2/7] hv_netvsc: dev hold/put reference to VF sthemmin
@ 2016-09-22 23:56 ` sthemmin
  2016-09-22 23:56 ` [PATCH 4/7] hv_netvsc: improve VF device matching sthemmin
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: sthemmin @ 2016-09-22 23:56 UTC (permalink / raw)
  To: K. Y. Srinivasan, Haiyang Zhang, davem; +Cc: netdev, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

The callback handler for netlink events can be simplified:
 * Consolidate check for netlink callback events about this driver itself.
 * Ignore non-Ethernet devices.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 drivers/net/hyperv/netvsc_drv.c |   28 ++++++++++------------------
 1 files changed, 10 insertions(+), 18 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index e74dbcc..849b566 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1238,10 +1238,6 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
 	struct net_device *ndev;
 	struct net_device_context *net_device_ctx;
 	struct netvsc_device *netvsc_dev;
-	const struct ethtool_ops *eth_ops = vf_netdev->ethtool_ops;
-
-	if (eth_ops == NULL || eth_ops == &ethtool_ops)
-		return NOTIFY_DONE;
 
 	/*
 	 * We will use the MAC address to locate the synthetic interface to
@@ -1286,12 +1282,8 @@ static int netvsc_vf_up(struct net_device *vf_netdev)
 {
 	struct net_device *ndev;
 	struct netvsc_device *netvsc_dev;
-	const struct ethtool_ops *eth_ops = vf_netdev->ethtool_ops;
 	struct net_device_context *net_device_ctx;
 
-	if (eth_ops == &ethtool_ops)
-		return NOTIFY_DONE;
-
 	ndev = get_netvsc_net_device(vf_netdev->dev_addr);
 	if (!ndev)
 		return NOTIFY_DONE;
@@ -1329,10 +1321,6 @@ static int netvsc_vf_down(struct net_device *vf_netdev)
 	struct net_device *ndev;
 	struct netvsc_device *netvsc_dev;
 	struct net_device_context *net_device_ctx;
-	const struct ethtool_ops *eth_ops = vf_netdev->ethtool_ops;
-
-	if (eth_ops == &ethtool_ops)
-		return NOTIFY_DONE;
 
 	ndev = get_netvsc_net_device(vf_netdev->dev_addr);
 	if (!ndev)
@@ -1361,12 +1349,8 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
 {
 	struct net_device *ndev;
 	struct netvsc_device *netvsc_dev;
-	const struct ethtool_ops *eth_ops = vf_netdev->ethtool_ops;
 	struct net_device_context *net_device_ctx;
 
-	if (eth_ops == &ethtool_ops)
-		return NOTIFY_DONE;
-
 	ndev = get_netvsc_net_device(vf_netdev->dev_addr);
 	if (!ndev)
 		return NOTIFY_DONE;
@@ -1542,13 +1526,21 @@ static int netvsc_netdev_event(struct notifier_block *this,
 {
 	struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
 
+	/* Skip our own events */
+	if (event_dev->netdev_ops == &device_ops)
+		return NOTIFY_DONE;
+
+	/* Avoid non-Ethernet type devices */
+	if (event_dev->type != ARPHRD_ETHER)
+		return NOTIFY_DONE;
+
 	/* Avoid Vlan dev with same MAC registering as VF */
 	if (event_dev->priv_flags & IFF_802_1Q_VLAN)
 		return NOTIFY_DONE;
 
 	/* Avoid Bonding master dev with same MAC registering as VF */
-	if (event_dev->priv_flags & IFF_BONDING &&
-	    event_dev->flags & IFF_MASTER)
+	if ((event_dev->priv_flags & IFF_BONDING) &&
+	    (event_dev->flags & IFF_MASTER))
 		return NOTIFY_DONE;
 
 	switch (event) {
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/7] hv_netvsc: improve VF device matching
  2016-09-22 23:56 [PATCH net-next 0/7] hv_netvsc changes sthemmin
                   ` (2 preceding siblings ...)
  2016-09-22 23:56 ` [PATCH 3/7] hv_netvsc: simplify callback event code sthemmin
@ 2016-09-22 23:56 ` sthemmin
  2016-09-22 23:56 ` [PATCH 5/7] hv_netvsc: use RCU to protect vf_netdev sthemmin
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: sthemmin @ 2016-09-22 23:56 UTC (permalink / raw)
  To: K. Y. Srinivasan, Haiyang Zhang, davem; +Cc: netdev, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

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 <sthemmin@microsoft.com>
---
 drivers/net/hyperv/netvsc_drv.c |   60 +++++++++++++++++++++++++-------------
 1 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 849b566..8768219 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -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)
@@ -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;
 
@@ -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);
 
@@ -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);
@@ -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;
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/7] hv_netvsc: use RCU to protect vf_netdev
  2016-09-22 23:56 [PATCH net-next 0/7] hv_netvsc changes sthemmin
                   ` (3 preceding siblings ...)
  2016-09-22 23:56 ` [PATCH 4/7] hv_netvsc: improve VF device matching sthemmin
@ 2016-09-22 23:56 ` sthemmin
  2016-09-22 23:56 ` [PATCH 6/7] hv_netvsc: remove VF in flight counters sthemmin
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: sthemmin @ 2016-09-22 23:56 UTC (permalink / raw)
  To: K. Y. Srinivasan, Haiyang Zhang, davem; +Cc: netdev, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

The vf_netdev pointer in the netvsc device context can simply be protected
by RCU because network device destruction is already RCU synchronized.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 drivers/net/hyperv/hyperv_net.h |    2 +-
 drivers/net/hyperv/netvsc_drv.c |   29 +++++++++++++++--------------
 2 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 284b97b..6b79487 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -695,7 +695,7 @@ struct net_device_context {
 	bool start_remove;
 
 	/* State to manage the associated VF interface. */
-	struct net_device *vf_netdev;
+	struct net_device __rcu *vf_netdev;
 	bool vf_inject;
 	atomic_t vf_use_cnt;
 	/* 1: allocated, serial number is valid. 0: not allocated */
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 8768219..dde17c0 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -667,8 +667,8 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 {
 	struct net_device *net = hv_get_drvdata(device_obj);
 	struct net_device_context *net_device_ctx = netdev_priv(net);
+	struct net_device *vf_netdev;
 	struct sk_buff *skb;
-	struct sk_buff *vf_skb;
 	struct netvsc_stats *rx_stats;
 	u32 bytes_recvd = packet->total_data_buflen;
 	int ret = 0;
@@ -676,9 +676,12 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 	if (!net || net->reg_state != NETREG_REGISTERED)
 		return NVSP_STAT_FAIL;
 
-	if (READ_ONCE(net_device_ctx->vf_inject)) {
+	vf_netdev = rcu_dereference(net_device_ctx->vf_netdev);
+	if (vf_netdev) {
+		struct sk_buff *vf_skb;
+
 		atomic_inc(&net_device_ctx->vf_use_cnt);
-		if (!READ_ONCE(net_device_ctx->vf_inject)) {
+		if (!net_device_ctx->vf_inject) {
 			/*
 			 * We raced; just move on.
 			 */
@@ -694,13 +697,12 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 		 * the host). Deliver these via the VF interface
 		 * in the guest.
 		 */
-		vf_skb = netvsc_alloc_recv_skb(net_device_ctx->vf_netdev,
+		vf_skb = netvsc_alloc_recv_skb(vf_netdev,
 					       packet, csum_info, *data,
 					       vlan_tci);
 		if (vf_skb != NULL) {
-			++net_device_ctx->vf_netdev->stats.rx_packets;
-			net_device_ctx->vf_netdev->stats.rx_bytes +=
-				bytes_recvd;
+			++vf_netdev->stats.rx_packets;
+			vf_netdev->stats.rx_bytes += bytes_recvd;
 			netif_receive_skb(vf_skb);
 		} else {
 			++net->stats.rx_dropped;
@@ -1232,7 +1234,7 @@ static struct net_device *get_netvsc_bymac(const u8 *mac)
 	return NULL;
 }
 
-static struct net_device *get_netvsc_byref(const struct net_device *vf_netdev)
+static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
 {
 	struct net_device *dev;
 
@@ -1248,7 +1250,7 @@ static struct net_device *get_netvsc_byref(const struct net_device *vf_netdev)
 		if (net_device_ctx->nvdev == NULL)
 			continue;	/* device is removed */
 
-		if (net_device_ctx->vf_netdev == vf_netdev)
+		if (rtnl_dereference(net_device_ctx->vf_netdev) == vf_netdev)
 			return dev;	/* a match */
 	}
 
@@ -1275,7 +1277,7 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
 
 	net_device_ctx = netdev_priv(ndev);
 	netvsc_dev = net_device_ctx->nvdev;
-	if (!netvsc_dev || net_device_ctx->vf_netdev)
+	if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev))
 		return NOTIFY_DONE;
 
 	netdev_info(ndev, "VF registering: %s\n", vf_netdev->name);
@@ -1285,7 +1287,7 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
 	try_module_get(THIS_MODULE);
 
 	dev_hold(vf_netdev);
-	net_device_ctx->vf_netdev = vf_netdev;
+	rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev);
 	return NOTIFY_OK;
 }
 
@@ -1379,7 +1381,8 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
 
 	netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
 	netvsc_inject_disable(net_device_ctx);
-	net_device_ctx->vf_netdev = NULL;
+
+	RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
 	dev_put(vf_netdev);
 	module_put(THIS_MODULE);
 	return NOTIFY_OK;
@@ -1433,8 +1436,6 @@ static int netvsc_probe(struct hv_device *dev,
 	INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
 
 	atomic_set(&net_device_ctx->vf_use_cnt, 0);
-	net_device_ctx->vf_netdev = NULL;
-	net_device_ctx->vf_inject = false;
 
 	net->netdev_ops = &device_ops;
 
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 6/7] hv_netvsc: remove VF in flight counters
  2016-09-22 23:56 [PATCH net-next 0/7] hv_netvsc changes sthemmin
                   ` (4 preceding siblings ...)
  2016-09-22 23:56 ` [PATCH 5/7] hv_netvsc: use RCU to protect vf_netdev sthemmin
@ 2016-09-22 23:56 ` sthemmin
  2016-09-22 23:56 ` [PATCH 7/7] hv_netvsc: count multicast packets received sthemmin
  2016-09-23 12:21 ` [PATCH net-next 0/7] hv_netvsc changes David Miller
  7 siblings, 0 replies; 9+ messages in thread
From: sthemmin @ 2016-09-22 23:56 UTC (permalink / raw)
  To: K. Y. Srinivasan, Haiyang Zhang, davem; +Cc: netdev, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Since VF reference is now protected by RCU, no longer need the VF usage
counter and can use device flags to see whether to inject or not.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 drivers/net/hyperv/hyperv_net.h |    3 +-
 drivers/net/hyperv/netvsc_drv.c |   81 ++++++++++-----------------------------
 2 files changed, 21 insertions(+), 63 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 6b79487..1d49740 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -696,8 +696,7 @@ struct net_device_context {
 
 	/* State to manage the associated VF interface. */
 	struct net_device __rcu *vf_netdev;
-	bool vf_inject;
-	atomic_t vf_use_cnt;
+
 	/* 1: allocated, serial number is valid. 0: not allocated */
 	u32 vf_alloc;
 	/* Serial number of the VF to team with */
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index dde17c0..9375d82 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -670,50 +670,20 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 	struct net_device *vf_netdev;
 	struct sk_buff *skb;
 	struct netvsc_stats *rx_stats;
-	u32 bytes_recvd = packet->total_data_buflen;
-	int ret = 0;
 
-	if (!net || net->reg_state != NETREG_REGISTERED)
+	if (net->reg_state != NETREG_REGISTERED)
 		return NVSP_STAT_FAIL;
 
+	/*
+	 * If necessary, inject this packet into the VF interface.
+	 * On Hyper-V, multicast and brodcast packets are only delivered
+	 * to the synthetic interface (after subjecting these to
+	 * policy filters on the host). Deliver these via the VF
+	 * interface in the guest.
+	 */
 	vf_netdev = rcu_dereference(net_device_ctx->vf_netdev);
-	if (vf_netdev) {
-		struct sk_buff *vf_skb;
-
-		atomic_inc(&net_device_ctx->vf_use_cnt);
-		if (!net_device_ctx->vf_inject) {
-			/*
-			 * We raced; just move on.
-			 */
-			atomic_dec(&net_device_ctx->vf_use_cnt);
-			goto vf_injection_done;
-		}
-
-		/*
-		 * Inject this packet into the VF inerface.
-		 * On Hyper-V, multicast and brodcast packets
-		 * are only delivered on the synthetic interface
-		 * (after subjecting these to policy filters on
-		 * the host). Deliver these via the VF interface
-		 * in the guest.
-		 */
-		vf_skb = netvsc_alloc_recv_skb(vf_netdev,
-					       packet, csum_info, *data,
-					       vlan_tci);
-		if (vf_skb != NULL) {
-			++vf_netdev->stats.rx_packets;
-			vf_netdev->stats.rx_bytes += bytes_recvd;
-			netif_receive_skb(vf_skb);
-		} else {
-			++net->stats.rx_dropped;
-			ret = NVSP_STAT_FAIL;
-		}
-		atomic_dec(&net_device_ctx->vf_use_cnt);
-		return ret;
-	}
-
-vf_injection_done:
-	rx_stats = this_cpu_ptr(net_device_ctx->rx_stats);
+	if (vf_netdev && (vf_netdev->flags & IFF_UP))
+		net = vf_netdev;
 
 	/* Allocate a skb - TODO direct I/O to pages? */
 	skb = netvsc_alloc_recv_skb(net, packet, csum_info, *data, vlan_tci);
@@ -721,9 +691,17 @@ vf_injection_done:
 		++net->stats.rx_dropped;
 		return NVSP_STAT_FAIL;
 	}
-	skb_record_rx_queue(skb, channel->
-			    offermsg.offer.sub_channel_index);
 
+	if (net != vf_netdev)
+		skb_record_rx_queue(skb,
+				    channel->offermsg.offer.sub_channel_index);
+
+	/*
+	 * Even if injecting the packet, record the statistics
+	 * on the synthetic device because modifying the VF device
+	 * statistics will not work correctly.
+	 */
+	rx_stats = this_cpu_ptr(net_device_ctx->rx_stats);
 	u64_stats_update_begin(&rx_stats->syncp);
 	rx_stats->packets++;
 	rx_stats->bytes += packet->total_data_buflen;
@@ -1291,20 +1269,6 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
 	return NOTIFY_OK;
 }
 
-static void netvsc_inject_enable(struct net_device_context *net_device_ctx)
-{
-	net_device_ctx->vf_inject = true;
-}
-
-static void netvsc_inject_disable(struct net_device_context *net_device_ctx)
-{
-	net_device_ctx->vf_inject = false;
-
-	/* Wait for currently active users to drain out. */
-	while (atomic_read(&net_device_ctx->vf_use_cnt) != 0)
-		udelay(50);
-}
-
 static int netvsc_vf_up(struct net_device *vf_netdev)
 {
 	struct net_device *ndev;
@@ -1319,7 +1283,6 @@ static int netvsc_vf_up(struct net_device *vf_netdev)
 	netvsc_dev = net_device_ctx->nvdev;
 
 	netdev_info(ndev, "VF up: %s\n", vf_netdev->name);
-	netvsc_inject_enable(net_device_ctx);
 
 	/*
 	 * Open the device before switching data path.
@@ -1354,7 +1317,6 @@ static int netvsc_vf_down(struct net_device *vf_netdev)
 	netvsc_dev = net_device_ctx->nvdev;
 
 	netdev_info(ndev, "VF down: %s\n", vf_netdev->name);
-	netvsc_inject_disable(net_device_ctx);
 	netvsc_switch_datapath(ndev, false);
 	netdev_info(ndev, "Data path switched from VF: %s\n", vf_netdev->name);
 	rndis_filter_close(netvsc_dev);
@@ -1380,7 +1342,6 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
 	netvsc_dev = net_device_ctx->nvdev;
 
 	netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
-	netvsc_inject_disable(net_device_ctx);
 
 	RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
 	dev_put(vf_netdev);
@@ -1435,8 +1396,6 @@ static int netvsc_probe(struct hv_device *dev,
 	spin_lock_init(&net_device_ctx->lock);
 	INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
 
-	atomic_set(&net_device_ctx->vf_use_cnt, 0);
-
 	net->netdev_ops = &device_ops;
 
 	net->hw_features = NETVSC_HW_FEATURES;
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 7/7] hv_netvsc: count multicast packets received
  2016-09-22 23:56 [PATCH net-next 0/7] hv_netvsc changes sthemmin
                   ` (5 preceding siblings ...)
  2016-09-22 23:56 ` [PATCH 6/7] hv_netvsc: remove VF in flight counters sthemmin
@ 2016-09-22 23:56 ` sthemmin
  2016-09-23 12:21 ` [PATCH net-next 0/7] hv_netvsc changes David Miller
  7 siblings, 0 replies; 9+ messages in thread
From: sthemmin @ 2016-09-22 23:56 UTC (permalink / raw)
  To: K. Y. Srinivasan, Haiyang Zhang, davem; +Cc: netdev, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Useful for debugging issues with multicast and SR-IOV to keep track
of number of received multicast packets.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 drivers/net/hyperv/hyperv_net.h |    2 ++
 drivers/net/hyperv/netvsc_drv.c |    9 ++++++++-
 2 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 1d49740..7130bf9 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -649,6 +649,8 @@ struct multi_recv_comp {
 struct netvsc_stats {
 	u64 packets;
 	u64 bytes;
+	u64 broadcast;
+	u64 multicast;
 	struct u64_stats_sync syncp;
 };
 
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 9375d82..52eeb2f 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -705,6 +705,11 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 	u64_stats_update_begin(&rx_stats->syncp);
 	rx_stats->packets++;
 	rx_stats->bytes += packet->total_data_buflen;
+
+	if (skb->pkt_type == PACKET_BROADCAST)
+		++rx_stats->broadcast;
+	else if (skb->pkt_type == PACKET_MULTICAST)
+		++rx_stats->multicast;
 	u64_stats_update_end(&rx_stats->syncp);
 
 	/*
@@ -947,7 +952,7 @@ static struct rtnl_link_stats64 *netvsc_get_stats64(struct net_device *net,
 							    cpu);
 		struct netvsc_stats *rx_stats = per_cpu_ptr(ndev_ctx->rx_stats,
 							    cpu);
-		u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
+		u64 tx_packets, tx_bytes, rx_packets, rx_bytes, rx_multicast;
 		unsigned int start;
 
 		do {
@@ -960,12 +965,14 @@ static struct rtnl_link_stats64 *netvsc_get_stats64(struct net_device *net,
 			start = u64_stats_fetch_begin_irq(&rx_stats->syncp);
 			rx_packets = rx_stats->packets;
 			rx_bytes = rx_stats->bytes;
+			rx_multicast = rx_stats->multicast + rx_stats->broadcast;
 		} while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start));
 
 		t->tx_bytes	+= tx_bytes;
 		t->tx_packets	+= tx_packets;
 		t->rx_bytes	+= rx_bytes;
 		t->rx_packets	+= rx_packets;
+		t->multicast	+= rx_multicast;
 	}
 
 	t->tx_dropped	= net->stats.tx_dropped;
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH net-next 0/7] hv_netvsc changes
  2016-09-22 23:56 [PATCH net-next 0/7] hv_netvsc changes sthemmin
                   ` (6 preceding siblings ...)
  2016-09-22 23:56 ` [PATCH 7/7] hv_netvsc: count multicast packets received sthemmin
@ 2016-09-23 12:21 ` David Miller
  7 siblings, 0 replies; 9+ messages in thread
From: David Miller @ 2016-09-23 12:21 UTC (permalink / raw)
  To: sthemmin, sthemmin; +Cc: kys, haiyangz, netdev

From: sthemmin@exchange.microsoft.com
Date: Thu, 22 Sep 2016 16:56:28 -0700

> These are mostly about improving the handling of interaction between
> the virtual network device (netvsc) and the SR-IOV VF network device.

Series applied, thanks Stephen.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-09-23 12:21 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-22 23:56 [PATCH net-next 0/7] hv_netvsc changes sthemmin
2016-09-22 23:56 ` [PATCH 1/7] hv_netvsc: use consume_skb sthemmin
2016-09-22 23:56 ` [PATCH 2/7] hv_netvsc: dev hold/put reference to VF sthemmin
2016-09-22 23:56 ` [PATCH 3/7] hv_netvsc: simplify callback event code sthemmin
2016-09-22 23:56 ` [PATCH 4/7] hv_netvsc: improve VF device matching sthemmin
2016-09-22 23:56 ` [PATCH 5/7] hv_netvsc: use RCU to protect vf_netdev sthemmin
2016-09-22 23:56 ` [PATCH 6/7] hv_netvsc: remove VF in flight counters sthemmin
2016-09-22 23:56 ` [PATCH 7/7] hv_netvsc: count multicast packets received sthemmin
2016-09-23 12:21 ` [PATCH net-next 0/7] hv_netvsc changes David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.