All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <aliguori@us.ibm.com>
To: qemu-devel@nongnu.org, Avi Kivity <avi@qumranet.com>,
	Dor Laor <dor.laor@qumranet.com>,
	Rusty Russell <rusty@rustcorp.com.au>
Subject: [Qemu-devel] [PATCH 2/3] virtio network device
Date: Tue, 04 Dec 2007 15:54:20 -0600	[thread overview]
Message-ID: <4755CC8C.6000001@us.ibm.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 2 bytes --]




[-- Attachment #2: virtio-net.diff --]
[-- Type: text/x-patch, Size: 7193 bytes --]

Subject: [PATCH 2/3] virtio network device
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Avi Kivity <avi@qumranet.com>
Cc: Dor Laor <dor.laor@qumranet.com>

This patch implements the backend support for the virtio network device.  The
device is optimized for virtualized environments by limiting the number of
guest=>host transitions per-packet.  In the best case, the number of
transitions per-packet is < 1.

With some further optimizations, I have been able to obtain 1.5gbit/sec
host=>guest with this driver (compared to the 90mbit/sec from the rtl8139
card).  This requires additional patches not present in this series.

Index: qemu/Makefile.target
===================================================================
--- qemu.orig/Makefile.target	2007-12-04 14:15:20.000000000 -0600
+++ qemu/Makefile.target	2007-12-04 14:43:57.000000000 -0600
@@ -436,7 +436,7 @@
 VL_OBJS += rtl8139.o
 
 # virtio devices
-VL_OBJS += virtio.o
+VL_OBJS += virtio.o virtio-net.o
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
Index: qemu/hw/pci.c
===================================================================
--- qemu.orig/hw/pci.c	2007-12-04 14:15:20.000000000 -0600
+++ qemu/hw/pci.c	2007-12-04 14:44:06.000000000 -0600
@@ -25,6 +25,7 @@
 #include "pci.h"
 #include "console.h"
 #include "net.h"
+#include "pc.h"
 
 //#define DEBUG_PCI
 
@@ -591,9 +592,11 @@
         pci_rtl8139_init(bus, nd, devfn);
     } else if (strcmp(nd->model, "pcnet") == 0) {
         pci_pcnet_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "virtio") == 0) {
+	virtio_net_init(bus, nd, devfn);
     } else if (strcmp(nd->model, "?") == 0) {
         fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
-                        " ne2k_pci pcnet rtl8139\n");
+                        " ne2k_pci pcnet rtl8139 virtio\n");
         exit (1);
     } else {
         fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
Index: qemu/hw/virtio-net.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ qemu/hw/virtio-net.c	2007-12-04 14:17:37.000000000 -0600
@@ -0,0 +1,178 @@
+/*
+ * Virtio Network Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio.h"
+#include "net.h"
+#include "pc.h"
+
+/* from Linux's virtio_net.h */
+
+/* The ID for virtio_net */
+#define VIRTIO_ID_NET	1
+
+/* The feature bitmap for virtio net */
+#define VIRTIO_NET_F_NO_CSUM	0
+#define VIRTIO_NET_F_TSO4	1
+#define VIRTIO_NET_F_UFO	2
+#define VIRTIO_NET_F_TSO4_ECN	3
+#define VIRTIO_NET_F_TSO6	4
+#define VIRTIO_NET_F_MAC	5
+
+/* The config defining mac address (6 bytes) */
+struct virtio_net_config
+{
+    uint8_t mac[6];
+} __attribute__((packed));
+
+/* This is the first element of the scatter-gather list.  If you don't
+ * specify GSO or CSUM features, you can simply ignore the header. */
+struct virtio_net_hdr
+{
+#define VIRTIO_NET_HDR_F_NEEDS_CSUM	1	// Use csum_start, csum_offset
+    uint8_t flags;
+#define VIRTIO_NET_HDR_GSO_NONE		0	// Not a GSO frame
+#define VIRTIO_NET_HDR_GSO_TCPV4	1	// GSO frame, IPv4 TCP (TSO)
+/* FIXME: Do we need this?  If they said they can handle ECN, do they care? */
+#define VIRTIO_NET_HDR_GSO_TCPV4_ECN	2	// GSO frame, IPv4 TCP w/ ECN
+#define VIRTIO_NET_HDR_GSO_UDP		3	// GSO frame, IPv4 UDP (UFO)
+#define VIRTIO_NET_HDR_GSO_TCPV6	4	// GSO frame, IPv6 TCP
+    uint8_t gso_type;
+    uint16_t gso_size;
+    uint16_t csum_start;
+    uint16_t csum_offset;
+};
+
+typedef struct VirtIONet
+{
+    VirtIODevice vdev;
+    uint8_t mac[6];
+    VirtQueue *rx_vq;
+    VirtQueue *tx_vq;
+    VLANClientState *vc;
+    int can_receive;
+} VirtIONet;
+
+static VirtIONet *to_virtio_net(VirtIODevice *vdev)
+{
+    return (VirtIONet *)vdev;
+}
+
+static void virtio_net_update_config(VirtIODevice *vdev, uint8_t *config)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    struct virtio_net_config netcfg;
+
+    memcpy(netcfg.mac, n->mac, 6);
+    memcpy(config, &netcfg, sizeof(netcfg));
+}
+
+static uint32_t virtio_net_get_features(VirtIODevice *vdev)
+{
+    return (1 << VIRTIO_NET_F_MAC);
+}
+
+/* RX */
+
+static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    n->can_receive = 1;
+}
+
+static int virtio_net_can_receive(void *opaque)
+{
+    VirtIONet *n = opaque;
+
+    return (n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) && n->can_receive;
+}
+
+static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
+{
+    VirtIONet *n = opaque;
+    VirtQueueElement elem;
+    struct virtio_net_hdr *hdr;
+    int offset, i;
+
+    /* FIXME: the drivers really need to set their status better */
+    if (n->rx_vq->vring.avail == NULL) {
+	n->can_receive = 0;
+	return;
+    }
+
+    if (virtqueue_pop(n->rx_vq, &elem) == 0) {
+	/* wait until the guest adds some rx bufs */
+	n->can_receive = 0;
+	return;
+    }
+
+    hdr = (void *)elem.in_sg[0].iov_base;
+    hdr->flags = 0;
+    hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+
+    /* copy in packet.  ugh */
+    offset = 0;
+    i = 1;
+    while (offset < size && i < elem.in_num) {
+	int len = MIN(elem.in_sg[i].iov_len, size - offset);
+	memcpy(elem.in_sg[i].iov_base, buf + offset, len);
+	offset += len;
+	i++;
+    }
+
+    /* signal other side */
+    virtqueue_push(n->rx_vq, &elem, sizeof(*hdr) + offset);
+    virtio_notify(&n->vdev, n->rx_vq);
+}
+
+/* TX */
+static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    VirtQueueElement elem;
+
+    while (virtqueue_pop(vq, &elem)) {
+	int i;
+	size_t len = 0;
+
+	/* ignore the header for now */
+	for (i = 1; i < elem.out_num; i++) {
+	    qemu_send_packet(n->vc, elem.out_sg[i].iov_base,
+			     elem.out_sg[i].iov_len);
+	    len += elem.out_sg[i].iov_len;
+	}
+
+	virtqueue_push(vq, &elem, sizeof(struct virtio_net_hdr) + len);
+	virtio_notify(&n->vdev, vq);
+    }
+}
+
+void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
+{
+    VirtIONet *n;
+
+    n = (VirtIONet *)virtio_init_pci(bus, "virtio-net", 6900, 0x1000,
+				     0, VIRTIO_ID_NET,
+				     0x02, 0x00, 0x00,
+				     6, sizeof(VirtIONet));
+
+    n->vdev.update_config = virtio_net_update_config;
+    n->vdev.get_features = virtio_net_get_features;
+    n->rx_vq = virtio_add_queue(&n->vdev, 512, virtio_net_handle_rx);
+    n->tx_vq = virtio_add_queue(&n->vdev, 128, virtio_net_handle_tx);
+    n->can_receive = 0;
+    memcpy(n->mac, nd->macaddr, 6);
+    n->vc = qemu_new_vlan_client(nd->vlan, virtio_net_receive,
+				 virtio_net_can_receive, n);
+
+    return &n->vdev;
+}
Index: qemu/hw/pc.h
===================================================================
--- qemu.orig/hw/pc.h	2007-12-04 14:15:20.000000000 -0600
+++ qemu/hw/pc.h	2007-12-04 14:43:57.000000000 -0600
@@ -142,4 +142,9 @@
 
 void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd);
 
+/* virtio-net.c */
+
+void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn);
+
+
 #endif

             reply	other threads:[~2007-12-04 21:54 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-12-04 21:54 Anthony Liguori [this message]
2007-12-04 22:12 ` [Qemu-devel] [PATCH 2/3] virtio network device Anthony Liguori
2007-12-04 23:49 ` [Qemu-devel] " Dor Laor
2007-12-05 17:18   ` Anthony Liguori
2007-12-05 17:44     ` Paul Brook
2007-12-05 20:20       ` Anthony Liguori
2007-12-06  9:27         ` Jamie Lokier
2007-12-08 13:22         ` Paul Brook
2007-12-08 14:09           ` Jamie Lokier
2007-12-08 16:45             ` Paul Brook
2007-12-08 19:52               ` Blue Swirl
2007-12-08 21:55               ` Jamie Lokier
2007-12-08 22:02                 ` Anthony Liguori
2007-12-12  1:24                   ` Rusty Russell
2007-12-12  1:40                     ` Anthony Liguori
2007-12-18  2:31                       ` Rusty Russell
2007-12-08 21:59           ` Anthony Liguori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4755CC8C.6000001@us.ibm.com \
    --to=aliguori@us.ibm.com \
    --cc=avi@qumranet.com \
    --cc=dor.laor@qumranet.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rusty@rustcorp.com.au \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.