|
22 | 22 | #include <linux/bpf.h>
|
23 | 23 | #include <linux/filter.h>
|
24 | 24 | #include <linux/ptr_ring.h>
|
25 |
| -#include <linux/skb_array.h> |
26 | 25 | #include <linux/bpf_trace.h>
|
27 | 26 |
|
28 | 27 | #define DRV_NAME "veth"
|
29 | 28 | #define DRV_VERSION "1.0"
|
30 | 29 |
|
| 30 | +#define VETH_XDP_FLAG BIT(0) |
31 | 31 | #define VETH_RING_SIZE 256
|
32 | 32 | #define VETH_XDP_HEADROOM (XDP_PACKET_HEADROOM + NET_IP_ALIGN)
|
33 | 33 |
|
@@ -115,6 +115,24 @@ static const struct ethtool_ops veth_ethtool_ops = {
|
115 | 115 |
|
116 | 116 | /* general routines */
|
117 | 117 |
|
| 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 | + |
118 | 136 | static void __veth_xdp_flush(struct veth_priv *priv)
|
119 | 137 | {
|
120 | 138 | /* 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,
|
249 | 267 | return skb;
|
250 | 268 | }
|
251 | 269 |
|
| 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 | + |
252 | 327 | static struct sk_buff *veth_xdp_rcv_skb(struct veth_priv *priv,
|
253 | 328 | struct sk_buff *skb)
|
254 | 329 | {
|
@@ -359,12 +434,16 @@ static int veth_xdp_rcv(struct veth_priv *priv, int budget)
|
359 | 434 | int i, done = 0;
|
360 | 435 |
|
361 | 436 | 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; |
363 | 439 |
|
364 |
| - if (!skb) |
| 440 | + if (!ptr) |
365 | 441 | break;
|
366 | 442 |
|
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); |
368 | 447 |
|
369 | 448 | if (skb)
|
370 | 449 | napi_gro_receive(&priv->xdp_napi, skb);
|
@@ -417,7 +496,7 @@ static void veth_napi_del(struct net_device *dev)
|
417 | 496 | napi_disable(&priv->xdp_napi);
|
418 | 497 | netif_napi_del(&priv->xdp_napi);
|
419 | 498 | 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); |
421 | 500 | }
|
422 | 501 |
|
423 | 502 | static int veth_enable_xdp(struct net_device *dev)
|
|
0 commit comments