Thanks! Merged to master at 5bb3ad6e5867..22c2a880932b (from, to]
You can see the entire diff with 'git diff' or at https://github.com/brho/akaros/compare/5bb3ad6e5867...22c2a880932b On 2016-07-01 at 09:19 Kyle Milka <[email protected]> wrote: > From: Kyle Milka <[email protected]> > > We were able to get Linux to send a ping through the virtio device. Used > linux/lguest.c as a starting point and virtio_lguest_console.c for finding > the names of our version of the functions. This included adding the > network device struct and transmit and receive functions. > > Fixes: b/29178446 > Change-Id: I840c0acc617d238fb2b24b5662ee76f615bc743f > Signed-off-by: Kyle Milka <[email protected]> > --- > tests/vmm/vmrunkernel.c | 58 ++++++++++- > user/vmm/include/vmm/virtio_net.h | 9 +- > user/vmm/include/vmm/vmm.h | 5 +- > user/vmm/virtio.c | 5 + > user/vmm/virtio_net.c | 209 > ++++++++++++++++++++++++++++++++++++++ > 5 files changed, 278 insertions(+), 8 deletions(-) > create mode 100644 user/vmm/virtio_net.c > > diff --git a/tests/vmm/vmrunkernel.c b/tests/vmm/vmrunkernel.c > index d00c441..da704f2 100644 > --- a/tests/vmm/vmrunkernel.c > +++ b/tests/vmm/vmrunkernel.c > @@ -27,6 +27,7 @@ > #include <vmm/virtio_ids.h> > #include <vmm/virtio_config.h> > #include <vmm/virtio_console.h> > +#include <vmm/virtio_net.h> > #include <vmm/virtio_lguest_console.h> > > #include <vmm/sched.h> > @@ -92,10 +93,11 @@ struct acpi_table_madt madt = { > }, > > .address = 0xfee00000ULL, > + .flags = 0, > }; > > struct acpi_madt_local_apic Apic0 = {.header = {.type = > ACPI_MADT_TYPE_LOCAL_APIC, .length = sizeof(struct acpi_madt_local_apic)}, > - .processor_id = 0, .id = 0}; > + .processor_id = 0, .id = 0, .lapic_flags = > 1}; > struct acpi_madt_io_apic Apic1 = {.header = {.type = ACPI_MADT_TYPE_IO_APIC, > .length = sizeof(struct acpi_madt_io_apic)}, > .id = 0, .address = 0xfec00000, > .global_irq_base = 0}; > struct acpi_madt_local_x2apic X2Apic0 = { > @@ -164,6 +166,7 @@ void vapic_status_dump(FILE *f, void *vapic); > #define LOCK_PREFIX "lock " > #define ADDR BITOP_ADDR(addr) > static inline int test_and_set_bit(int nr, volatile unsigned long *addr); > +static int default_nic = 1; > > pthread_t timerthread_struct; > > @@ -204,9 +207,8 @@ static struct virtio_console_config cons_cfg_d; > static struct virtio_vq_dev cons_vqdev = { > .name = "console", > .dev_id = VIRTIO_ID_CONSOLE, > - .dev_feat = ((uint64_t)1 << VIRTIO_F_VERSION_1) > - | (1 << VIRTIO_RING_F_INDIRECT_DESC) > - , > + .dev_feat = > + (1ULL << VIRTIO_F_VERSION_1) | (1 << VIRTIO_RING_F_INDIRECT_DESC), > .num_vqs = 2, > .cfg = &cons_cfg, > .cfg_d = &cons_cfg_d, > @@ -228,6 +230,44 @@ static struct virtio_vq_dev cons_vqdev = { > } > }; > > +static struct virtio_mmio_dev net_mmio_dev = { > + .poke_guest = virtio_poke_guest, > + .irq = 27, > +}; > + > +static struct virtio_net_config net_cfg = { > + .max_virtqueue_pairs = 1 > +}; > +static struct virtio_net_config net_cfg_d = { > + .max_virtqueue_pairs = 1 > +}; > + > +static struct virtio_vq_dev net_vqdev = { > + .name = "network", > + .dev_id = VIRTIO_ID_NET, > + .dev_feat = (1ULL << VIRTIO_F_VERSION_1 | 1 << VIRTIO_NET_F_MAC), > + > + .num_vqs = 2, > + .cfg = &net_cfg, > + .cfg_d = &net_cfg_d, > + .cfg_sz = sizeof(struct virtio_net_config), > + .transport_dev = &net_mmio_dev, > + .vqs = { > + { > + .name = "net_receiveq", > + .qnum_max = 64, > + .srv_fn = net_receiveq_fn, > + .vqdev = &net_vqdev > + }, > + { > + .name = "net_transmitq", > + .qnum_max = 64, > + .srv_fn = net_transmitq_fn, > + .vqdev = &net_vqdev > + }, > + } > +}; > + > void lowmem() { > __asm__ __volatile__ (".section .lowmem, \"aw\"\n\tlow: > \n\t.=0x1000\n\t.align 0x100000\n\t.previous\n"); > } > @@ -566,10 +606,18 @@ int main(int argc, char **argv) > bp->e820_map[e820i - 1].size), > 512 * GiB); > > - cons_mmio_dev.addr = virtio_mmio_base_addr; > + cons_mmio_dev.addr = > + virtio_mmio_base_addr + PGSIZE * VIRTIO_MMIO_CONSOLE_DEV; > cons_mmio_dev.vqdev = &cons_vqdev; > vm->virtio_mmio_devices[VIRTIO_MMIO_CONSOLE_DEV] = &cons_mmio_dev; > > + net_mmio_dev.addr = > + virtio_mmio_base_addr + PGSIZE * VIRTIO_MMIO_NETWORK_DEV; > + net_mmio_dev.vqdev = &net_vqdev; > + vm->virtio_mmio_devices[VIRTIO_MMIO_NETWORK_DEV] = &net_mmio_dev; > + > + net_init_fn(&net_vqdev, default_nic); > + > /* Set the kernel command line parameters */ > a += 4096; > cmdline = a; > diff --git a/user/vmm/include/vmm/virtio_net.h > b/user/vmm/include/vmm/virtio_net.h > index 31b8f54..c020e69 100644 > --- a/user/vmm/include/vmm/virtio_net.h > +++ b/user/vmm/include/vmm/virtio_net.h > @@ -27,7 +27,6 @@ > #include <stdint.h> > #include <vmm/virtio_ids.h> > #include <vmm/virtio_config.h> > -#include <linux/if_ether.h> > > /* The feature bitmap for virtio net */ > #define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */ > @@ -61,6 +60,10 @@ > #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ > #define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */ > > +#ifndef ETH_ALEN > +#define ETH_ALEN 6 /* Length of a MAC address (48 bits) */ > +#endif > + > struct virtio_net_config { > /* The config defining mac address (if VIRTIO_NET_F_MAC) */ > uint8_t mac[ETH_ALEN]; > @@ -239,3 +242,7 @@ struct virtio_net_ctrl_mq { > */ > #define VIRTIO_NET_CTRL_GUEST_OFFLOADS 5 > #define VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET 0 > + > +void net_receiveq_fn(void *_vq); > +void net_transmitq_fn(void *_vq); > +void net_init_fn(struct virtio_vq_dev *vqdev, int nic); > diff --git a/user/vmm/include/vmm/vmm.h b/user/vmm/include/vmm/vmm.h > index a61d9ad..ca1d6ec 100644 > --- a/user/vmm/include/vmm/vmm.h > +++ b/user/vmm/include/vmm/vmm.h > @@ -10,12 +10,13 @@ > #include <vmm/sched.h> > > /* The listing of VIRTIO MMIO devices. We currently only expect to have 2, > - * console and network. Only the console is implemented right now.*/ > + * console and network. Only the console is fully implemented right now.*/ > enum { > VIRTIO_MMIO_CONSOLE_DEV, > + VIRTIO_MMIO_NETWORK_DEV, > > /* This should always be the last entry. */ > - VIRTIO_MMIO_MAX_NUM_DEV = 2, > + VIRTIO_MMIO_MAX_NUM_DEV, > }; > > /* Structure to encapsulate all of the bookkeeping for a VM. */ > diff --git a/user/vmm/virtio.c b/user/vmm/virtio.c > index 165cb47..f64d1e2 100644 > --- a/user/vmm/virtio.c > +++ b/user/vmm/virtio.c > @@ -32,6 +32,11 @@ const char *virtio_validate_feat(struct virtio_vq_dev > *vqdev, uint64_t feat) > case VIRTIO_ID_CONSOLE: > // No interdependent features for the console. > break; > + case VIRTIO_ID_NET: > + // There is no "mandatory" feature bit that we always > want to have, > + // either the device can set its own MAC Address (as it > does now) > + // or the driver can set it using a controller thread. > + break; > case 0: > return "Invalid device id (0x0)! On the MMIO transport, > this value indicates that the device is a system memory map with placeholder > devices at static, well known addresses. In any case, this is not something > you validate features for."; > default: > diff --git a/user/vmm/virtio_net.c b/user/vmm/virtio_net.c > new file mode 100644 > index 0000000..40299a0 > --- /dev/null > +++ b/user/vmm/virtio_net.c > @@ -0,0 +1,209 @@ > +/* Virtio helper functions from linux/tools/lguest/lguest.c > + * > + * Copyright (C) 1991-2016, the Linux Kernel authors > + * Copyright (c) 2016 Google Inc. > + * > + * Author: > + * Rusty Russell <[email protected]> > + * Kyle Milka <[email protected]> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * The code from lguest.c has been modified for Akaros. > + * > + * Original linux/tools/lguest/lguest.c: > + * https://github.com/torvalds/linux/blob/v4.5/tools/lguest/lguest.c > + * most recent hash on the file as of v4.5 tag: > + * e523caa601f4a7c2fa1ecd040db921baf7453798 > + */ > + > +#include <stdlib.h> > +#include <unistd.h> > +#include <stdio.h> > +#include <fcntl.h> > +#include <vmm/virtio.h> > +#include <vmm/virtio_mmio.h> > +#include <vmm/virtio_net.h> > + > +#define VIRTIO_HEADER_SIZE 12 > + > +static int ctlfd; > +static int etherfd; > +static char data_path[128]; > +static char clone_path[64]; > + > +void net_init_fn(struct virtio_vq_dev *vqdev, int nic) > +{ > + char type[] = "connect -1"; > + char buf[8]; > + char addr_path[32]; > + char addr_buf[3]; > + int addr_fd; > + uint8_t addr_bytes; > + int num_read; > + int total_read = 0; > + > + snprintf(addr_path, sizeof(addr_path), "/net/ether%d/addr", nic); > + addr_fd = open(addr_path, O_RDONLY); > + if (addr_fd < 0) > + VIRTIO_DEV_ERRX(vqdev, "Bad addr_fd\n"); > + > + for (int i = 0; i < ETH_ALEN; ++i) { > + assert(read(addr_fd, addr_buf, 2) == 2); > + addr_buf[2] = 0; > + addr_bytes = (uint8_t)(strtol(addr_buf, 0, 16)); > + ((struct virtio_net_config *)(vqdev->cfg))->mac[i] = addr_bytes; > + ((struct virtio_net_config *)(vqdev->cfg_d))->mac[i] = > addr_bytes; > + } > + > + snprintf(clone_path, sizeof(clone_path), "/net/ether%d/clone", nic); > + ctlfd = open(clone_path, O_RDWR); > + if (ctlfd < 0) > + VIRTIO_DEV_ERRX(vqdev, "%s", clone_path); > + > + do { > + num_read = read(ctlfd, buf + total_read, sizeof(buf) - > total_read); > + total_read += num_read; > + } while(num_read > 0); > + > + etherfd = strtol(buf, 0, 10); > + if (etherfd < 0) > + VIRTIO_DEV_ERRX(vqdev, "bad etherfd %d (%s)", etherfd, buf); > + > + snprintf(data_path, sizeof(data_path), > + "/net/ether%d/%d/data", nic, etherfd); > + > + if (write(ctlfd, type, sizeof(type)) != sizeof(type)) > + VIRTIO_DEV_ERRX(vqdev, "write to ctlfd failed"); > +} > + > +/* net_receiveq_fn receives packets for the guest thoeugh the virtio > networking > + * device and the _vq virtio queue. > + */ > +void net_receiveq_fn(void *_vq) > +{ > + struct virtio_vq *vq = _vq; > + uint32_t head; > + uint32_t olen, ilen; > + int num_read; > + struct iovec *iov; > + struct virtio_mmio_dev *dev = vq->vqdev->transport_dev; > + int fd; > + struct virtio_net_hdr_v1 *net_header; > + > + fd = open(data_path, O_RDWR); > + if (fd == -1) > + VIRTIO_DEV_ERRX(vq->vqdev, "Could not open data file for > ether1."); > + > + if (!vq) > + VIRTIO_DEV_ERRX(vq->vqdev, > + "\n %s:%d\n" > + " Virtio device: (not sure which one): Error, device > behavior.\n" > + " The device must provide a valid virtio_vq as an > argument to %s." > + , __FILE__, __LINE__, __func__); > + > + if (vq->qready == 0x0) > + VIRTIO_DEV_ERRX(vq->vqdev, > + "The service function for queue '%s' was launched > before the driver set QueueReady to 0x1.", > + vq->name); > + > + iov = malloc(vq->qnum_max * sizeof(struct iovec)); > + assert(iov != NULL); > + > + if (!dev->poke_guest) { > + free(iov); > + VIRTIO_DEV_ERRX(vq->vqdev, > + "The 'poke_guest' function pointer was not > set."); > + } > + > + for (;;) { > + head = virtio_next_avail_vq_desc(vq, iov, &olen, &ilen); > + if (olen) { > + free(iov); > + VIRTIO_DRI_ERRX(vq->vqdev, > + "The driver placed a device-readable buffer in > the console device's receiveq.\n" > + " See virtio-v1.0-cs04 s5.3.6.1 Device > Operation"); > + } > + > + /* For receive the virtio header is in iov[0], so we only want > + * the packet to be read into iov[1] and above. > + */ > + num_read = readv(fd, iov + 1, ilen - 1); > + if (num_read < 0) { > + free(iov); > + VIRTIO_DEV_ERRX(vq->vqdev, > + "Encountered an error trying to read input from > the ethernet device."); > + } > + > + /* See virtio spec virtio-v1.0-cs04 s5.1.6.3.2 Device > Requirments: > + * Setting Up Receive Buffers > + * > + * VIRTIO_NET_F_MRG_RXBUF is not currently negotiated. > + * num_buffers will always be 1 if VIRTIO_NET_F_MRG_RXBUF is not > + * negotiated. > + */ > + net_header = iov[0].iov_base; > + net_header->num_buffers = 1; > + virtio_add_used_desc(vq, head, num_read + VIRTIO_HEADER_SIZE); > + > + virtio_mmio_set_vring_irq(dev); > + dev->poke_guest(dev->vec); > + } > +} > + > +/* net_transmitq_fn transmits packets from the guest through the virtio > + * networking device through the _vq virtio queue. > + */ > +void net_transmitq_fn(void *_vq) > +{ > + struct virtio_vq *vq = _vq; > + uint32_t head; > + uint32_t olen, ilen; > + struct iovec *iov; > + struct virtio_mmio_dev *dev = vq->vqdev->transport_dev; > + void *stripped; > + int fd = open(data_path, O_RDWR); > + if (fd == -1) > + VIRTIO_DEV_ERRX(vq->vqdev, "Could not open data file for > ether1."); > + > + iov = malloc(vq->qnum_max * sizeof(struct iovec)); > + assert(iov != NULL); > + > + if (!dev->poke_guest) { > + free(iov); > + VIRTIO_DEV_ERRX(vq->vqdev, > + "The 'poke_guest' function pointer was not > set."); > + } > + > + for (;;) { > + head = virtio_next_avail_vq_desc(vq, iov, &olen, &ilen); > + > + if (ilen) { > + free(iov); > + VIRTIO_DRI_ERRX(vq->vqdev, > + "The driver placed a device-writeable > buffer in the network device's transmitq.\n" > + " See virtio-v1.0-cs04 s5.3.6.1 Device > Operation"); > + } > + > + /* Strip off the virtio header (the first 12 bytes), as it is > + * not a part of the actual ethernet frame. > + */ > + for (int i = 0; i < olen; i++) { > + stripped = iov[i].iov_base + VIRTIO_HEADER_SIZE; > + assert(write(fd, stripped, iov[i].iov_len - > VIRTIO_HEADER_SIZE) == iov[i].iov_len - VIRTIO_HEADER_SIZE); > + } > + > + virtio_add_used_desc(vq, head, 0); > + > + virtio_mmio_set_vring_irq(dev); > + dev->poke_guest(dev->vec); > + } > +} -- You received this message because you are subscribed to the Google Groups "Akaros" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. For more options, visit https://groups.google.com/d/optout.
