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.


Fix a virtio ring buffer free run index overflow bug
Lei Xia [Mon, 8 Feb 2010 00:35:29 +0000 (18:35 -0600)]
palacios/include/devices/lnx_virtio_pci.h
palacios/src/devices/lnx_virtio_nic.c
palacios/src/palacios/vmm_vnet.c

index 1131feb..5ecf694 100644 (file)
@@ -128,6 +128,8 @@ struct virtio_queue {
     uint16_t queue_size;
   
     uint16_t cur_avail_idx;
+    uint16_t last_avail_idx;
+    bool idx_overflow;
 
     addr_t ring_desc_addr;
     addr_t ring_avail_addr;
index 4874b73..ea998af 100644 (file)
@@ -7,14 +7,12 @@
  * and the University of New Mexico.  You can find out more at 
  * http://www.v3vee.org
  *
- * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
  * Copyright (c) 2008, Lei Xia <lxia@northwestern.edu>
  * Copyright (c) 2008, Cui Zheng <cuizheng@cs.unm.edu>
  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
  * All rights reserved.
  *
- * Author: Jack Lange <jarusl@cs.northwestern.edu>
- *               Lei Xia <lxia@northwestern.edu>
+ * Author: Lei Xia <lxia@northwestern.edu>
  *             Cui Zheng <cuizheng@cs.unm.edu>
  *              
  *
@@ -37,6 +35,8 @@
 #define PrintDebug(fmt, args...)
 #endif
 
+//#define VIRTIO_NIC_PROFILE
+
 /* The feature bitmap for virtio net */
 #define VIRTIO_NET_F_CSUM      0       /* Host handles pkts w/ partial csum */
 #define VIRTIO_NET_F_GUEST_CSUM        1       /* Guest handles pkts w/ partial csum */
@@ -74,7 +74,7 @@ struct virtio_net_hdr {
 }__attribute__((packed));
 
        
-#define QUEUE_SIZE 1024
+#define QUEUE_SIZE 4096
 #define CTRL_QUEUE_SIZE 64
 #define ETH_ALEN 6
 
@@ -106,6 +106,8 @@ struct virtio_net_state {
     void * backend_data;
     struct virtio_dev_state * virtio_dev;
     struct list_head dev_link;
+
+    ulong_t pkt_sent, pkt_recv, pkt_drop;
 };
 
 
@@ -254,12 +256,11 @@ static int send_pkt_to_guest(struct virtio_net_state * virtio, uchar_t * buf, ui
     uint32_t hdr_len = sizeof(struct virtio_net_hdr);
     uint32_t data_len = size;
     uint32_t offset = 0;
+       
+    PrintDebug("VIRTIO NIC:  sending packet to virtio nic %p, size:%d", virtio, size);
 
-    //PrintDebug("VIRTIO NIC:  Handle RX: cur_index=%d (mod=%d), avail_index=%d\n", 
-              //q->cur_avail_idx, q->cur_avail_idx % q->queue_size, q->avail->index);
-
-    PrintError("VIRTIO NIC:  sending packet to net_state %p, size:%d", virtio, size);
-
+    virtio->pkt_recv ++;
+       
     if (!raw) {
        data_len -= hdr_len;
     }
@@ -272,67 +273,66 @@ static int send_pkt_to_guest(struct virtio_net_state * virtio, uchar_t * buf, ui
        return -1;
     }
 
-    if (q->cur_avail_idx < q->avail->index) {
+    if (q->last_avail_idx > q->avail->index)
+       q->idx_overflow = true;
+    q->last_avail_idx = q->avail->index;
+
+    if (q->cur_avail_idx < q->avail->index || (q->idx_overflow && q->cur_avail_idx < q->avail->index+65536)){
        addr_t hdr_addr = 0;
        uint16_t hdr_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
        uint16_t buf_idx = 0;
        struct vring_desc * hdr_desc = NULL;
 
-       //PrintDebug("Descriptor index=%d\n", q->cur_avail_idx % q->queue_size);
-
        hdr_desc = &(q->desc[hdr_idx]);
-
-       //PrintDebug("Header Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", hdr_desc, 
-                  //(void *)(hdr_desc->addr_gpa), hdr_desc->length, hdr_desc->flags, hdr_desc->next);  
-
        if (guest_pa_to_host_va(virtio->virtio_dev->vm, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
            PrintError("Could not translate receive buffer address\n");
            return -1;
        }
 
-       //copy header to the header descriptor
        memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr));
 
-       //Zheng 01/02/2010: zero payload
        if (offset >= data_len) {
            hdr_desc->flags &= ~VIRTIO_NEXT_FLAG;
        }
 
-       //copy data to the next descriptors
-       //Zheng 01/02/2010: put data into the next descriptor, rather than 0! 
        for (buf_idx = hdr_desc->next; offset < data_len; buf_idx = q->desc[hdr_idx].next) {
-       //      for (buf_idx = 0; offset < data_len; buf_idx = q->desc[hdr_idx].next) {
            struct vring_desc * buf_desc = &(q->desc[buf_idx]);
            uint32_t len = 0;
 
-           //Zheng 01/02/2010: commented this - we need to check 
-           //       if there still is some data left
-           //buf_desc->flags = VIRTIO_NEXT_FLAG;
-        
-           //PrintError("JACK: copying packet to up desc (len = %d)\n", data_len - offset);
-           //v3_hexdump(buf + offset, data_len - offset, NULL, 0);
-
            len = copy_data_to_desc(virtio, buf_desc, buf + offset, data_len - offset);
            
            offset += len;
 
-           //Zheng 01/02/2010: check if there still is some data left 
            if (offset < data_len) {
                buf_desc->flags = VIRTIO_NEXT_FLAG;             
            }
 
            buf_desc->length = len;  // TODO: do we need this?
-           //PrintError("JACK: setting buffer descriptor length to %d)\n", buf_desc->length);
        }
-
        
        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 = data_len + hdr_len; // This should be the total length of data sent to guest (header+pkt_data)
 
        q->used->index++;
+
+       int last_idx = q->cur_avail_idx;
        q->cur_avail_idx++;
+       if (q->cur_avail_idx < last_idx)
+           q->idx_overflow = false;
+    } else {
+       virtio->pkt_drop++;
+       
+#ifdef VIRTIO_NIC_PROFILE
+       PrintError("Virtio NIC: %p, one pkt dropped receieved: %ld, dropped: %ld, sent: %ld curidx: %d, avaiIdx: %d\n", virtio, virtio->pkt_recv, virtio->pkt_drop, virtio->pkt_sent, q->cur_avail_idx, q->avail->index);
+#endif
     }
 
+#ifdef VIRTIO_NIC_PROFILE
+    if ((virtio->pkt_recv % 10000) == 0){
+       PrintError("Virtio NIC: %p, receieved: %ld, dropped: %ld, sent: %ld curidx: %d, avaiIdx: %d\n", virtio, virtio->pkt_recv, virtio->pkt_drop, virtio->pkt_sent, q->cur_avail_idx, q->avail->index);
+    }
+#endif
+
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
        v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
@@ -381,15 +381,21 @@ static int handle_ctrl(struct virtio_net_state * dev) {
 //get packet from guest
 static int handle_pkt_tx(struct virtio_net_state * virtio_state) 
 {
-    //struct virtio_net_state *virtio = (struct virtio_net_state *)dev->private_data;    
     struct virtio_queue * q = &(virtio_state->tx_vq);
+    struct virtio_net_hdr * hdr = NULL;
 
-    //PrintDebug("VIRTIO NIC pkt_tx: cur_index=%d (mod=%d), avail_index=%d\n", 
-             // q->cur_avail_idx, q->cur_avail_idx % q->queue_size, q->avail->index);
+    virtio_state->pkt_sent ++;
 
-    struct virtio_net_hdr * hdr = NULL;
+    if (q->avail->index < q->last_avail_idx)
+       q->idx_overflow = true;
+    q->last_avail_idx = q->avail->index;
+
+#ifdef VIRTIO_NIC_PROFILE
+    if(virtio_state->pkt_sent % 10000 == 0)
+       PrintError("Virtio NIC: %p, pkt_sent: %ld curidx: %d, avaiIdx: %d\n", virtio_state, virtio_state->pkt_sent, q->cur_avail_idx, q->avail->index);
+#endif 
 
-    while (q->cur_avail_idx < q->avail->index) {
+    while (q->cur_avail_idx < q->avail->index ||(q->idx_overflow && q->cur_avail_idx < (q->avail->index + 65536))) {
        struct vring_desc * hdr_desc = NULL;
        addr_t hdr_addr = 0;
        uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
@@ -397,30 +403,17 @@ static int handle_pkt_tx(struct virtio_net_state * virtio_state)
        uint32_t req_len = 0;
        int i = 0;
 
-       //PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % q->queue_size);
-
        hdr_desc = &(q->desc[desc_idx]);
-
-       //PrintDebug("Header Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", hdr_desc, 
-                  //(void *)(hdr_desc->addr_gpa), hdr_desc->length, hdr_desc->flags, hdr_desc->next);  
-
        if (guest_pa_to_host_va(virtio_state->virtio_dev->vm, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
            PrintError("Could not translate block header address\n");
            return -1;
        }
 
        hdr = (struct virtio_net_hdr*)hdr_addr;
-       
-       //PrintDebug("NIC Op Hdr (ptr=%p) header len =%x\n", (void *)hdr_addr, (int)hdr->hdr_len);
-
        desc_idx = hdr_desc->next;
        
        for (i = 0; i < desc_cnt - 1; i++) {    
            struct vring_desc * buf_desc = &(q->desc[desc_idx]);
-
-           //PrintDebug("Buffer Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", buf_desc, 
-                      //(void *)(buf_desc->addr_gpa), buf_desc->length, buf_desc->flags, buf_desc->next);
-
            if (pkt_write(virtio_state, buf_desc) == -1) {
                PrintError("Error handling nic operation\n");
                return -1;
@@ -434,11 +427,14 @@ static int handle_pkt_tx(struct virtio_net_state * virtio_state)
        q->used->ring[q->used->index % q->queue_size].length = req_len; // What do we set this to????
 
        q->used->index++;
-       q->cur_avail_idx++;
+
+       int last_idx = q->cur_avail_idx;
+       q->cur_avail_idx ++;
+       if (q->cur_avail_idx < last_idx)
+           q->idx_overflow = false;
     }
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
-       //PrintDebug("Raising IRQ %d\n",  virtio_state->pci_dev->config_header.intr_line);
        v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 0, virtio_state->pci_dev);
        virtio_state->virtio_cfg.pci_isr = 0x1;
     }
@@ -777,6 +773,7 @@ static int register_dev(struct virtio_dev_state * virtio, struct virtio_net_stat
     net_state->ctrl_vq.queue_size = CTRL_QUEUE_SIZE;
 
     net_state->virtio_dev = virtio;
+    net_state->pkt_sent = net_state->pkt_recv = net_state->pkt_drop = 0;
 
     virtio_reset(net_state);
 
index d2daa7e..188f730 100644 (file)
@@ -8,16 +8,14 @@
  * http://www.v3vee.org
  *
  * Copyright (c) 2009, Lei Xia <lxia@northwestern.edu> 
- * Copyright (c) 2009, Yuan Tang <ytang@northwestern.edu> 
- * Copyright (c) 2009, Jack Lange <jarusl@cs.northwestern.edu> 
- * Copyright (c) 2009, Peter Dinda <pdinda@northwestern.edu>
+ * Copyright (c) 2009, Yuan Tang <ytang@northwestern.edu>  
+ * Copyright (c) 2009, Zheng Cui <czheng@unm.edu>
  * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org> 
  * All rights reserved.
  *
  * Author: Lei Xia <lxia@northwestern.edu>
  *        Yuan Tang <ytang@northwestern.edu>
- *        Jack Lange <jarusl@cs.northwestern.edu> 
- *        Peter Dinda <pdinda@northwestern.edu
+ *       Zheng Cui <czheng@unm.edu>
  *
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
@@ -216,6 +214,7 @@ static int look_into_cache(route_hashkey_t hashkey, int * matches) {
     return n_matches;
 }
 
+
 #ifdef CONFIG_DEBUG_VNET
 
 static void print_packet(uchar_t *pkt, int size) {
@@ -276,6 +275,43 @@ static void dump_routes(struct routing_entry **route_tables) {
     PrintDebug("\nVnet: route table dump end =====\n");
 }
 
+static void dump_dom0_routes(struct routing_entry routes[], int size) {
+    char dest_str[18];
+    char src_str[18];
+    struct routing_entry *route = NULL;
+    int i;
+
+    PrintDebug("\nVnet: route table from dom0 guest =====\n");
+
+    for(i = 0; i <size; i++) {
+        route = &routes[i];
+        mac_to_string(route->src_mac, src_str);  
+        mac_to_string(route->dest_mac, dest_str);
+        PrintDebug("route: %d\n", i);
+        PrintDebug("SRC(%s), DEST(%s), src_mac_qual(%d), dst_mac_qual(%d)\n", src_str, dest_str, route->src_mac_qual, route->dest_mac_qual);
+        PrintDebug("Src_Link(%d), src_type(%d), dst_link(%d), dst_type(%d)\n\n", route->src_link_idx, route->src_type, route->link_idx, route->link_type);
+    }
+
+    PrintDebug("\nVnet: route table dom0 guest end =====\n");
+}
+
+static void dump_dom0_links(struct vnet_if_link links[], int size) {
+    struct vnet_if_link *link = NULL;
+    int i;
+
+    PrintDebug("\nVnet: link table from dom0 guest =====\n");
+
+    for(i = 0; i <size; i++) {
+        link = &links[i];
+        PrintDebug("link: %d\n", i);
+        PrintDebug("dest_ip(%ld), dst_port(%d), prot_type(%d)\n", link->dest_ip, link->dest_port, link->pro_type);
+        PrintDebug("vnet_header:\n");
+        v3_hexdump(&link->vnet_header, sizeof(struct udp_link_header), NULL, 0);
+    }
+
+    PrintDebug("\nVnet: link table dom0 guest end =====\n");
+}
+
 #endif
 
 static int __add_link_entry(struct link_entry * link) {
@@ -659,12 +695,12 @@ static int send_ethernet_pkt(uchar_t *data, int len) {
     struct ethernet_pkt *pkt;
 
     pkt = (struct ethernet_pkt *)V3_Malloc(sizeof(struct ethernet_pkt));
-    memset(pkt, 0, sizeof(struct ethernet_pkt));
-
+   
     if(pkt == NULL){
         PrintError("VNET: Memory allocate fails\n");
         return -1;
     }
+    memset(pkt, 0, sizeof(struct ethernet_pkt));
        
     ethernet_packet_init(pkt, data, len);  //====here we copy sending data once 
        
@@ -929,43 +965,47 @@ static int addto_routing_link_tables(struct routing_entry *route_tab,
     return 0;
 }
 
-struct table_init_info {
-    addr_t routing_table_start;
-    uint16_t routing_table_size;
-    addr_t link_table_start;
-    uint16_t link_table_size;
-};
-
 //add the guest specified routes and links to the tables
 static int handle_init_tables_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
-    addr_t guest_addr = (addr_t)info->vm_regs.rcx;
-    addr_t info_addr, route_addr, link_addr;
-    struct table_init_info *init_info;
-    struct link_entry *link_array;
-    struct routing_entry *route_array;   
+    struct vnet_if_link *link_array;
+    struct routing_entry *route_array;
+    addr_t routes_addr, routes_addr_gva;
+    addr_t links_addr, links_addr_gva;
+    uint16_t route_size, link_size;
 
-    PrintDebug("Vnet: In handle_init_tables_hcall\n");
+    routes_addr_gva = (addr_t)info->vm_regs.rbx;
+    route_size = (uint16_t)info->vm_regs.rcx;
+    links_addr_gva  = (addr_t)info->vm_regs.rdx;
+    link_size = (uint16_t)info->vm_regs.rsi;
 
-    if (guest_va_to_host_va(info, guest_addr, &info_addr) == -1) {
+    PrintDebug("Vnet: In handle_init_tables_hcall\n");
+    PrintDebug("Vnet: route_table_start: %x, route size: %d\n", (int)routes_addr_gva, route_size);
+    PrintDebug("Vnet: link_table_start: %x, link size: %d\n", (int)links_addr_gva, link_size);
+       
+    if (guest_va_to_host_va(info, routes_addr_gva, &routes_addr) == -1) {
        PrintError("VNET: Could not translate guest address\n");
        return -1;
     }
-    init_info = (struct table_init_info *)info_addr;
+    route_array = (struct routing_entry *)routes_addr;
 
-    if (guest_va_to_host_va(info, init_info->routing_table_start, &route_addr) == -1) {
-       PrintError("VNET: Could not translate guest address\n");
-       return -1;
-    }
-    route_array = (struct routing_entry *)route_addr;
+#ifdef CONFIG_DEBUG_VNET
+    dump_dom0_routes(route_array, route_size);
+#endif
 
-    if (guest_va_to_host_va(info, init_info->link_table_start, &link_addr) == -1) {
+    if (guest_va_to_host_va(info, links_addr_gva, &links_addr) == -1) {
        PrintError("VNET: Could not translate guest address\n");
        return -1;
     }  
-    link_array = (struct link_entry *)link_addr;
+    link_array = (struct vnet_if_link *)links_addr;
+
+#ifdef CONFIG_DEBUG_VNET
+    dump_dom0_links(link_array, link_size);
+#endif
+
+
+// TODO:
+    if (0)addto_routing_link_tables(route_array, route_size, NULL, 0);
 
-    addto_routing_link_tables(route_array, init_info->routing_table_size, link_array, init_info->link_table_size);
-    
     return 0;
 }