diff options
-rw-r--r-- | drivers/net/virtio_net.c | 112 |
1 files changed, 87 insertions, 25 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index e53365a86ca3..5deeda61d6d3 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -333,9 +333,9 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi, | |||
333 | static void virtnet_xdp_xmit(struct virtnet_info *vi, | 333 | static void virtnet_xdp_xmit(struct virtnet_info *vi, |
334 | struct receive_queue *rq, | 334 | struct receive_queue *rq, |
335 | struct send_queue *sq, | 335 | struct send_queue *sq, |
336 | struct xdp_buff *xdp) | 336 | struct xdp_buff *xdp, |
337 | void *data) | ||
337 | { | 338 | { |
338 | struct page *page = virt_to_head_page(xdp->data); | ||
339 | struct virtio_net_hdr_mrg_rxbuf *hdr; | 339 | struct virtio_net_hdr_mrg_rxbuf *hdr; |
340 | unsigned int num_sg, len; | 340 | unsigned int num_sg, len; |
341 | void *xdp_sent; | 341 | void *xdp_sent; |
@@ -343,20 +343,45 @@ static void virtnet_xdp_xmit(struct virtnet_info *vi, | |||
343 | 343 | ||
344 | /* Free up any pending old buffers before queueing new ones. */ | 344 | /* Free up any pending old buffers before queueing new ones. */ |
345 | while ((xdp_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) { | 345 | while ((xdp_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) { |
346 | struct page *sent_page = virt_to_head_page(xdp_sent); | 346 | if (vi->mergeable_rx_bufs) { |
347 | put_page(sent_page); | 347 | struct page *sent_page = virt_to_head_page(xdp_sent); |
348 | |||
349 | put_page(sent_page); | ||
350 | } else { /* small buffer */ | ||
351 | struct sk_buff *skb = xdp_sent; | ||
352 | |||
353 | kfree_skb(skb); | ||
354 | } | ||
348 | } | 355 | } |
349 | 356 | ||
350 | /* Zero header and leave csum up to XDP layers */ | 357 | if (vi->mergeable_rx_bufs) { |
351 | hdr = xdp->data; | 358 | /* Zero header and leave csum up to XDP layers */ |
352 | memset(hdr, 0, vi->hdr_len); | 359 | hdr = xdp->data; |
360 | memset(hdr, 0, vi->hdr_len); | ||
361 | |||
362 | num_sg = 1; | ||
363 | sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data); | ||
364 | } else { /* small buffer */ | ||
365 | struct sk_buff *skb = data; | ||
353 | 366 | ||
354 | num_sg = 1; | 367 | /* Zero header and leave csum up to XDP layers */ |
355 | sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data); | 368 | hdr = skb_vnet_hdr(skb); |
369 | memset(hdr, 0, vi->hdr_len); | ||
370 | |||
371 | num_sg = 2; | ||
372 | sg_init_table(sq->sg, 2); | ||
373 | sg_set_buf(sq->sg, hdr, vi->hdr_len); | ||
374 | skb_to_sgvec(skb, sq->sg + 1, 0, skb->len); | ||
375 | } | ||
356 | err = virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, | 376 | err = virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, |
357 | xdp->data, GFP_ATOMIC); | 377 | data, GFP_ATOMIC); |
358 | if (unlikely(err)) { | 378 | if (unlikely(err)) { |
359 | put_page(page); | 379 | if (vi->mergeable_rx_bufs) { |
380 | struct page *page = virt_to_head_page(xdp->data); | ||
381 | |||
382 | put_page(page); | ||
383 | } else /* small buffer */ | ||
384 | kfree_skb(data); | ||
360 | return; // On error abort to avoid unnecessary kick | 385 | return; // On error abort to avoid unnecessary kick |
361 | } | 386 | } |
362 | 387 | ||
@@ -366,23 +391,26 @@ static void virtnet_xdp_xmit(struct virtnet_info *vi, | |||
366 | static u32 do_xdp_prog(struct virtnet_info *vi, | 391 | static u32 do_xdp_prog(struct virtnet_info *vi, |
367 | struct receive_queue *rq, | 392 | struct receive_queue *rq, |
368 | struct bpf_prog *xdp_prog, | 393 | struct bpf_prog *xdp_prog, |
369 | struct page *page, int offset, int len) | 394 | void *data, int len) |
370 | { | 395 | { |
371 | int hdr_padded_len; | 396 | int hdr_padded_len; |
372 | struct xdp_buff xdp; | 397 | struct xdp_buff xdp; |
398 | void *buf; | ||
373 | unsigned int qp; | 399 | unsigned int qp; |
374 | u32 act; | 400 | u32 act; |
375 | u8 *buf; | ||
376 | |||
377 | buf = page_address(page) + offset; | ||
378 | 401 | ||
379 | if (vi->mergeable_rx_bufs) | 402 | if (vi->mergeable_rx_bufs) { |
380 | hdr_padded_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); | 403 | hdr_padded_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); |
381 | else | 404 | xdp.data = data + hdr_padded_len; |
382 | hdr_padded_len = sizeof(struct padded_vnet_hdr); | 405 | xdp.data_end = xdp.data + (len - vi->hdr_len); |
406 | buf = data; | ||
407 | } else { /* small buffers */ | ||
408 | struct sk_buff *skb = data; | ||
383 | 409 | ||
384 | xdp.data = buf + hdr_padded_len; | 410 | xdp.data = skb->data; |
385 | xdp.data_end = xdp.data + (len - vi->hdr_len); | 411 | xdp.data_end = xdp.data + len; |
412 | buf = skb->data; | ||
413 | } | ||
386 | 414 | ||
387 | act = bpf_prog_run_xdp(xdp_prog, &xdp); | 415 | act = bpf_prog_run_xdp(xdp_prog, &xdp); |
388 | switch (act) { | 416 | switch (act) { |
@@ -392,8 +420,8 @@ static u32 do_xdp_prog(struct virtnet_info *vi, | |||
392 | qp = vi->curr_queue_pairs - | 420 | qp = vi->curr_queue_pairs - |
393 | vi->xdp_queue_pairs + | 421 | vi->xdp_queue_pairs + |
394 | smp_processor_id(); | 422 | smp_processor_id(); |
395 | xdp.data = buf + (vi->mergeable_rx_bufs ? 0 : 4); | 423 | xdp.data = buf; |
396 | virtnet_xdp_xmit(vi, rq, &vi->sq[qp], &xdp); | 424 | virtnet_xdp_xmit(vi, rq, &vi->sq[qp], &xdp, data); |
397 | return XDP_TX; | 425 | return XDP_TX; |
398 | default: | 426 | default: |
399 | bpf_warn_invalid_xdp_action(act); | 427 | bpf_warn_invalid_xdp_action(act); |
@@ -403,14 +431,47 @@ static u32 do_xdp_prog(struct virtnet_info *vi, | |||
403 | } | 431 | } |
404 | } | 432 | } |
405 | 433 | ||
406 | static struct sk_buff *receive_small(struct virtnet_info *vi, void *buf, unsigned int len) | 434 | static struct sk_buff *receive_small(struct net_device *dev, |
435 | struct virtnet_info *vi, | ||
436 | struct receive_queue *rq, | ||
437 | void *buf, unsigned int len) | ||
407 | { | 438 | { |
408 | struct sk_buff * skb = buf; | 439 | struct sk_buff * skb = buf; |
440 | struct bpf_prog *xdp_prog; | ||
409 | 441 | ||
410 | len -= vi->hdr_len; | 442 | len -= vi->hdr_len; |
411 | skb_trim(skb, len); | 443 | skb_trim(skb, len); |
412 | 444 | ||
445 | rcu_read_lock(); | ||
446 | xdp_prog = rcu_dereference(rq->xdp_prog); | ||
447 | if (xdp_prog) { | ||
448 | struct virtio_net_hdr_mrg_rxbuf *hdr = buf; | ||
449 | u32 act; | ||
450 | |||
451 | if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) | ||
452 | goto err_xdp; | ||
453 | act = do_xdp_prog(vi, rq, xdp_prog, skb, len); | ||
454 | switch (act) { | ||
455 | case XDP_PASS: | ||
456 | break; | ||
457 | case XDP_TX: | ||
458 | rcu_read_unlock(); | ||
459 | goto xdp_xmit; | ||
460 | case XDP_DROP: | ||
461 | default: | ||
462 | goto err_xdp; | ||
463 | } | ||
464 | } | ||
465 | rcu_read_unlock(); | ||
466 | |||
413 | return skb; | 467 | return skb; |
468 | |||
469 | err_xdp: | ||
470 | rcu_read_unlock(); | ||
471 | dev->stats.rx_dropped++; | ||
472 | kfree_skb(skb); | ||
473 | xdp_xmit: | ||
474 | return NULL; | ||
414 | } | 475 | } |
415 | 476 | ||
416 | static struct sk_buff *receive_big(struct net_device *dev, | 477 | static struct sk_buff *receive_big(struct net_device *dev, |
@@ -537,7 +598,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, | |||
537 | if (unlikely(hdr->hdr.gso_type)) | 598 | if (unlikely(hdr->hdr.gso_type)) |
538 | goto err_xdp; | 599 | goto err_xdp; |
539 | 600 | ||
540 | act = do_xdp_prog(vi, rq, xdp_prog, xdp_page, offset, len); | 601 | act = do_xdp_prog(vi, rq, xdp_prog, |
602 | page_address(xdp_page) + offset, len); | ||
541 | switch (act) { | 603 | switch (act) { |
542 | case XDP_PASS: | 604 | case XDP_PASS: |
543 | /* We can only create skb based on xdp_page. */ | 605 | /* We can only create skb based on xdp_page. */ |
@@ -672,7 +734,7 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq, | |||
672 | else if (vi->big_packets) | 734 | else if (vi->big_packets) |
673 | skb = receive_big(dev, vi, rq, buf, len); | 735 | skb = receive_big(dev, vi, rq, buf, len); |
674 | else | 736 | else |
675 | skb = receive_small(vi, buf, len); | 737 | skb = receive_small(dev, vi, rq, buf, len); |
676 | 738 | ||
677 | if (unlikely(!skb)) | 739 | if (unlikely(!skb)) |
678 | return; | 740 | return; |