Revision 279a4253
b/hw/virtio-net.c | ||
---|---|---|
528 | 528 |
{ |
529 | 529 |
VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; |
530 | 530 |
struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL; |
531 |
size_t hdr_len, offset, i;
|
|
531 |
size_t guest_hdr_len, offset, i, host_hdr_len;
|
|
532 | 532 |
|
533 | 533 |
if (!virtio_net_can_receive(&n->nic->nc)) |
534 | 534 |
return -1; |
535 | 535 |
|
536 | 536 |
/* hdr_len refers to the header we supply to the guest */ |
537 |
hdr_len = n->mergeable_rx_bufs ? |
|
537 |
guest_hdr_len = n->mergeable_rx_bufs ?
|
|
538 | 538 |
sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); |
539 | 539 |
|
540 | 540 |
|
541 |
if (!virtio_net_has_buffers(n, size + hdr_len)) |
|
541 |
host_hdr_len = n->has_vnet_hdr ? sizeof(struct virtio_net_hdr) : 0; |
|
542 |
if (!virtio_net_has_buffers(n, size + guest_hdr_len - host_hdr_len)) |
|
542 | 543 |
return 0; |
543 | 544 |
|
544 | 545 |
if (!receive_filter(n, buf, size)) |
... | ... | |
553 | 554 |
|
554 | 555 |
total = 0; |
555 | 556 |
|
556 |
if ((i != 0 && !n->mergeable_rx_bufs) || |
|
557 |
virtqueue_pop(n->rx_vq, &elem) == 0) { |
|
557 |
if (virtqueue_pop(n->rx_vq, &elem) == 0) { |
|
558 | 558 |
if (i == 0) |
559 | 559 |
return -1; |
560 |
fprintf(stderr, "virtio-net truncating packet: " |
|
561 |
"offset %zd, size %zd, hdr_len %zd\n", |
|
562 |
offset, size, hdr_len); |
|
560 |
fprintf(stderr, "virtio-net unexpected empty queue: " |
|
561 |
"i %zd mergeable %d offset %zd, size %zd, " |
|
562 |
"guest hdr len %zd, host hdr len %zd guest features 0x%x\n", |
|
563 |
i, n->mergeable_rx_bufs, offset, size, |
|
564 |
guest_hdr_len, host_hdr_len, n->vdev.guest_features); |
|
563 | 565 |
exit(1); |
564 | 566 |
} |
565 | 567 |
|
... | ... | |
568 | 570 |
exit(1); |
569 | 571 |
} |
570 | 572 |
|
571 |
if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != hdr_len) { |
|
573 |
if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) {
|
|
572 | 574 |
fprintf(stderr, "virtio-net header not in first element\n"); |
573 | 575 |
exit(1); |
574 | 576 |
} |
... | ... | |
580 | 582 |
mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base; |
581 | 583 |
|
582 | 584 |
offset += receive_header(n, sg, elem.in_num, |
583 |
buf + offset, size - offset, hdr_len); |
|
584 |
total += hdr_len; |
|
585 |
buf + offset, size - offset, guest_hdr_len);
|
|
586 |
total += guest_hdr_len;
|
|
585 | 587 |
} |
586 | 588 |
|
587 | 589 |
/* copy in packet. ugh */ |
588 | 590 |
len = iov_from_buf(sg, elem.in_num, |
589 | 591 |
buf + offset, size - offset); |
590 | 592 |
total += len; |
593 |
offset += len; |
|
594 |
/* If buffers can't be merged, at this point we |
|
595 |
* must have consumed the complete packet. |
|
596 |
* Otherwise, drop it. */ |
|
597 |
if (!n->mergeable_rx_bufs && offset < size) { |
|
598 |
#if 0 |
|
599 |
fprintf(stderr, "virtio-net truncated non-mergeable packet: " |
|
600 |
|
|
601 |
"i %zd mergeable %d offset %zd, size %zd, " |
|
602 |
"guest hdr len %zd, host hdr len %zd\n", |
|
603 |
i, n->mergeable_rx_bufs, |
|
604 |
offset, size, guest_hdr_len, host_hdr_len); |
|
605 |
#endif |
|
606 |
return size; |
|
607 |
} |
|
591 | 608 |
|
592 | 609 |
/* signal other side */ |
593 | 610 |
virtqueue_fill(n->rx_vq, &elem, total, i++); |
594 |
|
|
595 |
offset += len; |
|
596 | 611 |
} |
597 | 612 |
|
598 | 613 |
if (mhdr) |
Also available in: Unified diff