Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


minor fix to virtio VNET device to make it compilable
[palacios.git] / palacios / src / devices / lnx_virtio_vnet.c
index 215e664..7b6d75c 100644 (file)
@@ -13,7 +13,7 @@
  * All rights reserved.
  *
  * Author: Jack Lange <jarusl@cs.northwestern.edu>
- *            Lei Xia <lxia@cs.northwestern.edu>
+ *             Lei Xia <lxia@cs.northwestern.edu>
  *
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
 #include <palacios/vmm_dev_mgr.h>
 #include <palacios/vm_guest_mem.h>
 #include <devices/lnx_virtio_pci.h>
-#include <palacios/vmm_vnet.h>
+#include <vnet/vnet.h>
 #include <palacios/vmm_sprintf.h>
 #include <devices/pci.h>
 
 
-#ifndef CONFIG_DEBUG_LINUX_VIRTIO_VNET
+#ifndef V3_CONFIG_DEBUG_LINUX_VIRTIO_VNET
 #undef PrintDebug
 #define PrintDebug(fmt, args...)
 #endif
@@ -75,7 +75,6 @@ struct virtio_vnet_state {
 #define VNET_ADD_LINK 21
 #define VNET_DEL_LINK 22
 
-// structure of the vnet command header
 struct vnet_ctrl_hdr {
     uint8_t cmd_type;
     uint32_t num_cmds;
@@ -123,9 +122,8 @@ static int get_desc_count(struct virtio_queue * q, int index) {
 }
 
 
-
-
-static int handle_cmd_kick(struct guest_info * core, struct virtio_vnet_state * vnet_state) {
+static int handle_cmd_kick(struct guest_info * core, 
+                          struct virtio_vnet_state * vnet_state) {
     struct virtio_queue * q = &(vnet_state->queue[0]);
     
     PrintDebug("VNET Bridge: Handling command  queue\n");
@@ -142,7 +140,6 @@ static int handle_cmd_kick(struct guest_info * core, struct virtio_vnet_state *
        uint8_t * status_ptr = NULL;
        uint8_t status = 0;
 
-
        PrintDebug("VNET Bridge: CMD: Descriptor Count=%d, index=%d, desc_idx=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE, desc_idx);
 
        if (desc_cnt < 3) {
@@ -159,8 +156,7 @@ static int handle_cmd_kick(struct guest_info * core, struct virtio_vnet_state *
 
        desc_idx = hdr_desc->next;
        
-       if (hdr->cmd_type == VNET_ADD_ROUTE) {
-           
+       if (hdr->cmd_type == VNET_ADD_ROUTE) {   
            for (i = 0; i < hdr->num_cmds; i++) {
                uint8_t tmp_status = 0;
                struct v3_vnet_route * route = NULL;
@@ -172,26 +168,21 @@ static int handle_cmd_kick(struct guest_info * core, struct virtio_vnet_state *
                    return -1;
                }
 
-               // add route
-               PrintDebug("VNET Bridge: Adding VNET Route\n");
-
                tmp_status = v3_vnet_add_route(*route);
-
-               PrintDebug("VNET Route Added\n");
-
                if (tmp_status != 0) {
                    PrintError("Error adding VNET ROUTE\n");
+                       
                    status = tmp_status;
                }
 
+               PrintDebug("VNET Route Added\n");
+
                xfer_len += buf_desc->length;
                desc_idx = buf_desc->next;
            }
 
        } 
 
-
-
        status_desc = &(q->desc[desc_idx]);
 
        if (v3_gpa_to_hva(core, status_desc->addr_gpa, (addr_t *)&status_ptr) == -1) {
@@ -222,63 +213,48 @@ static int handle_cmd_kick(struct guest_info * core, struct virtio_vnet_state *
 }
 
 
-static int vnet_pkt_input_cb(struct v3_vm_info * vm,  struct v3_vnet_pkt vnet_pkts[], uint16_t pkt_num, void * private_data){
+static int vnet_pkt_input_cb(struct v3_vm_info * vm,  
+                            struct v3_vnet_pkt * pkt, 
+                            void * private_data){
     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
     struct virtio_queue * q = &(vnet_state->queue[RECV_QUEUE]);
     int ret_val = -1;
     unsigned long flags;
-    uint16_t sent;
-    struct v3_vnet_pkt *pkt;
-
-    if(pkt_num <= 0)
-       return 0;
 
     flags = v3_lock_irqsave(vnet_state->lock);
        
     if (q->ring_avail_addr == 0) {
        PrintError("Queue is not set\n");
+       
        goto exit;
     }
 
-    PrintDebug("VNET Bridge: RX: running on cpu: %d, num of pkts: %d\n", V3_Get_CPU(), pkt_num);
-
-    for(sent = 0; sent < pkt_num; sent ++) {
-       pkt = &vnet_pkts[sent];
-       vnet_state->pkt_recv ++;
-
-       if (q->cur_avail_idx != q->avail->index) {
-           uint16_t pkt_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
-           struct vring_desc * pkt_desc = NULL;
-           struct vnet_bridge_pkt * virtio_pkt = NULL;
+    if (q->cur_avail_idx != q->avail->index) {
+       uint16_t pkt_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
+       struct vring_desc * pkt_desc = NULL;
+       struct vnet_bridge_pkt * virtio_pkt = NULL;
 
-           pkt_desc = &(q->desc[pkt_idx]);
-           PrintDebug("VNET Bridge RX: buffer desc len: %d\n", pkt_desc->length);
+       pkt_desc = &(q->desc[pkt_idx]);
 
-           if (v3_gpa_to_hva(&(vm->cores[0]), pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
-               PrintError("Could not translate buffer address\n");
-               goto exit;
-           }
+       if (v3_gpa_to_hva(&(vm->cores[0]), pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
+           PrintError("Could not translate buffer address\n");
+           goto exit;
+       }
 
-           PrintDebug("VNET Bridge: RX: pkt sent to guest pkt size: %d, dst link: %d\n", pkt->size, pkt->dst_id);
+       PrintDebug("VNET Bridge: RX: pkt sent to guest pkt size: %d, dst link: %d\n", pkt->size, pkt->dst_id);
 
-           // Fill in dst packet buffer
-           virtio_pkt->link_id = pkt->dst_id;
-           virtio_pkt->pkt_size = pkt->size;
-           memcpy(virtio_pkt->pkt, pkt->data, pkt->size);
+       // Fill in dst packet buffer
+       virtio_pkt->link_id = pkt->dst_id;
+       virtio_pkt->pkt_size = pkt->size;
+       memcpy(virtio_pkt->pkt, pkt->data, pkt->size);
        
-           q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
-           q->used->ring[q->used->index % q->queue_size].length = sizeof(struct vnet_bridge_pkt); 
-
-           q->used->index++;
-           q->cur_avail_idx++;
-       } else {
-           vnet_state->pkt_drop ++;
-           v3_vnet_disable_bridge();
-       }
-    }
+       q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
+       q->used->ring[q->used->index % q->queue_size].length = sizeof(struct vnet_bridge_pkt); 
 
-    if(sent == 0){
-       goto exit;
+       q->used->index++;
+       q->cur_avail_idx++;
+    } else {
+       vnet_state->pkt_drop ++;
     }
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
@@ -288,19 +264,7 @@ static int vnet_pkt_input_cb(struct v3_vm_info * vm,  struct v3_vnet_pkt vnet_pk
     }
 
     ret_val = 0;
-
        
-#ifdef CONFIG_VNET_PROFILE
-    if (vnet_state->pkt_recv % 200000 == 0)
-       PrintError("Vnet Bridge: sent: %ld, rxed: %ld, dropped: %ld, total exit: %ld, tx exit: %ld, rx exit: %ld\n",
-                       vnet_state->pkt_sent,
-                       vnet_state->pkt_recv,
-                       vnet_state->pkt_drop, 
-                       vnet_state->total_exit,
-                       vnet_state->tx_exit,
-                       vnet_state->rx_exit);
-#endif
-
 exit:
 
     v3_unlock_irqrestore(vnet_state->lock, flags);
@@ -308,22 +272,14 @@ exit:
     return ret_val;
 }
 
-static void vnet_pkt_input_xcall(void *data){
-    struct v3_vnet_bridge_input_args *args = (struct v3_vnet_bridge_input_args *)data;
-       
-    vnet_pkt_input_cb(args->vm, args->vnet_pkts, args->pkt_num, args->private_data);
-}
-
-static int handle_pkt_kick(struct guest_info *core, struct virtio_vnet_state * vnet_state) 
+static int do_tx_pkts(struct guest_info * core, 
+                          struct virtio_vnet_state * vnet_state) 
 {
     struct virtio_queue * q = &(vnet_state->queue[XMIT_QUEUE]);
-    unsigned long flags = 0;
     int recvd = 0;
        
-    flags = v3_lock_irqsave(vnet_state->lock);
-
     if (q->ring_avail_addr == 0) {
-       goto exit;
+       return -1;
     }
 
     while (q->cur_avail_idx != q->avail->index) {
@@ -332,18 +288,23 @@ static int handle_pkt_kick(struct guest_info *core, struct virtio_vnet_state * v
        struct vnet_bridge_pkt * virtio_pkt = NULL;
 
        pkt_desc = &(q->desc[desc_idx]);
-
-       PrintDebug("VNET Bridge: Handle TX desc buf_len: %d\n", pkt_desc->length);
        
        if (v3_gpa_to_hva(core, pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
            PrintError("Could not translate buffer address\n");
            return -1;
        }
 
-       PrintDebug("VNET Bridge: TX: on cpu %d pkt size: %d, dst link: %d\n", cpu, virtio_pkt->pkt_size, virtio_pkt->link_id);
-       
-       v3_vnet_rx(virtio_pkt->pkt, virtio_pkt->pkt_size, virtio_pkt->link_id, LINK_EDGE);
+       //PrintDebug("VNET Bridge: TX: on cpu %d pkt size: %d, dst link: %d\n", cpu, virtio_pkt->pkt_size, virtio_pkt->link_id);
+
+       struct v3_vnet_pkt pkt;
+       pkt.size = virtio_pkt->pkt_size;
+       pkt.src_type = LINK_EDGE;
+       pkt.src_id = 0;
+       memcpy(pkt.header, virtio_pkt->pkt, ETHERNET_HEADER_LEN);
+       pkt.data = virtio_pkt->pkt;
 
+       v3_vnet_send_pkt(&pkt, NULL);
+       
        q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
        q->used->ring[q->used->index % q->queue_size].length = pkt_desc->length; // What do we set this to????
        q->used->index++;
@@ -355,68 +316,41 @@ static int handle_pkt_kick(struct guest_info *core, struct virtio_vnet_state * v
     }
 
     if(recvd == 0){
-       goto exit;
-    }
-
-    //PrintError("In polling get %d\n", recvd);
-       
-    //if on the dom0 core, interrupt the domU core to poll pkts
-    //otherwise, call the polling directly
-    int cpu = V3_Get_CPU();
-    if(vnet_state->vm->cores[0].cpu_id == cpu){
-       cpu = (cpu == 0)?1:0;
-       v3_interrupt_cpu(vnet_state->vm, cpu, V3_VNET_POLLING_VECTOR);
-    }else{
-       v3_vnet_polling();
+       return 0;
     }
 
-    if((vnet_state->pkt_sent % (QUEUE_SIZE/20)) == 0) { //optimized for guest's, batch the interrupts
-           if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
-               v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
-               vnet_state->virtio_cfg.pci_isr = 0x1;
-           }
+    if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
+           v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
+           vnet_state->virtio_cfg.pci_isr = 0x1;
     }
-
-#ifdef CONFIG_VNET_PROFILE
-    if (vnet_state->pkt_sent % 200000 == 0)
-       PrintError("Vnet Bridge: sent: %ld, rxed: %ld, dropped: %ld, total exit: %ld, tx exit: %ld, rx exit: %ld\n",
-                       vnet_state->pkt_sent,
-                       vnet_state->pkt_recv,
-                       vnet_state->pkt_drop, 
-                       vnet_state->total_exit,
-                       vnet_state->tx_exit,
-                       vnet_state->rx_exit);
-#endif
-
-exit:
-    v3_unlock_irqrestore(vnet_state->lock,flags);
-
+       
     return 0;
 }
 
-static int polling_pkt_from_guest(struct v3_vm_info * vm, void *private_data){
+static void vnet_virtio_poll(struct v3_vm_info * vm, void * private_data){
     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
-       
-    return handle_pkt_kick(&(vm->cores[0]), vnet_state);
+
+    if(vm == vnet_state->vm){  
+       do_tx_pkts(&(vm->cores[0]), vnet_state);
+    }
 }
 
-static int handle_rx_kick(struct guest_info *core, struct virtio_vnet_state * vnet_state) 
-{
-    v3_vnet_enable_bridge();
-       
+static int handle_rx_queue_kick(struct guest_info *core, 
+                         struct virtio_vnet_state * vnet_state) 
+{      
     return 0;
 }
 
-static int vnet_virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
+static int vnet_virtio_io_write(struct guest_info * core, 
+                               uint16_t port, void * src, 
+                               uint_t length, void * private_data) {
     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
     int port_idx = port % vnet_state->io_range_size;
 
     PrintDebug("VNET Bridge: VIRTIO VNET Write for port %d len=%d, value=%x\n", 
               port, length, *(uint32_t *)src);
-    PrintDebug("VNET Bridge: port idx=%d\n", port_idx);
 
     vnet_state->total_exit ++;
-
     switch (port_idx) {
        case GUEST_FEATURES_PORT:
            if (length != 4) {
@@ -467,13 +401,14 @@ static int vnet_virtio_io_write(struct guest_info * core, uint16_t port, void *
 
                if(vnet_state->queue[RECV_QUEUE].avail != NULL){
                    vnet_state->ready = 1;
+                   vnet_state->queue[RECV_QUEUE].used->flags |= VRING_NO_NOTIFY_FLAG;
                }
 
                //No notify when there is pkt tx from guest
+               //palacios will do the polling
                if(vnet_state->queue[XMIT_QUEUE].used != NULL){
                    vnet_state->queue[XMIT_QUEUE].used->flags |= VRING_NO_NOTIFY_FLAG;
                }
-               
            } else {
                PrintError("Illegal write length for page frame number\n");
                return -1;
@@ -502,14 +437,13 @@ static int vnet_virtio_io_write(struct guest_info * core, uint16_t port, void *
                    return -1;
                }
            } else if (queue_idx == 1) {
-               if (handle_pkt_kick(core, vnet_state) == -1){
+               if (do_tx_pkts(core, vnet_state) == -1){
                    PrintError("Could not handle Virtio VNET TX\n");
                    return -1;
                }
-               vnet_state->tx_exit ++;
-               //PrintError("Notify on TX\n");
+               PrintError("Notify on TX\n");
            } else if (queue_idx == 2) {
-               if (handle_rx_kick(core, vnet_state) == -1){
+               if (handle_rx_queue_kick(core, vnet_state) == -1){
                    PrintError("Could not handle Virtio RX buffer refills Kick\n");
                    return -1;
                }
@@ -543,7 +477,9 @@ static int vnet_virtio_io_write(struct guest_info * core, uint16_t port, void *
 }
 
 
-static int vnet_virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
+static int vnet_virtio_io_read(struct guest_info * core, 
+                              uint16_t port, void * dst, 
+                              uint_t length, void * private_data) {
 
     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
     int port_idx = port % vnet_state->io_range_size;
@@ -612,12 +548,17 @@ static int vnet_virtio_io_read(struct guest_info * core, uint16_t port, void * d
 }
 
 
+static int virtio_free(struct virtio_vnet_state * vnet_state) {
+
+    // unregister from PCI
+
+    V3_Free(vnet_state);
+    return 0;
+}
+
 
 static struct v3_device_ops dev_ops = {
-    .free = NULL,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+    .free = (int (*)(void *))virtio_free,
 };
 
 static int dev_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
@@ -638,10 +579,11 @@ static int dev_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        
     vnet_state->vm = vm;
 
-    struct vm_device * dev = v3_allocate_device(name, &dev_ops, vnet_state);
+    struct vm_device * dev = v3_add_device(vm, name, &dev_ops, vnet_state);
 
-    if (v3_attach_device(vm, dev) == -1) {
+    if (dev == NULL) {
        PrintError("Could not attach device %s\n", name);
+       V3_Free(vnet_state);
        return -1;
     }
 
@@ -679,12 +621,13 @@ static int dev_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        bars[0].private_data = vnet_state;
 
        pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
-                                        0, PCI_AUTO_DEV_NUM, 0,
+                                        0, 5 /*PCI_AUTO_DEV_NUM*/, 0,
                                         "LNX_VIRTIO_VNET", bars,
                                         NULL, NULL, NULL, vnet_state);
 
        if (!pci_dev) {
            PrintError("Could not register PCI Device\n");
+           v3_remove_device(dev);
            return -1;
        }
        
@@ -704,9 +647,13 @@ static int dev_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     virtio_reset(vnet_state);
 
+    struct v3_vnet_bridge_ops brg_ops;
+    brg_ops.input = vnet_pkt_input_cb;
+    brg_ops.poll = vnet_virtio_poll;
+
     V3_Print("Registering Virtio device as vnet bridge\n");
-    v3_vnet_add_bridge(vm, vnet_pkt_input_cb, vnet_pkt_input_xcall, polling_pkt_from_guest, 0, 500000, (void *)vnet_state);
 
+    v3_vnet_add_bridge(vm, &brg_ops, CTL_VM_BRIDGE, (void *)vnet_state);
 
     return 0;
 }