1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2019, Microsoft Corporation.
5 * Haiyang Zhang <haiyangz@microsoft.com>
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 #include <linux/netdevice.h>
11 #include <linux/etherdevice.h>
12 #include <linux/ethtool.h>
13 #include <linux/bpf.h>
14 #include <linux/bpf_trace.h>
15 #include <linux/kernel.h>
18 #include <linux/mutex.h>
19 #include <linux/rtnetlink.h>
21 #include "hyperv_net.h"
23 u32
netvsc_run_xdp(struct net_device
*ndev
, struct netvsc_channel
*nvchan
,
26 void *data
= nvchan
->rsc
.data
[0];
27 u32 len
= nvchan
->rsc
.len
[0];
28 struct page
*page
= NULL
;
29 struct bpf_prog
*prog
;
32 xdp
->data_hard_start
= NULL
;
35 prog
= rcu_dereference(nvchan
->bpf_prog
);
40 /* allocate page buffer for data */
41 page
= alloc_page(GFP_ATOMIC
);
47 xdp
->data_hard_start
= page_address(page
);
48 xdp
->data
= xdp
->data_hard_start
+ NETVSC_XDP_HDRM
;
49 xdp_set_data_meta_invalid(xdp
);
50 xdp
->data_end
= xdp
->data
+ len
;
51 xdp
->rxq
= &nvchan
->xdp_rxq
;
54 memcpy(xdp
->data
, data
, len
);
56 act
= bpf_prog_run_xdp(prog
, xdp
);
65 trace_xdp_exception(ndev
, prog
, act
);
69 bpf_warn_invalid_xdp_action(act
);
75 if (page
&& act
!= XDP_PASS
&& act
!= XDP_TX
) {
77 xdp
->data_hard_start
= NULL
;
83 unsigned int netvsc_xdp_fraglen(unsigned int len
)
85 return SKB_DATA_ALIGN(len
) +
86 SKB_DATA_ALIGN(sizeof(struct skb_shared_info
));
89 struct bpf_prog
*netvsc_xdp_get(struct netvsc_device
*nvdev
)
91 return rtnl_dereference(nvdev
->chan_table
[0].bpf_prog
);
94 int netvsc_xdp_set(struct net_device
*dev
, struct bpf_prog
*prog
,
95 struct netlink_ext_ack
*extack
,
96 struct netvsc_device
*nvdev
)
98 struct bpf_prog
*old_prog
;
101 old_prog
= netvsc_xdp_get(nvdev
);
103 if (!old_prog
&& !prog
)
106 buf_max
= NETVSC_XDP_HDRM
+ netvsc_xdp_fraglen(dev
->mtu
+ ETH_HLEN
);
107 if (prog
&& buf_max
> PAGE_SIZE
) {
108 netdev_err(dev
, "XDP: mtu:%u too large, buf_max:%u\n",
110 NL_SET_ERR_MSG_MOD(extack
, "XDP: mtu too large");
115 if (prog
&& (dev
->features
& NETIF_F_LRO
)) {
116 netdev_err(dev
, "XDP: not support LRO\n");
117 NL_SET_ERR_MSG_MOD(extack
, "XDP: not support LRO");
123 bpf_prog_add(prog
, nvdev
->num_chn
);
125 for (i
= 0; i
< nvdev
->num_chn
; i
++)
126 rcu_assign_pointer(nvdev
->chan_table
[i
].bpf_prog
, prog
);
129 for (i
= 0; i
< nvdev
->num_chn
; i
++)
130 bpf_prog_put(old_prog
);
135 int netvsc_vf_setxdp(struct net_device
*vf_netdev
, struct bpf_prog
*prog
)
137 struct netdev_bpf xdp
;
145 ndo_bpf
= vf_netdev
->netdev_ops
->ndo_bpf
;
149 memset(&xdp
, 0, sizeof(xdp
));
151 xdp
.command
= XDP_SETUP_PROG
;
154 return ndo_bpf(vf_netdev
, &xdp
);
157 static u32
netvsc_xdp_query(struct netvsc_device
*nvdev
)
159 struct bpf_prog
*prog
= netvsc_xdp_get(nvdev
);
162 return prog
->aux
->id
;
167 int netvsc_bpf(struct net_device
*dev
, struct netdev_bpf
*bpf
)
169 struct net_device_context
*ndevctx
= netdev_priv(dev
);
170 struct netvsc_device
*nvdev
= rtnl_dereference(ndevctx
->nvdev
);
171 struct net_device
*vf_netdev
= rtnl_dereference(ndevctx
->vf_netdev
);
172 struct netlink_ext_ack
*extack
= bpf
->extack
;
175 if (!nvdev
|| nvdev
->destroy
) {
176 if (bpf
->command
== XDP_QUERY_PROG
) {
178 return 0; /* Query must always succeed */
184 switch (bpf
->command
) {
186 ret
= netvsc_xdp_set(dev
, bpf
->prog
, extack
, nvdev
);
191 ret
= netvsc_vf_setxdp(vf_netdev
, bpf
->prog
);
194 netdev_err(dev
, "vf_setxdp failed:%d\n", ret
);
195 NL_SET_ERR_MSG_MOD(extack
, "vf_setxdp failed");
197 netvsc_xdp_set(dev
, NULL
, extack
, nvdev
);
203 bpf
->prog_id
= netvsc_xdp_query(nvdev
);