Olaf Hering 01a7c5
From: Haiyang Zhang <haiyangz@microsoft.com>
Olaf Hering 01a7c5
Date: Thu, 23 Jan 2020 13:52:34 -0800
Olaf Hering 01a7c5
Patch-mainline: v5.6-rc1
Olaf Hering 01a7c5
Subject: hv_netvsc: Add XDP support
Olaf Hering 01a7c5
Git-commit: 351e1581395fcc7fb952bbd7dda01238f69968fd
Olaf Hering 01a7c5
References: bsc#1177819, bsc#1177820
Olaf Hering 01a7c5
Olaf Hering 01a7c5
This patch adds support of XDP in native mode for hv_netvsc driver, and
Olaf Hering 01a7c5
transparently sets the XDP program on the associated VF NIC as well.
Olaf Hering 01a7c5
Olaf Hering 01a7c5
Setting / unsetting XDP program on synthetic NIC (netvsc) propagates to
Olaf Hering 01a7c5
VF NIC automatically. Setting / unsetting XDP program on VF NIC directly
Olaf Hering 01a7c5
is not recommended, also not propagated to synthetic NIC, and may be
Olaf Hering 01a7c5
overwritten by setting of synthetic NIC.
Olaf Hering 01a7c5
Olaf Hering 01a7c5
The Azure/Hyper-V synthetic NIC receive buffer doesn't provide headroom
Olaf Hering 01a7c5
for XDP. We thought about re-use the RNDIS header space, but it's too
Olaf Hering 01a7c5
small. So we decided to copy the packets to a page buffer for XDP. And,
Olaf Hering 01a7c5
most of our VMs on Azure have Accelerated  Network (SRIOV) enabled, so
Olaf Hering 01a7c5
most of the packets run on VF NIC. The synthetic NIC is considered as a
Olaf Hering 01a7c5
fallback data-path. So the data copy on netvsc won't impact performance
Olaf Hering 01a7c5
significantly.
Olaf Hering 01a7c5
Olaf Hering 01a7c5
XDP program cannot run with LRO (RSC) enabled, so you need to disable LRO
Olaf Hering 01a7c5
before running XDP:
Olaf Hering 01a7c5
        ethtool -K eth0 lro off
Olaf Hering 01a7c5
Olaf Hering 01a7c5
XDP actions not yet supported:
Olaf Hering 01a7c5
        XDP_REDIRECT
Olaf Hering 01a7c5
Olaf Hering 01a7c5
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Olaf Hering 01a7c5
Signed-off-by: David S. Miller <davem@davemloft.net>
Olaf Hering 01a7c5
Acked-by: Olaf Hering <ohering@suse.de>
Olaf Hering 01a7c5
---
Olaf Hering 01a7c5
 drivers/net/hyperv/Makefile       |   2 +-
Olaf Hering 01a7c5
 drivers/net/hyperv/hyperv_net.h   |  21 +++-
Olaf Hering 01a7c5
 drivers/net/hyperv/netvsc.c       |  31 +++++-
Olaf Hering 01a7c5
 drivers/net/hyperv/netvsc_bpf.c   | 209 ++++++++++++++++++++++++++++++++++++++
Olaf Hering 01a7c5
 drivers/net/hyperv/netvsc_drv.c   | 183 +++++++++++++++++++++++++++------
Olaf Hering 01a7c5
 drivers/net/hyperv/rndis_filter.c |   2 +-
Olaf Hering 01a7c5
 6 files changed, 409 insertions(+), 39 deletions(-)
Olaf Hering 01a7c5
 create mode 100644 drivers/net/hyperv/netvsc_bpf.c
Olaf Hering 01a7c5
Olaf Hering 01a7c5
diff --git a/drivers/net/hyperv/Makefile b/drivers/net/hyperv/Makefile
Olaf Hering 01a7c5
--- a/drivers/net/hyperv/Makefile
Olaf Hering 01a7c5
+++ b/drivers/net/hyperv/Makefile
Olaf Hering 01a7c5
@@ -1,3 +1,3 @@
Olaf Hering 01a7c5
 obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o netvsc_trace.o
Olaf Hering 01a7c5
+hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o netvsc_trace.o netvsc_bpf.o
Olaf Hering 01a7c5
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
Olaf Hering 01a7c5
--- a/drivers/net/hyperv/hyperv_net.h
Olaf Hering 01a7c5
+++ b/drivers/net/hyperv/hyperv_net.h
Olaf Hering 01a7c5
@@ -142,6 +142,8 @@ struct netvsc_device_info {
Olaf Hering 01a7c5
 	u32  send_section_size;
Olaf Hering 01a7c5
 	u32  recv_section_size;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+	struct bpf_prog *bprog;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 	u8 rss_key[NETVSC_HASH_KEYLEN];
Olaf Hering 01a7c5
 };
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -189,7 +191,8 @@ int netvsc_send(struct net_device *net,
Olaf Hering 01a7c5
 		struct hv_netvsc_packet *packet,
Olaf Hering 01a7c5
 		struct rndis_message *rndis_msg,
Olaf Hering 01a7c5
 		struct hv_page_buffer *page_buffer,
Olaf Hering 01a7c5
-		struct sk_buff *skb);
Olaf Hering 01a7c5
+		struct sk_buff *skb,
Olaf Hering 01a7c5
+		bool xdp_tx);
Olaf Hering 01a7c5
 void netvsc_linkstatus_callback(struct net_device *net,
Olaf Hering 01a7c5
 				struct rndis_message *resp);
Olaf Hering 01a7c5
 int netvsc_recv_callback(struct net_device *net,
Olaf Hering 01a7c5
@@ -198,6 +201,16 @@ int netvsc_recv_callback(struct net_device *net,
Olaf Hering 01a7c5
 void netvsc_channel_cb(void *context);
Olaf Hering 01a7c5
 int netvsc_poll(struct napi_struct *napi, int budget);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+u32 netvsc_run_xdp(struct net_device *ndev, struct netvsc_channel *nvchan,
Olaf Hering 01a7c5
+		   struct xdp_buff *xdp);
Olaf Hering 01a7c5
+unsigned int netvsc_xdp_fraglen(unsigned int len);
Olaf Hering 01a7c5
+struct bpf_prog *netvsc_xdp_get(struct netvsc_device *nvdev);
Olaf Hering 01a7c5
+int netvsc_xdp_set(struct net_device *dev, struct bpf_prog *prog,
Olaf Hering 01a7c5
+		   struct netlink_ext_ack *extack,
Olaf Hering 01a7c5
+		   struct netvsc_device *nvdev);
Olaf Hering 01a7c5
+int netvsc_vf_setxdp(struct net_device *vf_netdev, struct bpf_prog *prog);
Olaf Hering 01a7c5
+int netvsc_bpf(struct net_device *dev, struct netdev_bpf *bpf);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 int rndis_set_subchannel(struct net_device *ndev,
Olaf Hering 01a7c5
 			 struct netvsc_device *nvdev,
Olaf Hering 01a7c5
 			 struct netvsc_device_info *dev_info);
Olaf Hering 01a7c5
@@ -832,6 +845,8 @@ struct nvsp_message {
Olaf Hering 01a7c5
 #define RNDIS_MAX_PKT_DEFAULT 8
Olaf Hering 01a7c5
 #define RNDIS_PKT_ALIGN_DEFAULT 8
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+#define NETVSC_XDP_HDRM 256
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 struct multi_send_data {
Olaf Hering 01a7c5
 	struct sk_buff *skb; /* skb containing the pkt */
Olaf Hering 01a7c5
 	struct hv_netvsc_packet *pkt; /* netvsc pkt pending */
Olaf Hering 01a7c5
@@ -867,6 +882,7 @@ struct netvsc_stats {
Olaf Hering 01a7c5
 	u64 bytes;
Olaf Hering 01a7c5
 	u64 broadcast;
Olaf Hering 01a7c5
 	u64 multicast;
Olaf Hering 01a7c5
+	u64 xdp_drop;
Olaf Hering 01a7c5
 	struct u64_stats_sync syncp;
Olaf Hering 01a7c5
 };
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -972,6 +988,9 @@ struct netvsc_channel {
Olaf Hering 01a7c5
 	atomic_t queue_sends;
Olaf Hering 01a7c5
 	struct nvsc_rsc rsc;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+	struct bpf_prog __rcu *bpf_prog;
Olaf Hering 01a7c5
+	struct xdp_rxq_info xdp_rxq;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 	struct netvsc_stats tx_stats;
Olaf Hering 01a7c5
 	struct netvsc_stats rx_stats;
Olaf Hering 01a7c5
 };
Olaf Hering 01a7c5
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
Olaf Hering 01a7c5
--- a/drivers/net/hyperv/netvsc.c
Olaf Hering 01a7c5
+++ b/drivers/net/hyperv/netvsc.c
Olaf Hering 01a7c5
@@ -122,8 +122,10 @@ static void free_netvsc_device(struct rcu_head *head)
Olaf Hering 01a7c5
 	vfree(nvdev->send_buf);
Olaf Hering 01a7c5
 	kfree(nvdev->send_section_map);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-	for (i = 0; i < VRSS_CHANNEL_MAX; i++)
Olaf Hering 01a7c5
+	for (i = 0; i < VRSS_CHANNEL_MAX; i++) {
Olaf Hering 01a7c5
+		xdp_rxq_info_unreg(&nvdev->chan_table[i].xdp_rxq);
Olaf Hering 01a7c5
 		vfree(nvdev->chan_table[i].mrc.slots);
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	kfree(nvdev);
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
@@ -900,7 +902,8 @@ int netvsc_send(struct net_device *ndev,
Olaf Hering 01a7c5
 		struct hv_netvsc_packet *packet,
Olaf Hering 01a7c5
 		struct rndis_message *rndis_msg,
Olaf Hering 01a7c5
 		struct hv_page_buffer *pb,
Olaf Hering 01a7c5
-		struct sk_buff *skb)
Olaf Hering 01a7c5
+		struct sk_buff *skb,
Olaf Hering 01a7c5
+		bool xdp_tx)
Olaf Hering 01a7c5
 {
Olaf Hering 01a7c5
 	struct net_device_context *ndev_ctx = netdev_priv(ndev);
Olaf Hering 01a7c5
 	struct netvsc_device *net_device
Olaf Hering 01a7c5
@@ -923,10 +926,11 @@ int netvsc_send(struct net_device *ndev,
Olaf Hering 01a7c5
 	packet->send_buf_index = NETVSC_INVALID_INDEX;
Olaf Hering 01a7c5
 	packet->cp_partial = false;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-	/* Send control message directly without accessing msd (Multi-Send
Olaf Hering 01a7c5
-	 * Data) field which may be changed during data packet processing.
Olaf Hering 01a7c5
+	/* Send a control message or XDP packet directly without accessing
Olaf Hering 01a7c5
+	 * msd (Multi-Send Data) field which may be changed during data packet
Olaf Hering 01a7c5
+	 * processing.
Olaf Hering 01a7c5
 	 */
Olaf Hering 01a7c5
-	if (!skb)
Olaf Hering 01a7c5
+	if (!skb || xdp_tx)
Olaf Hering 01a7c5
 		return netvsc_send_pkt(device, packet, net_device, pb, skb);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	/* batch packets in send buffer if possible */
Olaf Hering 01a7c5
@@ -1392,6 +1396,21 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
Olaf Hering 01a7c5
 		nvchan->net_device = net_device;
Olaf Hering 01a7c5
 		u64_stats_init(&nvchan->tx_stats.syncp);
Olaf Hering 01a7c5
 		u64_stats_init(&nvchan->rx_stats.syncp);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		ret = xdp_rxq_info_reg(&nvchan->xdp_rxq, ndev, i);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		if (ret) {
Olaf Hering 01a7c5
+			netdev_err(ndev, "xdp_rxq_info_reg fail: %d\n", ret);
Olaf Hering 01a7c5
+			goto cleanup2;
Olaf Hering 01a7c5
+		}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		ret = xdp_rxq_info_reg_mem_model(&nvchan->xdp_rxq,
Olaf Hering 01a7c5
+						 MEM_TYPE_PAGE_SHARED, NULL);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		if (ret) {
Olaf Hering 01a7c5
+			netdev_err(ndev, "xdp reg_mem_model fail: %d\n", ret);
Olaf Hering 01a7c5
+			goto cleanup2;
Olaf Hering 01a7c5
+		}
Olaf Hering 01a7c5
 	}
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	/* Enable NAPI handler before init callbacks */
Olaf Hering 01a7c5
@@ -1437,6 +1456,8 @@ close:
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 cleanup:
Olaf Hering 01a7c5
 	netif_napi_del(&net_device->chan_table[0].napi);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+cleanup2:
Olaf Hering 01a7c5
 	free_netvsc_device(&net_device->rcu);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	return ERR_PTR(ret);
Olaf Hering 01a7c5
diff --git a/drivers/net/hyperv/netvsc_bpf.c b/drivers/net/hyperv/netvsc_bpf.c
Olaf Hering 01a7c5
new file mode 100644
Olaf Hering 01a7c5
index 000000000000..20adfe544294
Olaf Hering 01a7c5
--- /dev/null
Olaf Hering 01a7c5
+++ b/drivers/net/hyperv/netvsc_bpf.c
Olaf Hering 01a7c5
@@ -0,0 +1,209 @@
Olaf Hering 01a7c5
+// SPDX-License-Identifier: GPL-2.0-only
Olaf Hering 01a7c5
+/* Copyright (c) 2019, Microsoft Corporation.
Olaf Hering 01a7c5
+ *
Olaf Hering 01a7c5
+ * Author:
Olaf Hering 01a7c5
+ *   Haiyang Zhang <haiyangz@microsoft.com>
Olaf Hering 01a7c5
+ */
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+#include <linux/netdevice.h>
Olaf Hering 01a7c5
+#include <linux/etherdevice.h>
Olaf Hering 01a7c5
+#include <linux/ethtool.h>
Olaf Hering 01a7c5
+#include <linux/bpf.h>
Olaf Hering 01a7c5
+#include <linux/bpf_trace.h>
Olaf Hering 01a7c5
+#include <linux/kernel.h>
Olaf Hering 01a7c5
+#include <net/xdp.h>
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+#include <linux/mutex.h>
Olaf Hering 01a7c5
+#include <linux/rtnetlink.h>
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+#include "hyperv_net.h"
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+u32 netvsc_run_xdp(struct net_device *ndev, struct netvsc_channel *nvchan,
Olaf Hering 01a7c5
+		   struct xdp_buff *xdp)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	void *data = nvchan->rsc.data[0];
Olaf Hering 01a7c5
+	u32 len = nvchan->rsc.len[0];
Olaf Hering 01a7c5
+	struct page *page = NULL;
Olaf Hering 01a7c5
+	struct bpf_prog *prog;
Olaf Hering 01a7c5
+	u32 act = XDP_PASS;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	xdp->data_hard_start = NULL;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	rcu_read_lock();
Olaf Hering 01a7c5
+	prog = rcu_dereference(nvchan->bpf_prog);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (!prog)
Olaf Hering 01a7c5
+		goto out;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	/* allocate page buffer for data */
Olaf Hering 01a7c5
+	page = alloc_page(GFP_ATOMIC);
Olaf Hering 01a7c5
+	if (!page) {
Olaf Hering 01a7c5
+		act = XDP_DROP;
Olaf Hering 01a7c5
+		goto out;
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	xdp->data_hard_start = page_address(page);
Olaf Hering 01a7c5
+	xdp->data = xdp->data_hard_start + NETVSC_XDP_HDRM;
Olaf Hering 01a7c5
+	xdp_set_data_meta_invalid(xdp);
Olaf Hering 01a7c5
+	xdp->data_end = xdp->data + len;
Olaf Hering 01a7c5
+	xdp->rxq = &nvchan->xdp_rxq;
Olaf Hering 01a7c5
+	xdp->handle = 0;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	memcpy(xdp->data, data, len);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	act = bpf_prog_run_xdp(prog, xdp);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	switch (act) {
Olaf Hering 01a7c5
+	case XDP_PASS:
Olaf Hering 01a7c5
+	case XDP_TX:
Olaf Hering 01a7c5
+	case XDP_DROP:
Olaf Hering 01a7c5
+		break;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	case XDP_ABORTED:
Olaf Hering 01a7c5
+		trace_xdp_exception(ndev, prog, act);
Olaf Hering 01a7c5
+		break;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	default:
Olaf Hering 01a7c5
+		bpf_warn_invalid_xdp_action(act);
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+out:
Olaf Hering 01a7c5
+	rcu_read_unlock();
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (page && act != XDP_PASS && act != XDP_TX) {
Olaf Hering 01a7c5
+		__free_page(page);
Olaf Hering 01a7c5
+		xdp->data_hard_start = NULL;
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	return act;
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+unsigned int netvsc_xdp_fraglen(unsigned int len)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	return SKB_DATA_ALIGN(len) +
Olaf Hering 01a7c5
+	       SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+struct bpf_prog *netvsc_xdp_get(struct netvsc_device *nvdev)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	return rtnl_dereference(nvdev->chan_table[0].bpf_prog);
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+int netvsc_xdp_set(struct net_device *dev, struct bpf_prog *prog,
Olaf Hering 01a7c5
+		   struct netlink_ext_ack *extack,
Olaf Hering 01a7c5
+		   struct netvsc_device *nvdev)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	struct bpf_prog *old_prog;
Olaf Hering 01a7c5
+	int buf_max, i;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	old_prog = netvsc_xdp_get(nvdev);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (!old_prog && !prog)
Olaf Hering 01a7c5
+		return 0;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	buf_max = NETVSC_XDP_HDRM + netvsc_xdp_fraglen(dev->mtu + ETH_HLEN);
Olaf Hering 01a7c5
+	if (prog && buf_max > PAGE_SIZE) {
Olaf Hering 01a7c5
+		netdev_err(dev, "XDP: mtu:%u too large, buf_max:%u\n",
Olaf Hering 01a7c5
+			   dev->mtu, buf_max);
Olaf Hering 01a7c5
+		NL_SET_ERR_MSG_MOD(extack, "XDP: mtu too large");
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		return -EOPNOTSUPP;
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (prog && (dev->features & NETIF_F_LRO)) {
Olaf Hering 01a7c5
+		netdev_err(dev, "XDP: not support LRO\n");
Olaf Hering 01a7c5
+		NL_SET_ERR_MSG_MOD(extack, "XDP: not support LRO");
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		return -EOPNOTSUPP;
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (prog)
Olaf Hering 01a7c5
+		bpf_prog_add(prog, nvdev->num_chn);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	for (i = 0; i < nvdev->num_chn; i++)
Olaf Hering 01a7c5
+		rcu_assign_pointer(nvdev->chan_table[i].bpf_prog, prog);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (old_prog)
Olaf Hering 01a7c5
+		for (i = 0; i < nvdev->num_chn; i++)
Olaf Hering 01a7c5
+			bpf_prog_put(old_prog);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	return 0;
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+int netvsc_vf_setxdp(struct net_device *vf_netdev, struct bpf_prog *prog)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	struct netdev_bpf xdp;
Olaf Hering 01a7c5
+	bpf_op_t ndo_bpf;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	ASSERT_RTNL();
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (!vf_netdev)
Olaf Hering 01a7c5
+		return 0;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	ndo_bpf = vf_netdev->netdev_ops->ndo_bpf;
Olaf Hering 01a7c5
+	if (!ndo_bpf)
Olaf Hering 01a7c5
+		return 0;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	memset(&xdp, 0, sizeof(xdp));
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	xdp.command = XDP_SETUP_PROG;
Olaf Hering 01a7c5
+	xdp.prog = prog;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	return ndo_bpf(vf_netdev, &xdp;;
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+static u32 netvsc_xdp_query(struct netvsc_device *nvdev)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	struct bpf_prog *prog = netvsc_xdp_get(nvdev);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (prog)
Olaf Hering 01a7c5
+		return prog->aux->id;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	return 0;
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+int netvsc_bpf(struct net_device *dev, struct netdev_bpf *bpf)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	struct net_device_context *ndevctx = netdev_priv(dev);
Olaf Hering 01a7c5
+	struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
Olaf Hering 01a7c5
+	struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev);
Olaf Hering 01a7c5
+	struct netlink_ext_ack *extack = bpf->extack;
Olaf Hering 01a7c5
+	int ret;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (!nvdev || nvdev->destroy) {
Olaf Hering 01a7c5
+		if (bpf->command == XDP_QUERY_PROG) {
Olaf Hering 01a7c5
+			bpf->prog_id = 0;
Olaf Hering 01a7c5
+			return 0; /* Query must always succeed */
Olaf Hering 01a7c5
+		} else {
Olaf Hering 01a7c5
+			return -ENODEV;
Olaf Hering 01a7c5
+		}
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	switch (bpf->command) {
Olaf Hering 01a7c5
+	case XDP_SETUP_PROG:
Olaf Hering 01a7c5
+		ret = netvsc_xdp_set(dev, bpf->prog, extack, nvdev);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		if (ret)
Olaf Hering 01a7c5
+			return ret;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		ret = netvsc_vf_setxdp(vf_netdev, bpf->prog);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		if (ret) {
Olaf Hering 01a7c5
+			netdev_err(dev, "vf_setxdp failed:%d\n", ret);
Olaf Hering 01a7c5
+			NL_SET_ERR_MSG_MOD(extack, "vf_setxdp failed");
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+			netvsc_xdp_set(dev, NULL, extack, nvdev);
Olaf Hering 01a7c5
+		}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		return ret;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	case XDP_QUERY_PROG:
Olaf Hering 01a7c5
+		bpf->prog_id = netvsc_xdp_query(nvdev);
Olaf Hering 01a7c5
+		return 0;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	default:
Olaf Hering 01a7c5
+		return -EINVAL;
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
Olaf Hering 01a7c5
--- a/drivers/net/hyperv/netvsc_drv.c
Olaf Hering 01a7c5
+++ b/drivers/net/hyperv/netvsc_drv.c
Olaf Hering 01a7c5
@@ -25,6 +25,7 @@
Olaf Hering 01a7c5
 #include <linux/slab.h>
Olaf Hering 01a7c5
 #include <linux/rtnetlink.h>
Olaf Hering 01a7c5
 #include <linux/netpoll.h>
Olaf Hering 01a7c5
+#include <linux/bpf.h>
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 #include <net/arp.h>
Olaf Hering 01a7c5
 #include <net/route.h>
Olaf Hering 01a7c5
@@ -519,7 +520,7 @@ static int netvsc_vf_xmit(struct net_device *net, struct net_device *vf_netdev,
Olaf Hering 01a7c5
 	return rc;
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
Olaf Hering 01a7c5
+static int netvsc_xmit(struct sk_buff *skb, struct net_device *net, bool xdp_tx)
Olaf Hering 01a7c5
 {
Olaf Hering 01a7c5
 	struct net_device_context *net_device_ctx = netdev_priv(net);
Olaf Hering 01a7c5
 	struct hv_netvsc_packet *packet = NULL;
Olaf Hering 01a7c5
@@ -686,7 +687,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
Olaf Hering 01a7c5
 	/* timestamp packet in software */
Olaf Hering 01a7c5
 	skb_tx_timestamp(skb);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-	ret = netvsc_send(net, packet, rndis_msg, pb, skb);
Olaf Hering 01a7c5
+	ret = netvsc_send(net, packet, rndis_msg, pb, skb, xdp_tx);
Olaf Hering 01a7c5
 	if (likely(ret == 0))
Olaf Hering 01a7c5
 		return NETDEV_TX_OK;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -709,6 +710,11 @@ no_memory:
Olaf Hering 01a7c5
 	goto drop;
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *ndev)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	return netvsc_xmit(skb, ndev, false);
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 /*
Olaf Hering 01a7c5
  * netvsc_linkstatus_callback - Link up/down notification
Olaf Hering 01a7c5
  */
Olaf Hering 01a7c5
@@ -751,6 +757,22 @@ void netvsc_linkstatus_callback(struct net_device *net,
Olaf Hering 01a7c5
 	schedule_delayed_work(&ndev_ctx->dwork, 0);
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+static void netvsc_xdp_xmit(struct sk_buff *skb, struct net_device *ndev)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	int rc;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	skb->queue_mapping = skb_get_rx_queue(skb);
Olaf Hering 01a7c5
+	__skb_push(skb, ETH_HLEN);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	rc = netvsc_xmit(skb, ndev, true);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (dev_xmit_complete(rc))
Olaf Hering 01a7c5
+		return;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	dev_kfree_skb_any(skb);
Olaf Hering 01a7c5
+	ndev->stats.tx_dropped++;
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 static void netvsc_comp_ipcsum(struct sk_buff *skb)
Olaf Hering 01a7c5
 {
Olaf Hering 01a7c5
 	struct iphdr *iph = (struct iphdr *)skb->data;
Olaf Hering 01a7c5
@@ -760,7 +782,8 @@ static void netvsc_comp_ipcsum(struct sk_buff *skb)
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
Olaf Hering 01a7c5
-					     struct netvsc_channel *nvchan)
Olaf Hering 01a7c5
+					     struct netvsc_channel *nvchan,
Olaf Hering 01a7c5
+					     struct xdp_buff *xdp)
Olaf Hering 01a7c5
 {
Olaf Hering 01a7c5
 	struct napi_struct *napi = &nvchan->napi;
Olaf Hering 01a7c5
 	const struct ndis_pkt_8021q_info *vlan = nvchan->rsc.vlan;
Olaf Hering 01a7c5
@@ -768,18 +791,37 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
Olaf Hering 01a7c5
 	const struct ndis_tcp_ip_checksum_info *csum_info =
Olaf Hering 01a7c5
 						nvchan->rsc.csum_info;
Olaf Hering 01a7c5
 	struct sk_buff *skb;
Olaf Hering 01a7c5
+	void *xbuf = xdp->data_hard_start;
Olaf Hering 01a7c5
 	int i;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-	skb = napi_alloc_skb(napi, nvchan->rsc.pktlen);
Olaf Hering 01a7c5
-	if (!skb)
Olaf Hering 01a7c5
-		return skb;
Olaf Hering 01a7c5
+	if (xbuf) {
Olaf Hering 01a7c5
+		unsigned int hdroom = xdp->data - xdp->data_hard_start;
Olaf Hering 01a7c5
+		unsigned int xlen = xdp->data_end - xdp->data;
Olaf Hering 01a7c5
+		unsigned int frag_size = netvsc_xdp_fraglen(hdroom + xlen);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-	/*
Olaf Hering 01a7c5
-	 * Copy to skb. This copy is needed here since the memory pointed by
Olaf Hering 01a7c5
-	 * hv_netvsc_packet cannot be deallocated
Olaf Hering 01a7c5
-	 */
Olaf Hering 01a7c5
-	for (i = 0; i < nvchan->rsc.cnt; i++)
Olaf Hering 01a7c5
-		skb_put_data(skb, nvchan->rsc.data[i], nvchan->rsc.len[i]);
Olaf Hering 01a7c5
+		skb = build_skb(xbuf, frag_size);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		if (!skb) {
Olaf Hering 01a7c5
+			__free_page(virt_to_page(xbuf));
Olaf Hering 01a7c5
+			return NULL;
Olaf Hering 01a7c5
+		}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		skb_reserve(skb, hdroom);
Olaf Hering 01a7c5
+		skb_put(skb, xlen);
Olaf Hering 01a7c5
+		skb->dev = napi->dev;
Olaf Hering 01a7c5
+	} else {
Olaf Hering 01a7c5
+		skb = napi_alloc_skb(napi, nvchan->rsc.pktlen);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		if (!skb)
Olaf Hering 01a7c5
+			return NULL;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		/* Copy to skb. This copy is needed here since the memory
Olaf Hering 01a7c5
+		 * pointed by hv_netvsc_packet cannot be deallocated.
Olaf Hering 01a7c5
+		 */
Olaf Hering 01a7c5
+		for (i = 0; i < nvchan->rsc.cnt; i++)
Olaf Hering 01a7c5
+			skb_put_data(skb, nvchan->rsc.data[i],
Olaf Hering 01a7c5
+				     nvchan->rsc.len[i]);
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	skb->protocol = eth_type_trans(skb, net);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -829,13 +871,25 @@ int netvsc_recv_callback(struct net_device *net,
Olaf Hering 01a7c5
 	struct vmbus_channel *channel = nvchan->channel;
Olaf Hering 01a7c5
 	u16 q_idx = channel->offermsg.offer.sub_channel_index;
Olaf Hering 01a7c5
 	struct sk_buff *skb;
Olaf Hering 01a7c5
-	struct netvsc_stats *rx_stats;
Olaf Hering 01a7c5
+	struct netvsc_stats *rx_stats = &nvchan->rx_stats;
Olaf Hering 01a7c5
+	struct xdp_buff xdp;
Olaf Hering 01a7c5
+	u32 act;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	if (net->reg_state != NETREG_REGISTERED)
Olaf Hering 01a7c5
 		return NVSP_STAT_FAIL;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+	act = netvsc_run_xdp(net, nvchan, &xdp;;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (act != XDP_PASS && act != XDP_TX) {
Olaf Hering 01a7c5
+		u64_stats_update_begin(&rx_stats->syncp);
Olaf Hering 01a7c5
+		rx_stats->xdp_drop++;
Olaf Hering 01a7c5
+		u64_stats_update_end(&rx_stats->syncp);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		return NVSP_STAT_SUCCESS; /* consumed by XDP */
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 	/* Allocate a skb - TODO direct I/O to pages? */
Olaf Hering 01a7c5
-	skb = netvsc_alloc_recv_skb(net, nvchan);
Olaf Hering 01a7c5
+	skb = netvsc_alloc_recv_skb(net, nvchan, &xdp;;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	if (unlikely(!skb)) {
Olaf Hering 01a7c5
 		++net_device_ctx->eth_stats.rx_no_memory;
Olaf Hering 01a7c5
@@ -849,7 +903,6 @@ int netvsc_recv_callback(struct net_device *net,
Olaf Hering 01a7c5
 	 * on the synthetic device because modifying the VF device
Olaf Hering 01a7c5
 	 * statistics will not work correctly.
Olaf Hering 01a7c5
 	 */
Olaf Hering 01a7c5
-	rx_stats = &nvchan->rx_stats;
Olaf Hering 01a7c5
 	u64_stats_update_begin(&rx_stats->syncp);
Olaf Hering 01a7c5
 	rx_stats->packets++;
Olaf Hering 01a7c5
 	rx_stats->bytes += nvchan->rsc.pktlen;
Olaf Hering 01a7c5
@@ -860,6 +913,11 @@ int netvsc_recv_callback(struct net_device *net,
Olaf Hering 01a7c5
 		++rx_stats->multicast;
Olaf Hering 01a7c5
 	u64_stats_update_end(&rx_stats->syncp);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+	if (act == XDP_TX) {
Olaf Hering 01a7c5
+		netvsc_xdp_xmit(skb, net);
Olaf Hering 01a7c5
+		return NVSP_STAT_SUCCESS;
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 	napi_gro_receive(&nvchan->napi, skb);
Olaf Hering 01a7c5
 	return NVSP_STAT_SUCCESS;
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
@@ -886,10 +944,11 @@ static void netvsc_get_channels(struct net_device *net,
Olaf Hering 01a7c5
 /* Alloc struct netvsc_device_info, and initialize it from either existing
Olaf Hering 01a7c5
  * struct netvsc_device, or from default values.
Olaf Hering 01a7c5
  */
Olaf Hering 01a7c5
-static struct netvsc_device_info *netvsc_devinfo_get
Olaf Hering 01a7c5
-			(struct netvsc_device *nvdev)
Olaf Hering 01a7c5
+static
Olaf Hering 01a7c5
+struct netvsc_device_info *netvsc_devinfo_get(struct netvsc_device *nvdev)
Olaf Hering 01a7c5
 {
Olaf Hering 01a7c5
 	struct netvsc_device_info *dev_info;
Olaf Hering 01a7c5
+	struct bpf_prog *prog;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	dev_info = kzalloc(sizeof(*dev_info), GFP_ATOMIC);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -897,6 +956,8 @@ static struct netvsc_device_info *netvsc_devinfo_get
Olaf Hering 01a7c5
 		return NULL;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	if (nvdev) {
Olaf Hering 01a7c5
+		ASSERT_RTNL();
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 		dev_info->num_chn = nvdev->num_chn;
Olaf Hering 01a7c5
 		dev_info->send_sections = nvdev->send_section_cnt;
Olaf Hering 01a7c5
 		dev_info->send_section_size = nvdev->send_section_size;
Olaf Hering 01a7c5
@@ -905,6 +966,12 @@ static struct netvsc_device_info *netvsc_devinfo_get
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 		memcpy(dev_info->rss_key, nvdev->extension->rss_key,
Olaf Hering 01a7c5
 		       NETVSC_HASH_KEYLEN);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+		prog = netvsc_xdp_get(nvdev);
Olaf Hering 01a7c5
+		if (prog) {
Olaf Hering 01a7c5
+			bpf_prog_inc(prog);
Olaf Hering 01a7c5
+			dev_info->bprog = prog;
Olaf Hering 01a7c5
+		}
Olaf Hering 01a7c5
 	} else {
Olaf Hering 01a7c5
 		dev_info->num_chn = VRSS_CHANNEL_DEFAULT;
Olaf Hering 01a7c5
 		dev_info->send_sections = NETVSC_DEFAULT_TX;
Olaf Hering 01a7c5
@@ -916,6 +983,17 @@ static struct netvsc_device_info *netvsc_devinfo_get
Olaf Hering 01a7c5
 	return dev_info;
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+/* Free struct netvsc_device_info */
Olaf Hering 01a7c5
+static void netvsc_devinfo_put(struct netvsc_device_info *dev_info)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	if (dev_info->bprog) {
Olaf Hering 01a7c5
+		ASSERT_RTNL();
Olaf Hering 01a7c5
+		bpf_prog_put(dev_info->bprog);
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	kfree(dev_info);
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 static int netvsc_detach(struct net_device *ndev,
Olaf Hering 01a7c5
 			 struct netvsc_device *nvdev)
Olaf Hering 01a7c5
 {
Olaf Hering 01a7c5
@@ -927,6 +1005,8 @@ static int netvsc_detach(struct net_device *ndev,
Olaf Hering 01a7c5
 	if (cancel_work_sync(&nvdev->subchan_work))
Olaf Hering 01a7c5
 		nvdev->num_chn = 1;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+	netvsc_xdp_set(ndev, NULL, NULL, nvdev);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 	/* If device was up (receiving) then shutdown */
Olaf Hering 01a7c5
 	if (netif_running(ndev)) {
Olaf Hering 01a7c5
 		netvsc_tx_disable(nvdev, ndev);
Olaf Hering 01a7c5
@@ -960,7 +1040,8 @@ static int netvsc_attach(struct net_device *ndev,
Olaf Hering 01a7c5
 	struct hv_device *hdev = ndev_ctx->device_ctx;
Olaf Hering 01a7c5
 	struct netvsc_device *nvdev;
Olaf Hering 01a7c5
 	struct rndis_device *rdev;
Olaf Hering 01a7c5
-	int ret;
Olaf Hering 01a7c5
+	struct bpf_prog *prog;
Olaf Hering 01a7c5
+	int ret = 0;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	nvdev = rndis_filter_device_add(hdev, dev_info);
Olaf Hering 01a7c5
 	if (IS_ERR(nvdev))
Olaf Hering 01a7c5
@@ -976,6 +1057,13 @@ static int netvsc_attach(struct net_device *ndev,
Olaf Hering 01a7c5
 		}
Olaf Hering 01a7c5
 	}
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+	prog = dev_info->bprog;
Olaf Hering 01a7c5
+	if (prog) {
Olaf Hering 01a7c5
+		ret = netvsc_xdp_set(ndev, prog, NULL, nvdev);
Olaf Hering 01a7c5
+		if (ret)
Olaf Hering 01a7c5
+			goto err1;
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 	/* In any case device is now ready */
Olaf Hering 01a7c5
 	netif_device_attach(ndev);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -985,7 +1073,7 @@ static int netvsc_attach(struct net_device *ndev,
Olaf Hering 01a7c5
 	if (netif_running(ndev)) {
Olaf Hering 01a7c5
 		ret = rndis_filter_open(nvdev);
Olaf Hering 01a7c5
 		if (ret)
Olaf Hering 01a7c5
-			goto err;
Olaf Hering 01a7c5
+			goto err2;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 		rdev = nvdev->extension;
Olaf Hering 01a7c5
 		if (!rdev->link_state)
Olaf Hering 01a7c5
@@ -994,9 +1082,10 @@ static int netvsc_attach(struct net_device *ndev,
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	return 0;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-err:
Olaf Hering 01a7c5
+err2:
Olaf Hering 01a7c5
 	netif_device_detach(ndev);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+err1:
Olaf Hering 01a7c5
 	rndis_filter_device_remove(hdev, nvdev);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	return ret;
Olaf Hering 01a7c5
@@ -1046,7 +1135,7 @@ static int netvsc_set_channels(struct net_device *net,
Olaf Hering 01a7c5
 	}
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 out:
Olaf Hering 01a7c5
-	kfree(device_info);
Olaf Hering 01a7c5
+	netvsc_devinfo_put(device_info);
Olaf Hering 01a7c5
 	return ret;
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -1153,7 +1242,7 @@ rollback_vf:
Olaf Hering 01a7c5
 		dev_set_mtu(vf_netdev, orig_mtu);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 out:
Olaf Hering 01a7c5
-	kfree(device_info);
Olaf Hering 01a7c5
+	netvsc_devinfo_put(device_info);
Olaf Hering 01a7c5
 	return ret;
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -1378,8 +1467,8 @@ static const struct {
Olaf Hering 01a7c5
 /* statistics per queue (rx/tx packets/bytes) */
Olaf Hering 01a7c5
 #define NETVSC_PCPU_STATS_LEN (num_present_cpus() * ARRAY_SIZE(pcpu_stats))
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-/* 4 statistics per queue (rx/tx packets/bytes) */
Olaf Hering 01a7c5
-#define NETVSC_QUEUE_STATS_LEN(dev) ((dev)->num_chn * 4)
Olaf Hering 01a7c5
+/* 5 statistics per queue (rx/tx packets/bytes, rx xdp_drop) */
Olaf Hering 01a7c5
+#define NETVSC_QUEUE_STATS_LEN(dev) ((dev)->num_chn * 5)
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 static int netvsc_get_sset_count(struct net_device *dev, int string_set)
Olaf Hering 01a7c5
 {
Olaf Hering 01a7c5
@@ -1411,6 +1500,7 @@ static void netvsc_get_ethtool_stats(struct net_device *dev,
Olaf Hering 01a7c5
 	struct netvsc_ethtool_pcpu_stats *pcpu_sum;
Olaf Hering 01a7c5
 	unsigned int start;
Olaf Hering 01a7c5
 	u64 packets, bytes;
Olaf Hering 01a7c5
+	u64 xdp_drop;
Olaf Hering 01a7c5
 	int i, j, cpu;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	if (!nvdev)
Olaf Hering 01a7c5
@@ -1439,9 +1529,11 @@ static void netvsc_get_ethtool_stats(struct net_device *dev,
Olaf Hering 01a7c5
 			start = u64_stats_fetch_begin_irq(&qstats->syncp);
Olaf Hering 01a7c5
 			packets = qstats->packets;
Olaf Hering 01a7c5
 			bytes = qstats->bytes;
Olaf Hering 01a7c5
+			xdp_drop = qstats->xdp_drop;
Olaf Hering 01a7c5
 		} while (u64_stats_fetch_retry_irq(&qstats->syncp, start));
Olaf Hering 01a7c5
 		data[i++] = packets;
Olaf Hering 01a7c5
 		data[i++] = bytes;
Olaf Hering 01a7c5
+		data[i++] = xdp_drop;
Olaf Hering 01a7c5
 	}
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	pcpu_sum = kvmalloc_array(num_possible_cpus(),
Olaf Hering 01a7c5
@@ -1489,6 +1581,8 @@ static void netvsc_get_strings(struct net_device *dev, u32 stringset, u8 *data)
Olaf Hering 01a7c5
 			p += ETH_GSTRING_LEN;
Olaf Hering 01a7c5
 			sprintf(p, "rx_queue_%u_bytes", i);
Olaf Hering 01a7c5
 			p += ETH_GSTRING_LEN;
Olaf Hering 01a7c5
+			sprintf(p, "rx_queue_%u_xdp_drop", i);
Olaf Hering 01a7c5
+			p += ETH_GSTRING_LEN;
Olaf Hering 01a7c5
 		}
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 		for_each_present_cpu(cpu) {
Olaf Hering 01a7c5
@@ -1785,10 +1879,27 @@ static int netvsc_set_ringparam(struct net_device *ndev,
Olaf Hering 01a7c5
 	}
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 out:
Olaf Hering 01a7c5
-	kfree(device_info);
Olaf Hering 01a7c5
+	netvsc_devinfo_put(device_info);
Olaf Hering 01a7c5
 	return ret;
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+static netdev_features_t netvsc_fix_features(struct net_device *ndev,
Olaf Hering 01a7c5
+					     netdev_features_t features)
Olaf Hering 01a7c5
+{
Olaf Hering 01a7c5
+	struct net_device_context *ndevctx = netdev_priv(ndev);
Olaf Hering 01a7c5
+	struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if (!nvdev || nvdev->destroy)
Olaf Hering 01a7c5
+		return features;
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	if ((features & NETIF_F_LRO) && netvsc_xdp_get(nvdev)) {
Olaf Hering 01a7c5
+		features ^= NETIF_F_LRO;
Olaf Hering 01a7c5
+		netdev_info(ndev, "Skip LRO - unsupported with XDP\n");
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
+	return features;
Olaf Hering 01a7c5
+}
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 static int netvsc_set_features(struct net_device *ndev,
Olaf Hering 01a7c5
 			       netdev_features_t features)
Olaf Hering 01a7c5
 {
Olaf Hering 01a7c5
@@ -1875,12 +1986,14 @@ static const struct net_device_ops device_ops = {
Olaf Hering 01a7c5
 	.ndo_start_xmit =		netvsc_start_xmit,
Olaf Hering 01a7c5
 	.ndo_change_rx_flags =		netvsc_change_rx_flags,
Olaf Hering 01a7c5
 	.ndo_set_rx_mode =		netvsc_set_rx_mode,
Olaf Hering 01a7c5
+	.ndo_fix_features =		netvsc_fix_features,
Olaf Hering 01a7c5
 	.ndo_set_features =		netvsc_set_features,
Olaf Hering 01a7c5
 	.ndo_change_mtu =		netvsc_change_mtu,
Olaf Hering 01a7c5
 	.ndo_validate_addr =		eth_validate_addr,
Olaf Hering 01a7c5
 	.ndo_set_mac_address =		netvsc_set_mac_addr,
Olaf Hering 01a7c5
 	.ndo_select_queue =		netvsc_select_queue,
Olaf Hering 01a7c5
 	.ndo_get_stats64 =		netvsc_get_stats64,
Olaf Hering 01a7c5
+	.ndo_bpf =			netvsc_bpf,
Olaf Hering 01a7c5
 };
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 /*
Olaf Hering 01a7c5
@@ -2167,6 +2280,7 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
Olaf Hering 01a7c5
 {
Olaf Hering 01a7c5
 	struct net_device_context *net_device_ctx;
Olaf Hering 01a7c5
 	struct netvsc_device *netvsc_dev;
Olaf Hering 01a7c5
+	struct bpf_prog *prog;
Olaf Hering 01a7c5
 	struct net_device *ndev;
Olaf Hering 01a7c5
 	int ret;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -2211,6 +2325,9 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	dev_hold(vf_netdev);
Olaf Hering 01a7c5
 	rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev);
Olaf Hering 01a7c5
+	prog = netvsc_xdp_get(netvsc_dev);
Olaf Hering 01a7c5
+	netvsc_vf_setxdp(vf_netdev, prog);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 	return NOTIFY_OK;
Olaf Hering 01a7c5
 }
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
@@ -2252,6 +2369,8 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
+	netvsc_vf_setxdp(vf_netdev, NULL);
Olaf Hering 01a7c5
+
Olaf Hering 01a7c5
 	netdev_rx_handler_unregister(vf_netdev);
Olaf Hering 01a7c5
 	netdev_upper_dev_unlink(vf_netdev, ndev);
Olaf Hering 01a7c5
 	RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
Olaf Hering 01a7c5
@@ -2363,14 +2482,14 @@ static int netvsc_probe(struct hv_device *dev,
Olaf Hering 01a7c5
 	list_add(&net_device_ctx->list, &netvsc_dev_list);
Olaf Hering 01a7c5
 	rtnl_unlock();
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
-	kfree(device_info);
Olaf Hering 01a7c5
+	netvsc_devinfo_put(device_info);
Olaf Hering 01a7c5
 	return 0;
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 register_failed:
Olaf Hering 01a7c5
 	rtnl_unlock();
Olaf Hering 01a7c5
 	rndis_filter_device_remove(dev, nvdev);
Olaf Hering 01a7c5
 rndis_failed:
Olaf Hering 01a7c5
-	kfree(device_info);
Olaf Hering 01a7c5
+	netvsc_devinfo_put(device_info);
Olaf Hering 01a7c5
 devinfo_failed:
Olaf Hering 01a7c5
 	free_percpu(net_device_ctx->vf_stats);
Olaf Hering 01a7c5
 no_stats:
Olaf Hering 01a7c5
@@ -2398,8 +2517,10 @@ static int netvsc_remove(struct hv_device *dev)
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	rtnl_lock();
Olaf Hering 01a7c5
 	nvdev = rtnl_dereference(ndev_ctx->nvdev);
Olaf Hering 01a7c5
-	if (nvdev)
Olaf Hering 01a7c5
+	if (nvdev) {
Olaf Hering 01a7c5
 		cancel_work_sync(&nvdev->subchan_work);
Olaf Hering 01a7c5
+		netvsc_xdp_set(net, NULL, NULL, nvdev);
Olaf Hering 01a7c5
+	}
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	/*
Olaf Hering 01a7c5
 	 * Call to the vsc driver to let it know that the device is being
Olaf Hering 01a7c5
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
Olaf Hering 01a7c5
--- a/drivers/net/hyperv/rndis_filter.c
Olaf Hering 01a7c5
+++ b/drivers/net/hyperv/rndis_filter.c
Olaf Hering 01a7c5
@@ -235,7 +235,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
Olaf Hering 01a7c5
 	trace_rndis_send(dev->ndev, 0, &req->request_msg);
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	rcu_read_lock_bh();
Olaf Hering 01a7c5
-	ret = netvsc_send(dev->ndev, packet, NULL, pb, NULL);
Olaf Hering 01a7c5
+	ret = netvsc_send(dev->ndev, packet, NULL, pb, NULL, false);
Olaf Hering 01a7c5
 	rcu_read_unlock_bh();
Olaf Hering 01a7c5
 
Olaf Hering 01a7c5
 	return ret;