Revision 279a4253 hw/virtio-net.c

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