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.

Reply via email to