Commit fbe78f4f55c6fdf1f8df3d82bf31835de9283fa3

Authored by aliguori
1 parent fc9902d9

virtio-net support

This adds virtio-net support.  This is based on the virtio-net driver 
that exists in kvm-userspace.  This also adds a new qemu_sendv_packet 
which virtio-net requires.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6073 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -637,7 +637,7 @@ OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
637 637 OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
638 638 OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o
639 639 # virtio support
640   -OBJS+= virtio.o virtio-blk.o virtio-balloon.o
  640 +OBJS+= virtio.o virtio-blk.o virtio-balloon.o virtio-net.o
641 641 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
642 642 endif
643 643 ifeq ($(TARGET_BASE_ARCH), ppc)
... ... @@ -664,7 +664,7 @@ ifdef CONFIG_KVM
664 664 OBJS+= kvm_ppc.o
665 665 endif
666 666 # virtio support
667   -OBJS+= virtio.o virtio-blk.o virtio-balloon.o
  667 +OBJS+= virtio.o virtio-blk.o virtio-balloon.o virtio-net.o
668 668 endif
669 669 ifeq ($(TARGET_BASE_ARCH), mips)
670 670 OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
... ...
hw/pci.c
... ... @@ -25,6 +25,7 @@
25 25 #include "pci.h"
26 26 #include "console.h"
27 27 #include "net.h"
  28 +#include "virtio-net.h"
28 29  
29 30 //#define DEBUG_PCI
30 31  
... ... @@ -654,9 +655,11 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn)
654 655 pci_e1000_init(bus, nd, devfn);
655 656 } else if (strcmp(nd->model, "pcnet") == 0) {
656 657 pci_pcnet_init(bus, nd, devfn);
  658 + } else if (strcmp(nd->model, "virtio") == 0) {
  659 + virtio_net_init(bus, nd, devfn);
657 660 } else if (strcmp(nd->model, "?") == 0) {
658 661 fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
659   - " ne2k_pci pcnet rtl8139 e1000\n");
  662 + " ne2k_pci pcnet rtl8139 e1000 virtio\n");
660 663 exit (1);
661 664 } else {
662 665 fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
... ...
hw/virtio-net.c 0 → 100644
  1 +/*
  2 + * Virtio Network Device
  3 + *
  4 + * Copyright IBM, Corp. 2007
  5 + *
  6 + * Authors:
  7 + * Anthony Liguori <aliguori@us.ibm.com>
  8 + *
  9 + * This work is licensed under the terms of the GNU GPL, version 2. See
  10 + * the COPYING file in the top-level directory.
  11 + *
  12 + */
  13 +
  14 +#include "virtio.h"
  15 +#include "net.h"
  16 +#include "qemu-timer.h"
  17 +#include "virtio-net.h"
  18 +
  19 +typedef struct VirtIONet
  20 +{
  21 + VirtIODevice vdev;
  22 + uint8_t mac[6];
  23 + VirtQueue *rx_vq;
  24 + VirtQueue *tx_vq;
  25 + VLANClientState *vc;
  26 + QEMUTimer *tx_timer;
  27 + int tx_timer_active;
  28 + int mergeable_rx_bufs;
  29 +} VirtIONet;
  30 +
  31 +/* TODO
  32 + * - we could suppress RX interrupt if we were so inclined.
  33 + */
  34 +
  35 +static VirtIONet *to_virtio_net(VirtIODevice *vdev)
  36 +{
  37 + return (VirtIONet *)vdev;
  38 +}
  39 +
  40 +static void virtio_net_update_config(VirtIODevice *vdev, uint8_t *config)
  41 +{
  42 + VirtIONet *n = to_virtio_net(vdev);
  43 + struct virtio_net_config netcfg;
  44 +
  45 + memcpy(netcfg.mac, n->mac, 6);
  46 + memcpy(config, &netcfg, sizeof(netcfg));
  47 +}
  48 +
  49 +static uint32_t virtio_net_get_features(VirtIODevice *vdev)
  50 +{
  51 + uint32_t features = (1 << VIRTIO_NET_F_MAC);
  52 +
  53 + return features;
  54 +}
  55 +
  56 +static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
  57 +{
  58 + VirtIONet *n = to_virtio_net(vdev);
  59 +
  60 + n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF));
  61 +}
  62 +
  63 +/* RX */
  64 +
  65 +static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
  66 +{
  67 +}
  68 +
  69 +static int do_virtio_net_can_receive(VirtIONet *n, int bufsize)
  70 +{
  71 + if (!virtio_queue_ready(n->rx_vq) ||
  72 + !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
  73 + return 0;
  74 +
  75 + if (virtio_queue_empty(n->rx_vq) ||
  76 + (n->mergeable_rx_bufs &&
  77 + !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) {
  78 + virtio_queue_set_notification(n->rx_vq, 1);
  79 + return 0;
  80 + }
  81 +
  82 + virtio_queue_set_notification(n->rx_vq, 0);
  83 + return 1;
  84 +}
  85 +
  86 +static int virtio_net_can_receive(void *opaque)
  87 +{
  88 + VirtIONet *n = opaque;
  89 +
  90 + return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE);
  91 +}
  92 +
  93 +static int iov_fill(struct iovec *iov, int iovcnt, const void *buf, int count)
  94 +{
  95 + int offset, i;
  96 +
  97 + offset = i = 0;
  98 + while (offset < count && i < iovcnt) {
  99 + int len = MIN(iov[i].iov_len, count - offset);
  100 + memcpy(iov[i].iov_base, buf + offset, len);
  101 + offset += len;
  102 + i++;
  103 + }
  104 +
  105 + return offset;
  106 +}
  107 +
  108 +static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
  109 + const void *buf, int size, int hdr_len)
  110 +{
  111 + struct virtio_net_hdr *hdr = iov[0].iov_base;
  112 + int offset = 0;
  113 +
  114 + hdr->flags = 0;
  115 + hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
  116 +
  117 + /* We only ever receive a struct virtio_net_hdr from the tapfd,
  118 + * but we may be passing along a larger header to the guest.
  119 + */
  120 + iov[0].iov_base += hdr_len;
  121 + iov[0].iov_len -= hdr_len;
  122 +
  123 + return offset;
  124 +}
  125 +
  126 +static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
  127 +{
  128 + VirtIONet *n = opaque;
  129 + struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
  130 + int hdr_len, offset, i;
  131 +
  132 + if (!do_virtio_net_can_receive(n, size))
  133 + return;
  134 +
  135 + /* hdr_len refers to the header we supply to the guest */
  136 + hdr_len = n->mergeable_rx_bufs ?
  137 + sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
  138 +
  139 + offset = i = 0;
  140 +
  141 + while (offset < size) {
  142 + VirtQueueElement elem;
  143 + int len, total;
  144 + struct iovec sg[VIRTQUEUE_MAX_SIZE];
  145 +
  146 + len = total = 0;
  147 +
  148 + if ((i != 0 && !n->mergeable_rx_bufs) ||
  149 + virtqueue_pop(n->rx_vq, &elem) == 0) {
  150 + if (i == 0)
  151 + return;
  152 + fprintf(stderr, "virtio-net truncating packet\n");
  153 + exit(1);
  154 + }
  155 +
  156 + if (elem.in_num < 1) {
  157 + fprintf(stderr, "virtio-net receive queue contains no in buffers\n");
  158 + exit(1);
  159 + }
  160 +
  161 + if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != hdr_len) {
  162 + fprintf(stderr, "virtio-net header not in first element\n");
  163 + exit(1);
  164 + }
  165 +
  166 + memcpy(&sg, &elem.in_sg[0], sizeof(sg[0]) * elem.in_num);
  167 +
  168 + if (i == 0) {
  169 + if (n->mergeable_rx_bufs)
  170 + mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;
  171 +
  172 + offset += receive_header(n, sg, elem.in_num,
  173 + buf + offset, size - offset, hdr_len);
  174 + total += hdr_len;
  175 + }
  176 +
  177 + /* copy in packet. ugh */
  178 + len = iov_fill(sg, elem.in_num,
  179 + buf + offset, size - offset);
  180 + total += len;
  181 +
  182 + /* signal other side */
  183 + virtqueue_fill(n->rx_vq, &elem, total, i++);
  184 +
  185 + offset += len;
  186 + }
  187 +
  188 + if (mhdr)
  189 + mhdr->num_buffers = i;
  190 +
  191 + virtqueue_flush(n->rx_vq, i);
  192 + virtio_notify(&n->vdev, n->rx_vq);
  193 +}
  194 +
  195 +/* TX */
  196 +static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
  197 +{
  198 + VirtQueueElement elem;
  199 + int has_vnet_hdr = 0;
  200 +
  201 + if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
  202 + return;
  203 +
  204 + while (virtqueue_pop(vq, &elem)) {
  205 + ssize_t len = 0;
  206 + unsigned int out_num = elem.out_num;
  207 + struct iovec *out_sg = &elem.out_sg[0];
  208 + unsigned hdr_len;
  209 +
  210 + /* hdr_len refers to the header received from the guest */
  211 + hdr_len = n->mergeable_rx_bufs ?
  212 + sizeof(struct virtio_net_hdr_mrg_rxbuf) :
  213 + sizeof(struct virtio_net_hdr);
  214 +
  215 + if (out_num < 1 || out_sg->iov_len != hdr_len) {
  216 + fprintf(stderr, "virtio-net header not in first element\n");
  217 + exit(1);
  218 + }
  219 +
  220 + /* ignore the header if GSO is not supported */
  221 + if (!has_vnet_hdr) {
  222 + out_num--;
  223 + out_sg++;
  224 + len += hdr_len;
  225 + } else if (n->mergeable_rx_bufs) {
  226 + /* tapfd expects a struct virtio_net_hdr */
  227 + hdr_len -= sizeof(struct virtio_net_hdr);
  228 + out_sg->iov_len -= hdr_len;
  229 + len += hdr_len;
  230 + }
  231 +
  232 + len += qemu_sendv_packet(n->vc, out_sg, out_num);
  233 +
  234 + virtqueue_push(vq, &elem, len);
  235 + virtio_notify(&n->vdev, vq);
  236 + }
  237 +}
  238 +
  239 +static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
  240 +{
  241 + VirtIONet *n = to_virtio_net(vdev);
  242 +
  243 + if (n->tx_timer_active) {
  244 + virtio_queue_set_notification(vq, 1);
  245 + qemu_del_timer(n->tx_timer);
  246 + n->tx_timer_active = 0;
  247 + virtio_net_flush_tx(n, vq);
  248 + } else {
  249 + qemu_mod_timer(n->tx_timer,
  250 + qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
  251 + n->tx_timer_active = 1;
  252 + virtio_queue_set_notification(vq, 0);
  253 + }
  254 +}
  255 +
  256 +static void virtio_net_tx_timer(void *opaque)
  257 +{
  258 + VirtIONet *n = opaque;
  259 +
  260 + n->tx_timer_active = 0;
  261 +
  262 + /* Just in case the driver is not ready on more */
  263 + if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
  264 + return;
  265 +
  266 + virtio_queue_set_notification(n->tx_vq, 1);
  267 + virtio_net_flush_tx(n, n->tx_vq);
  268 +}
  269 +
  270 +static void virtio_net_save(QEMUFile *f, void *opaque)
  271 +{
  272 + VirtIONet *n = opaque;
  273 +
  274 + virtio_save(&n->vdev, f);
  275 +
  276 + qemu_put_buffer(f, n->mac, 6);
  277 + qemu_put_be32(f, n->tx_timer_active);
  278 +}
  279 +
  280 +static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
  281 +{
  282 + VirtIONet *n = opaque;
  283 +
  284 + if (version_id != 1)
  285 + return -EINVAL;
  286 +
  287 + virtio_load(&n->vdev, f);
  288 +
  289 + qemu_get_buffer(f, n->mac, 6);
  290 + n->tx_timer_active = qemu_get_be32(f);
  291 +
  292 + if (n->tx_timer_active) {
  293 + qemu_mod_timer(n->tx_timer,
  294 + qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
  295 + }
  296 +
  297 + return 0;
  298 +}
  299 +
  300 +PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
  301 +{
  302 + VirtIONet *n;
  303 + static int virtio_net_id;
  304 +
  305 + n = (VirtIONet *)virtio_init_pci(bus, "virtio-net", 6900, 0x1000,
  306 + 0, VIRTIO_ID_NET,
  307 + 0x02, 0x00, 0x00,
  308 + 6, sizeof(VirtIONet));
  309 + if (!n)
  310 + return NULL;
  311 +
  312 + n->vdev.get_config = virtio_net_update_config;
  313 + n->vdev.get_features = virtio_net_get_features;
  314 + n->vdev.set_features = virtio_net_set_features;
  315 + n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
  316 + n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx);
  317 + memcpy(n->mac, nd->macaddr, 6);
  318 + n->vc = qemu_new_vlan_client(nd->vlan, virtio_net_receive,
  319 + virtio_net_can_receive, n);
  320 +
  321 + n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n);
  322 + n->tx_timer_active = 0;
  323 + n->mergeable_rx_bufs = 0;
  324 +
  325 + register_savevm("virtio-net", virtio_net_id++, 1,
  326 + virtio_net_save, virtio_net_load, n);
  327 +
  328 + return (PCIDevice *)n;
  329 +}
... ...
hw/virtio-net.h 0 → 100644
  1 +/*
  2 + * Virtio Network Device
  3 + *
  4 + * Copyright IBM, Corp. 2007
  5 + *
  6 + * Authors:
  7 + * Anthony Liguori <aliguori@us.ibm.com>
  8 + *
  9 + * This work is licensed under the terms of the GNU GPL, version 2. See
  10 + * the COPYING file in the top-level directory.
  11 + *
  12 + */
  13 +
  14 +#ifndef _QEMU_VIRTIO_NET_H
  15 +#define _QEMU_VIRTIO_NET_H
  16 +
  17 +#include "virtio.h"
  18 +#include "net.h"
  19 +#include "pci.h"
  20 +
  21 +/* from Linux's virtio_net.h */
  22 +
  23 +/* The ID for virtio_net */
  24 +#define VIRTIO_ID_NET 1
  25 +
  26 +/* The feature bitmap for virtio net */
  27 +#define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */
  28 +#define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */
  29 +#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */
  30 +#define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */
  31 +#define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in. */
  32 +#define VIRTIO_NET_F_GUEST_TSO6 8 /* Guest can handle TSOv6 in. */
  33 +#define VIRTIO_NET_F_GUEST_ECN 9 /* Guest can handle TSO[6] w/ ECN in. */
  34 +#define VIRTIO_NET_F_GUEST_UFO 10 /* Guest can handle UFO in. */
  35 +#define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in. */
  36 +#define VIRTIO_NET_F_HOST_TSO6 12 /* Host can handle TSOv6 in. */
  37 +#define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in. */
  38 +#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */
  39 +#define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */
  40 +
  41 +#define TX_TIMER_INTERVAL 150000 /* 150 us */
  42 +
  43 +/* Maximum packet size we can receive from tap device: header + 64k */
  44 +#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
  45 +
  46 +/* The config defining mac address (6 bytes) */
  47 +struct virtio_net_config
  48 +{
  49 + uint8_t mac[6];
  50 +} __attribute__((packed));
  51 +
  52 +/* This is the first element of the scatter-gather list. If you don't
  53 + * specify GSO or CSUM features, you can simply ignore the header. */
  54 +struct virtio_net_hdr
  55 +{
  56 +#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset
  57 + uint8_t flags;
  58 +#define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame
  59 +#define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO)
  60 +#define VIRTIO_NET_HDR_GSO_UDP 3 // GSO frame, IPv4 UDP (UFO)
  61 +#define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP
  62 +#define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set
  63 + uint8_t gso_type;
  64 + uint16_t hdr_len;
  65 + uint16_t gso_size;
  66 + uint16_t csum_start;
  67 + uint16_t csum_offset;
  68 +};
  69 +
  70 +/* This is the version of the header to use when the MRG_RXBUF
  71 + * feature has been negotiated. */
  72 +struct virtio_net_hdr_mrg_rxbuf
  73 +{
  74 + struct virtio_net_hdr hdr;
  75 + uint16_t num_buffers; /* Number of merged rx buffers */
  76 +};
  77 +
  78 +PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn);
  79 +
  80 +#endif
... ...
... ... @@ -369,6 +369,50 @@ void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
369 369 }
370 370 }
371 371  
  372 +static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
  373 + int iovcnt)
  374 +{
  375 + uint8_t buffer[4096];
  376 + size_t offset = 0;
  377 + int i;
  378 +
  379 + for (i = 0; i < iovcnt; i++) {
  380 + size_t len;
  381 +
  382 + len = MIN(sizeof(buffer) - offset, iov[i].iov_len);
  383 + memcpy(buffer + offset, iov[i].iov_base, len);
  384 + offset += len;
  385 + }
  386 +
  387 + vc->fd_read(vc->opaque, buffer, offset);
  388 +
  389 + return offset;
  390 +}
  391 +
  392 +ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov,
  393 + int iovcnt)
  394 +{
  395 + VLANState *vlan = vc1->vlan;
  396 + VLANClientState *vc;
  397 + ssize_t max_len = 0;
  398 +
  399 + for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
  400 + ssize_t len = 0;
  401 +
  402 + if (vc == vc1)
  403 + continue;
  404 +
  405 + if (vc->fd_readv)
  406 + len = vc->fd_readv(vc->opaque, iov, iovcnt);
  407 + else if (vc->fd_read)
  408 + len = vc_sendv_compat(vc, iov, iovcnt);
  409 +
  410 + max_len = MAX(max_len, len);
  411 + }
  412 +
  413 + return max_len;
  414 +}
  415 +
372 416 #if defined(CONFIG_SLIRP)
373 417  
374 418 /* slirp network adapter */
... ...
1 1 #ifndef QEMU_NET_H
2 2 #define QEMU_NET_H
3 3  
  4 +#include "qemu-common.h"
  5 +
4 6 /* VLANs support */
5 7  
  8 +typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int);
  9 +
6 10 typedef struct VLANClientState VLANClientState;
7 11  
8 12 struct VLANClientState {
9 13 IOReadHandler *fd_read;
  14 + IOReadvHandler *fd_readv;
10 15 /* Packets may still be sent if this returns zero. It's used to
11 16 rate-limit the slirp code. */
12 17 IOCanRWHandler *fd_can_read;
... ... @@ -30,6 +35,8 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan,
30 35 void *opaque);
31 36 void qemu_del_vlan_client(VLANClientState *vc);
32 37 int qemu_can_send_packet(VLANClientState *vc);
  38 +ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
  39 + int iovcnt);
33 40 void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
34 41 void qemu_handler_true(void *opaque);
35 42  
... ...