Skip to content

Commit 9fc8d51

Browse files
Toshiaki Makitaborkmann
authored andcommitted
veth: Handle xdp_frames in xdp napi ring
This is preparation for XDP TX and ndo_xdp_xmit. This allows napi handler to handle xdp_frames through xdp ring as well as sk_buff. v8: - Don't use xdp_frame pointer address to calculate skb->head and headroom. v7: - Use xdp_scrub_frame() instead of memset(). v3: - Revert v2 change around rings and use a flag to differentiate skb and xdp_frame, since bulk skb xmit makes little performance difference for now. v2: - Use another ring instead of using flag to differentiate skb and xdp_frame. This approach makes bulk skb transmit possible in veth_xmit later. - Clear xdp_frame feilds in skb->head. - Implement adjust_tail. Signed-off-by: Toshiaki Makita <[email protected]> Acked-by: John Fastabend <[email protected]> Acked-by: Jesper Dangaard Brouer <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent a8d5b4a commit 9fc8d51

File tree

1 file changed

+84
-5
lines changed

1 file changed

+84
-5
lines changed

drivers/net/veth.c

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222
#include <linux/bpf.h>
2323
#include <linux/filter.h>
2424
#include <linux/ptr_ring.h>
25-
#include <linux/skb_array.h>
2625
#include <linux/bpf_trace.h>
2726

2827
#define DRV_NAME "veth"
2928
#define DRV_VERSION "1.0"
3029

30+
#define VETH_XDP_FLAG BIT(0)
3131
#define VETH_RING_SIZE 256
3232
#define VETH_XDP_HEADROOM (XDP_PACKET_HEADROOM + NET_IP_ALIGN)
3333

@@ -115,6 +115,24 @@ static const struct ethtool_ops veth_ethtool_ops = {
115115

116116
/* general routines */
117117

118+
static bool veth_is_xdp_frame(void *ptr)
119+
{
120+
return (unsigned long)ptr & VETH_XDP_FLAG;
121+
}
122+
123+
static void *veth_ptr_to_xdp(void *ptr)
124+
{
125+
return (void *)((unsigned long)ptr & ~VETH_XDP_FLAG);
126+
}
127+
128+
static void veth_ptr_free(void *ptr)
129+
{
130+
if (veth_is_xdp_frame(ptr))
131+
xdp_return_frame(veth_ptr_to_xdp(ptr));
132+
else
133+
kfree_skb(ptr);
134+
}
135+
118136
static void __veth_xdp_flush(struct veth_priv *priv)
119137
{
120138
/* Write ptr_ring before reading rx_notify_masked */
@@ -249,6 +267,63 @@ static struct sk_buff *veth_build_skb(void *head, int headroom, int len,
249267
return skb;
250268
}
251269

270+
static struct sk_buff *veth_xdp_rcv_one(struct veth_priv *priv,
271+
struct xdp_frame *frame)
272+
{
273+
void *hard_start = frame->data - frame->headroom;
274+
void *head = hard_start - sizeof(struct xdp_frame);
275+
int len = frame->len, delta = 0;
276+
struct bpf_prog *xdp_prog;
277+
unsigned int headroom;
278+
struct sk_buff *skb;
279+
280+
rcu_read_lock();
281+
xdp_prog = rcu_dereference(priv->xdp_prog);
282+
if (likely(xdp_prog)) {
283+
struct xdp_buff xdp;
284+
u32 act;
285+
286+
xdp.data_hard_start = hard_start;
287+
xdp.data = frame->data;
288+
xdp.data_end = frame->data + frame->len;
289+
xdp.data_meta = frame->data - frame->metasize;
290+
xdp.rxq = &priv->xdp_rxq;
291+
292+
act = bpf_prog_run_xdp(xdp_prog, &xdp);
293+
294+
switch (act) {
295+
case XDP_PASS:
296+
delta = frame->data - xdp.data;
297+
len = xdp.data_end - xdp.data;
298+
break;
299+
default:
300+
bpf_warn_invalid_xdp_action(act);
301+
case XDP_ABORTED:
302+
trace_xdp_exception(priv->dev, xdp_prog, act);
303+
case XDP_DROP:
304+
goto err_xdp;
305+
}
306+
}
307+
rcu_read_unlock();
308+
309+
headroom = sizeof(struct xdp_frame) + frame->headroom - delta;
310+
skb = veth_build_skb(head, headroom, len, 0);
311+
if (!skb) {
312+
xdp_return_frame(frame);
313+
goto err;
314+
}
315+
316+
xdp_scrub_frame(frame);
317+
skb->protocol = eth_type_trans(skb, priv->dev);
318+
err:
319+
return skb;
320+
err_xdp:
321+
rcu_read_unlock();
322+
xdp_return_frame(frame);
323+
324+
return NULL;
325+
}
326+
252327
static struct sk_buff *veth_xdp_rcv_skb(struct veth_priv *priv,
253328
struct sk_buff *skb)
254329
{
@@ -359,12 +434,16 @@ static int veth_xdp_rcv(struct veth_priv *priv, int budget)
359434
int i, done = 0;
360435

361436
for (i = 0; i < budget; i++) {
362-
struct sk_buff *skb = __ptr_ring_consume(&priv->xdp_ring);
437+
void *ptr = __ptr_ring_consume(&priv->xdp_ring);
438+
struct sk_buff *skb;
363439

364-
if (!skb)
440+
if (!ptr)
365441
break;
366442

367-
skb = veth_xdp_rcv_skb(priv, skb);
443+
if (veth_is_xdp_frame(ptr))
444+
skb = veth_xdp_rcv_one(priv, veth_ptr_to_xdp(ptr));
445+
else
446+
skb = veth_xdp_rcv_skb(priv, ptr);
368447

369448
if (skb)
370449
napi_gro_receive(&priv->xdp_napi, skb);
@@ -417,7 +496,7 @@ static void veth_napi_del(struct net_device *dev)
417496
napi_disable(&priv->xdp_napi);
418497
netif_napi_del(&priv->xdp_napi);
419498
priv->rx_notify_masked = false;
420-
ptr_ring_cleanup(&priv->xdp_ring, __skb_array_destroy_skb);
499+
ptr_ring_cleanup(&priv->xdp_ring, veth_ptr_free);
421500
}
422501

423502
static int veth_enable_xdp(struct net_device *dev)

0 commit comments

Comments
 (0)