~jderose/ubuntu/raring/qemu/vde-again

« back to all changes in this revision

Viewing changes to .pc/gridcentric/migrate-macs/hw/virtio-net.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2013-01-14 23:22:51 UTC
  • mfrom: (1.6.7) (11.1.12 experimental)
  • Revision ID: package-import@ubuntu.com-20130114232251-zuuixzxdshv9uu7s
Tags: 1.3.0+dfsg-1~exp3ubuntu1
* Merge 1.3.0+dfsg-1~exp3.  Remaining ubuntu delta:
  - debian/control:
    * update maintainer
    * remove vde2 recommends
    * build-deps: remove libusbredir, libvdeplug2-dev,
      libspice-server-dev, libspice-protocol-dev, libiscsi-dev,
      and libxen-dev.
    * qemu-keymaps: break/replace qemu-common
    * qemu-system:
      - break/replace qemu-common
      - depend on udev
      - remove openbios-ppc, openbios-sparc, and openhackware from
        Depends.  (Intend to add them back once we can build them.)
      - provides: qemu-kvm
    * qemu-utils: break/replace qemu-kvm
    * set up transitional packages for qemu-kvm, qemu-common, and kvm.
  - qemu-kvm.upstart:
    - add qemu-system.qemu-kvm.upstart
    - debian/rules: add dh_installinit to get qemu-system.upstart installed.
    - take the defaults from the old qemu-kvm.defaults, and move them into
      the upstart job
  - debian/patches:
    - apply gridcentric patches from lp:~amscanne/+junk/gridcentric-qemu-patches
    - apply arm patches from git://git.linaro.org/qemu/qemu-linaro.git
  - ifup/down:
    - copy Debian qemu-kvm's kvm-ifup/down into debian/
    - fix dh_install for kvm-ifup/down in debian/rules
    - add links for qemu-ifup/down in qemu-system.links
    - remove (debian's original) qemu-ifup from qemu-system.install
  - debian/qemu-system.postinst
    - udevadm trigger to fix up /dev/kvm perms
    - make the 'qemu' symlink point to qemu-system-x86_64, not -i386.
  - debian/qemu-system.links:
    - point 'kvm' to qemu-system-x86_64
    - remove pxe-virtio, pxe-e1000 and pxe-rtl8139 links (which conflict
      with ones from kvm-ipxe).  We may want to move the links from kvm-ipxe
      back to qemu-system at some point.
* Add note about kvm to qemu-system.README.debian.
* Copy kvm-ifup and kvm-ifdown from debian's qemu-kvm
* Remove TAPBR from qemu-kvm.conf.
* Make sure /dev/kvm gets its acls cleared:
  - Add acl to qemu-system.depends
  - update qemu-system.udev to run setfacl to set g::rw acl
* qemu-system.qemu-kvm.conf: don't rmmod at stop
* Remove vnc-jpeg, libiscsi-dev, and vde from debian/configure-opts
* Remove hugepages sysctl file - qemu now supports transparent hugepages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
41
41
    int32_t tx_burst;
42
42
    int tx_waiting;
43
43
    uint32_t has_vnet_hdr;
 
44
    size_t host_hdr_len;
 
45
    size_t guest_hdr_len;
44
46
    uint8_t has_ufo;
45
47
    struct {
46
48
        VirtQueueElement elem;
200
202
    memset(n->vlans, 0, MAX_VLAN >> 3);
201
203
}
202
204
 
203
 
static int peer_has_vnet_hdr(VirtIONet *n)
 
205
static void peer_test_vnet_hdr(VirtIONet *n)
204
206
{
205
207
    if (!n->nic->nc.peer)
206
 
        return 0;
 
208
        return;
207
209
 
208
210
    if (n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP)
209
 
        return 0;
 
211
        return;
210
212
 
211
213
    n->has_vnet_hdr = tap_has_vnet_hdr(n->nic->nc.peer);
 
214
}
212
215
 
 
216
static int peer_has_vnet_hdr(VirtIONet *n)
 
217
{
213
218
    return n->has_vnet_hdr;
214
219
}
215
220
 
223
228
    return n->has_ufo;
224
229
}
225
230
 
 
231
static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs)
 
232
{
 
233
    n->mergeable_rx_bufs = mergeable_rx_bufs;
 
234
 
 
235
    n->guest_hdr_len = n->mergeable_rx_bufs ?
 
236
        sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
 
237
 
 
238
    if (peer_has_vnet_hdr(n) &&
 
239
        tap_has_vnet_hdr_len(n->nic->nc.peer, n->guest_hdr_len)) {
 
240
        tap_set_vnet_hdr_len(n->nic->nc.peer, n->guest_hdr_len);
 
241
        n->host_hdr_len = n->guest_hdr_len;
 
242
    }
 
243
}
 
244
 
226
245
static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
227
246
{
228
247
    VirtIONet *n = to_virtio_net(vdev);
229
248
 
230
249
    features |= (1 << VIRTIO_NET_F_MAC);
231
250
 
232
 
    if (peer_has_vnet_hdr(n)) {
233
 
        tap_using_vnet_hdr(n->nic->nc.peer, 1);
234
 
    } else {
 
251
    if (!peer_has_vnet_hdr(n)) {
235
252
        features &= ~(0x1 << VIRTIO_NET_F_CSUM);
236
253
        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO4);
237
254
        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO6);
277
294
{
278
295
    VirtIONet *n = to_virtio_net(vdev);
279
296
 
280
 
    n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF));
 
297
    virtio_net_set_mrg_rx_bufs(n, !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF)));
281
298
 
282
299
    if (n->has_vnet_hdr) {
283
300
        tap_set_offload(n->nic->nc.peer,
447
464
    VirtIONet *n = to_virtio_net(vdev);
448
465
 
449
466
    qemu_flush_queued_packets(&n->nic->nc);
450
 
 
451
 
    /* We now have RX buffers, signal to the IO thread to break out of the
452
 
     * select to re-poll the tap file descriptor */
453
 
    qemu_notify_event();
454
467
}
455
468
 
456
469
static int virtio_net_can_receive(NetClientState *nc)
503
516
 * cache.
504
517
 */
505
518
static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
506
 
                                        const uint8_t *buf, size_t size)
 
519
                                        uint8_t *buf, size_t size)
507
520
{
508
521
    if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
509
522
        (size > 27 && size < 1500) && /* normal sized MTU */
510
523
        (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
511
524
        (buf[23] == 17) && /* ip.protocol == UDP */
512
525
        (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
 
526
        net_checksum_calculate(buf, size);
 
527
        hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
 
528
    }
 
529
}
 
530
 
 
531
static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
 
532
                           const void *buf, size_t size)
 
533
{
 
534
    if (n->has_vnet_hdr) {
513
535
        /* FIXME this cast is evil */
514
 
        net_checksum_calculate((uint8_t *)buf, size);
515
 
        hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
516
 
    }
517
 
}
518
 
 
519
 
static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
520
 
                          const void *buf, size_t size, size_t hdr_len)
521
 
{
522
 
    struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)iov[0].iov_base;
523
 
    int offset = 0;
524
 
 
525
 
    hdr->flags = 0;
526
 
    hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
527
 
 
528
 
    if (n->has_vnet_hdr) {
529
 
        memcpy(hdr, buf, sizeof(*hdr));
530
 
        offset = sizeof(*hdr);
531
 
        work_around_broken_dhclient(hdr, buf + offset, size - offset);
532
 
    }
533
 
 
534
 
    /* We only ever receive a struct virtio_net_hdr from the tapfd,
535
 
     * but we may be passing along a larger header to the guest.
536
 
     */
537
 
    iov[0].iov_base += hdr_len;
538
 
    iov[0].iov_len  -= hdr_len;
539
 
 
540
 
    return offset;
 
536
        void *wbuf = (void *)buf;
 
537
        work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
 
538
                                    size - n->host_hdr_len);
 
539
        iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
 
540
    } else {
 
541
        struct virtio_net_hdr hdr = {
 
542
            .flags = 0,
 
543
            .gso_type = VIRTIO_NET_HDR_GSO_NONE
 
544
        };
 
545
        iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr);
 
546
    }
541
547
}
542
548
 
543
549
static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
550
556
    if (n->promisc)
551
557
        return 1;
552
558
 
553
 
    if (n->has_vnet_hdr) {
554
 
        ptr += sizeof(struct virtio_net_hdr);
555
 
    }
 
559
    ptr += n->host_hdr_len;
556
560
 
557
561
    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
558
562
        int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
596
600
static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size)
597
601
{
598
602
    VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
599
 
    struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
600
 
    size_t guest_hdr_len, offset, i, host_hdr_len;
 
603
    struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
 
604
    struct virtio_net_hdr_mrg_rxbuf mhdr;
 
605
    unsigned mhdr_cnt = 0;
 
606
    size_t offset, i, guest_offset;
601
607
 
602
608
    if (!virtio_net_can_receive(&n->nic->nc))
603
609
        return -1;
604
610
 
605
611
    /* hdr_len refers to the header we supply to the guest */
606
 
    guest_hdr_len = n->mergeable_rx_bufs ?
607
 
        sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
608
 
 
609
 
 
610
 
    host_hdr_len = n->has_vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
611
 
    if (!virtio_net_has_buffers(n, size + guest_hdr_len - host_hdr_len))
 
612
    if (!virtio_net_has_buffers(n, size + n->guest_hdr_len - n->host_hdr_len))
612
613
        return 0;
613
614
 
614
615
    if (!receive_filter(n, buf, size))
619
620
    while (offset < size) {
620
621
        VirtQueueElement elem;
621
622
        int len, total;
622
 
        struct iovec sg[VIRTQUEUE_MAX_SIZE];
 
623
        const struct iovec *sg = elem.in_sg;
623
624
 
624
625
        total = 0;
625
626
 
630
631
                    "i %zd mergeable %d offset %zd, size %zd, "
631
632
                    "guest hdr len %zd, host hdr len %zd guest features 0x%x",
632
633
                    i, n->mergeable_rx_bufs, offset, size,
633
 
                    guest_hdr_len, host_hdr_len, n->vdev.guest_features);
 
634
                    n->guest_hdr_len, n->host_hdr_len, n->vdev.guest_features);
634
635
            exit(1);
635
636
        }
636
637
 
639
640
            exit(1);
640
641
        }
641
642
 
642
 
        if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) {
643
 
            error_report("virtio-net header not in first element");
644
 
            exit(1);
645
 
        }
646
 
 
647
 
        memcpy(&sg, &elem.in_sg[0], sizeof(sg[0]) * elem.in_num);
648
 
 
649
643
        if (i == 0) {
650
 
            if (n->mergeable_rx_bufs)
651
 
                mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;
 
644
            assert(offset == 0);
 
645
            if (n->mergeable_rx_bufs) {
 
646
                mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
 
647
                                    sg, elem.in_num,
 
648
                                    offsetof(typeof(mhdr), num_buffers),
 
649
                                    sizeof(mhdr.num_buffers));
 
650
            }
652
651
 
653
 
            offset += receive_header(n, sg, elem.in_num,
654
 
                                     buf + offset, size - offset, guest_hdr_len);
655
 
            total += guest_hdr_len;
 
652
            receive_header(n, sg, elem.in_num, buf, size);
 
653
            offset = n->host_hdr_len;
 
654
            total += n->guest_hdr_len;
 
655
            guest_offset = n->guest_hdr_len;
 
656
        } else {
 
657
            guest_offset = 0;
656
658
        }
657
659
 
658
660
        /* copy in packet.  ugh */
659
 
        len = iov_from_buf(sg, elem.in_num, 0,
 
661
        len = iov_from_buf(sg, elem.in_num, guest_offset,
660
662
                           buf + offset, size - offset);
661
663
        total += len;
662
664
        offset += len;
669
671
                         "i %zd mergeable %d offset %zd, size %zd, "
670
672
                         "guest hdr len %zd, host hdr len %zd",
671
673
                         i, n->mergeable_rx_bufs,
672
 
                         offset, size, guest_hdr_len, host_hdr_len);
 
674
                         offset, size, n->guest_hdr_len, n->host_hdr_len);
673
675
#endif
674
676
            return size;
675
677
        }
678
680
        virtqueue_fill(n->rx_vq, &elem, total, i++);
679
681
    }
680
682
 
681
 
    if (mhdr) {
682
 
        stw_p(&mhdr->num_buffers, i);
 
683
    if (mhdr_cnt) {
 
684
        stw_p(&mhdr.num_buffers, i);
 
685
        iov_from_buf(mhdr_sg, mhdr_cnt,
 
686
                     0,
 
687
                     &mhdr.num_buffers, sizeof mhdr.num_buffers);
683
688
    }
684
689
 
685
690
    virtqueue_flush(n->rx_vq, i);
694
699
{
695
700
    VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
696
701
 
697
 
    virtqueue_push(n->tx_vq, &n->async_tx.elem, n->async_tx.len);
 
702
    virtqueue_push(n->tx_vq, &n->async_tx.elem, 0);
698
703
    virtio_notify(&n->vdev, n->tx_vq);
699
704
 
700
705
    n->async_tx.elem.out_num = n->async_tx.len = 0;
720
725
    }
721
726
 
722
727
    while (virtqueue_pop(vq, &elem)) {
723
 
        ssize_t ret, len = 0;
 
728
        ssize_t ret, len;
724
729
        unsigned int out_num = elem.out_num;
725
730
        struct iovec *out_sg = &elem.out_sg[0];
726
 
        unsigned hdr_len;
727
 
 
728
 
        /* hdr_len refers to the header received from the guest */
729
 
        hdr_len = n->mergeable_rx_bufs ?
730
 
            sizeof(struct virtio_net_hdr_mrg_rxbuf) :
731
 
            sizeof(struct virtio_net_hdr);
732
 
 
733
 
        if (out_num < 1 || out_sg->iov_len != hdr_len) {
 
731
        struct iovec sg[VIRTQUEUE_MAX_SIZE];
 
732
 
 
733
        if (out_num < 1) {
734
734
            error_report("virtio-net header not in first element");
735
735
            exit(1);
736
736
        }
737
737
 
738
 
        /* ignore the header if GSO is not supported */
739
 
        if (!n->has_vnet_hdr) {
740
 
            out_num--;
741
 
            out_sg++;
742
 
            len += hdr_len;
743
 
        } else if (n->mergeable_rx_bufs) {
744
 
            /* tapfd expects a struct virtio_net_hdr */
745
 
            hdr_len -= sizeof(struct virtio_net_hdr);
746
 
            out_sg->iov_len -= hdr_len;
747
 
            len += hdr_len;
 
738
        /*
 
739
         * If host wants to see the guest header as is, we can
 
740
         * pass it on unchanged. Otherwise, copy just the parts
 
741
         * that host is interested in.
 
742
         */
 
743
        assert(n->host_hdr_len <= n->guest_hdr_len);
 
744
        if (n->host_hdr_len != n->guest_hdr_len) {
 
745
            unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg),
 
746
                                       out_sg, out_num,
 
747
                                       0, n->host_hdr_len);
 
748
            sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num,
 
749
                             out_sg, out_num,
 
750
                             n->guest_hdr_len, -1);
 
751
            out_num = sg_num;
 
752
            out_sg = sg;
748
753
        }
749
754
 
 
755
        len = n->guest_hdr_len;
 
756
 
750
757
        ret = qemu_sendv_packet_async(&n->nic->nc, out_sg, out_num,
751
758
                                      virtio_net_tx_complete);
752
759
        if (ret == 0) {
758
765
 
759
766
        len += ret;
760
767
 
761
 
        virtqueue_push(vq, &elem, len);
 
768
        virtqueue_push(vq, &elem, 0);
762
769
        virtio_notify(&n->vdev, vq);
763
770
 
764
771
        if (++num_packets >= n->tx_burst) {
903
910
 
904
911
    qemu_get_buffer(f, n->mac, ETH_ALEN);
905
912
    n->tx_waiting = qemu_get_be32(f);
906
 
    n->mergeable_rx_bufs = qemu_get_be32(f);
 
913
 
 
914
    virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f));
907
915
 
908
916
    if (version_id >= 3)
909
917
        n->status = qemu_get_be16(f);
925
933
            qemu_get_buffer(f, n->mac_table.macs,
926
934
                            n->mac_table.in_use * ETH_ALEN);
927
935
        } else if (n->mac_table.in_use) {
928
 
            qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR);
 
936
            uint8_t *buf = g_malloc0(n->mac_table.in_use);
 
937
            qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN);
 
938
            g_free(buf);
929
939
            n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
930
940
            n->mac_table.in_use = 0;
931
941
        }
941
951
        }
942
952
 
943
953
        if (n->has_vnet_hdr) {
944
 
            tap_using_vnet_hdr(n->nic->nc.peer, 1);
945
954
            tap_set_offload(n->nic->nc.peer,
946
955
                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
947
956
                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
977
986
        }
978
987
    }
979
988
    n->mac_table.first_multi = i;
 
989
 
 
990
    /* nc.link_down can't be migrated, so infer link_down according
 
991
     * to link status bit in n->status */
 
992
    n->nic->nc.link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0;
 
993
 
980
994
    return 0;
981
995
}
982
996
 
1035
1049
    n->status = VIRTIO_NET_S_LINK_UP;
1036
1050
 
1037
1051
    n->nic = qemu_new_nic(&net_virtio_info, conf, object_get_typename(OBJECT(dev)), dev->id, n);
 
1052
    peer_test_vnet_hdr(n);
 
1053
    if (peer_has_vnet_hdr(n)) {
 
1054
        tap_using_vnet_hdr(n->nic->nc.peer, 1);
 
1055
        n->host_hdr_len = sizeof(struct virtio_net_hdr);
 
1056
    } else {
 
1057
        n->host_hdr_len = 0;
 
1058
    }
1038
1059
 
1039
1060
    qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a);
1040
1061
 
1041
1062
    n->tx_waiting = 0;
1042
1063
    n->tx_burst = net->txburst;
1043
 
    n->mergeable_rx_bufs = 0;
 
1064
    virtio_net_set_mrg_rx_bufs(n, 0);
1044
1065
    n->promisc = 1; /* for compatibility */
1045
1066
 
1046
1067
    n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);