|
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;
|