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
[palacios.git] / palacios / src / devices / lnx_virtio_nic.c
index 58e9e58..88d3a59 100644 (file)
@@ -27,6 +27,7 @@
 #include <palacios/vmm_sprintf.h>
 #include <palacios/vmm_vnet.h>
 #include <palacios/vmm_lock.h>
+#include <palacios/vmm_util.h>
 
 #include <devices/pci.h>
 
@@ -36,8 +37,6 @@
 #define PrintDebug(fmt, args...)
 #endif
 
-#define VIRTIO_NIC_PROFILE
-
 #define VIRTIO_NET_S_LINK_UP   1       /* Link is up */
 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
 
@@ -66,7 +65,7 @@ struct virtio_net_config
 struct virtio_dev_state {
     struct vm_device * pci_bus;
     struct list_head dev_list;
-    struct guest_info * vm;
+    struct v3_vm_info *vm;
 };
 
 struct virtio_net_state {
@@ -82,21 +81,16 @@ struct virtio_net_state {
     struct virtio_queue ctrl_vq; //index 2, ctrol info from guest
 
     ulong_t pkt_sent, pkt_recv, pkt_drop;
-    struct gen_queue * inpkt_q;
 
     struct v3_dev_net_ops * net_ops;
 
+    v3_lock_t lock;
+
     void * backend_data;
     struct virtio_dev_state * virtio_dev;
     struct list_head dev_link;
 };
 
-#define ETHERNET_PACKET_LEN 1514
-struct eth_pkt {
-    uint32_t size; //size of data
-    char data[ETHERNET_PACKET_LEN];
-}__attribute__((packed));
-
 static int virtio_free(struct vm_device * dev) 
 {
        
@@ -127,27 +121,28 @@ static int virtio_init_state(struct virtio_net_state * virtio)
     //virtio->virtio_cfg.status = VIRTIO_NET_S_LINK_UP;
     virtio->virtio_cfg.pci_isr = 0;
 
-    virtio->pkt_sent = virtio->pkt_recv = virtio->pkt_drop = 0;
+    if (v3_lock_init(&(virtio->lock)) == -1){
+        PrintError("Virtio NIC: Failure to init lock for net_state\n");
+    }
 
-    virtio->inpkt_q = v3_create_queue();
-    v3_init_queue(virtio->inpkt_q);
+    virtio->pkt_sent = virtio->pkt_recv = virtio->pkt_drop = 0;
 
     return 0;
 }
 
-static int pkt_tx(struct virtio_net_state * virtio, struct vring_desc * buf_desc) 
+static int pkt_tx(struct guest_info *core, struct virtio_net_state * virtio, struct vring_desc * buf_desc) 
 {
     uint8_t * buf = NULL;
     uint32_t len = buf_desc->length;
 
-    PrintDebug("Virtio NIC: Handling Virtio Write, net_state: %p\n", virtio);
+    PrintDebug("Virtio NIC: Virtio Pkt Sending, net_state: %p, pkt size: %d\n", virtio, len);
 
-    if (guest_pa_to_host_va(virtio->virtio_dev->vm, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
+    if (guest_pa_to_host_va(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
        PrintError("Could not translate buffer address\n");
        return -1;
     }
 
-    if (virtio->net_ops->send(buf, len, (void *)virtio, NULL) == -1) {
+    if (virtio->net_ops->send(buf, len, virtio->backend_data, NULL) == -1) {
        return -1;
     }
 
@@ -166,12 +161,16 @@ static int build_receive_header(struct virtio_net_hdr * hdr, const void * buf, i
     return 0;
 }
 
-static int copy_data_to_desc(struct virtio_net_state * virtio_state, struct vring_desc * desc, uchar_t * buf, uint_t buf_len) 
+static int copy_data_to_desc(struct guest_info *core, 
+                                       struct virtio_net_state * virtio_state, 
+                                       struct vring_desc * desc, 
+                                       uchar_t * buf, 
+                                       uint_t buf_len) 
 {
     uint32_t len;
     uint8_t * desc_buf = NULL;
 
-    if (guest_pa_to_host_va(virtio_state->virtio_dev->vm, desc->addr_gpa, (addr_t *)&(desc_buf)) == -1) {
+    if (guest_pa_to_host_va(core, desc->addr_gpa, (addr_t *)&(desc_buf)) == -1) {
        PrintError("Could not translate buffer address\n");
        return -1;
     }
@@ -181,119 +180,8 @@ static int copy_data_to_desc(struct virtio_net_state * virtio_state, struct vrin
     return len;
 }
 
-//send data to guest
-int send_pkt_to_guest(struct virtio_net_state * virtio, uchar_t * buf, uint_t size, int raw, void * private_data) 
-{
-    struct virtio_queue * q = &(virtio->rx_vq);
-    struct virtio_net_hdr hdr;
-    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);
-
-    virtio->pkt_recv ++;
-    if (!raw) {
-       data_len -= hdr_len;
-    }
 
-    build_receive_header(&hdr, buf, 1);
 
-    if (q->ring_avail_addr == 0) {
-       PrintError("Queue is not set\n");
-       return -1;
-    }
-
-    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;
-
-       hdr_desc = &(q->desc[hdr_idx]);
-       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;
-       }
-
-       memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr));
-       if (offset >= data_len) {
-           hdr_desc->flags &= ~VIRTIO_NEXT_FLAG;
-       }
-
-       for (buf_idx = hdr_desc->next; offset < data_len; buf_idx = q->desc[hdr_idx].next) {
-           struct vring_desc * buf_desc = &(q->desc[buf_idx]);
-           uint32_t len = 0;
-
-           len = copy_data_to_desc(virtio, buf_desc, buf + offset, data_len - offset);     
-           offset += len;
-           if (offset < data_len) {
-               buf_desc->flags = VIRTIO_NEXT_FLAG;             
-           }
-           buf_desc->length = len;
-       }
-       
-       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
-    }
-
-    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);
-       virtio->virtio_cfg.pci_isr = 0x1;
-    }
-
-#ifdef VIRTIO_NIC_PROFILE
-    if ((virtio->pkt_recv % 10000) == 0){
-       PrintError("Virtio NIC: %p, receieved: %ld, dropped: %ld, sent: %ld\n", 
-               virtio, virtio->pkt_recv, virtio->pkt_drop, virtio->pkt_sent);
-    }
-#endif
-
-    
-    return offset;
-}
-
-static int virtio_sendto_buf(struct virtio_net_state * net_state, uchar_t * buf, uint_t size) {
-    struct eth_pkt *pkt;
-
-    pkt = (struct eth_pkt *)V3_Malloc(sizeof(struct eth_pkt));
-    if(pkt == NULL){
-        PrintError("Virtio NIC: Memory allocate fails\n");
-        return -1;
-    }
-  
-    pkt->size = size;
-    memcpy(pkt->data, buf, size);
-    v3_enqueue(net_state->inpkt_q, (addr_t)pkt);
-       
-    PrintDebug("Virtio NIC: __virtio_sendto_buf: transmitting packet: (size:%d)\n", (int)pkt->size);
-
-    return pkt->size;
-}
-
-int virtio_dev_send(uchar_t * buf, uint32_t size, void *private_data) {
-    struct virtio_net_state *virtio_state = (struct virtio_net_state *)private_data;
-       
-    return virtio_sendto_buf(virtio_state, buf, size);
-}
 
 static int get_desc_count(struct virtio_queue * q, int index) {
     struct vring_desc * tmp_desc = &(q->desc[index]);
@@ -307,21 +195,18 @@ static int get_desc_count(struct virtio_queue * q, int index) {
     return cnt;
 }
 
-static int handle_ctrl(struct virtio_net_state * dev) {
+static int handle_ctrl(struct guest_info *core, struct virtio_net_state * dev) {
     return 0;
 }
 
-static int handle_pkt_tx(struct virtio_net_state * virtio_state) 
+static int handle_pkt_tx(struct guest_info *core, struct virtio_net_state * virtio_state) 
 {
     struct virtio_queue * q = &(virtio_state->tx_vq);
     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;
+    PrintDebug("Virtio NIC: TX: running on cpu: %d\n", V3_Get_CPU());
 
-    while (q->cur_avail_idx < q->avail->index || 
-                (q->idx_overflow && q->cur_avail_idx < (q->avail->index + 65536))) {
+    while (q->cur_avail_idx != q->avail->index) {
        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];
@@ -330,17 +215,17 @@ static int handle_pkt_tx(struct virtio_net_state * virtio_state)
        int i = 0;
 
        hdr_desc = &(q->desc[desc_idx]);
-       if (guest_pa_to_host_va(virtio_state->virtio_dev->vm, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
+       if (guest_pa_to_host_va(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
            PrintError("Could not translate block header address\n");
            return -1;
        }
 
        hdr = (struct virtio_net_hdr*)hdr_addr;
        desc_idx = hdr_desc->next;
-       
+
        for (i = 0; i < desc_cnt - 1; i++) {    
            struct vring_desc * buf_desc = &(q->desc[desc_idx]);
-           if (pkt_tx(virtio_state, buf_desc) == -1) {
+           if (pkt_tx(core, virtio_state, buf_desc) == -1) {
                PrintError("Error handling nic operation\n");
                return -1;
            }
@@ -354,10 +239,7 @@ 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++;
 
-       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)) {
@@ -365,15 +247,24 @@ static int handle_pkt_tx(struct virtio_net_state * virtio_state)
        virtio_state->virtio_cfg.pci_isr = 0x1;
     }
 
-#ifdef VIRTIO_NIC_PROFILE
-    if(virtio_state->pkt_sent % 10000 == 0)
-       PrintError("Virtio NIC: %p, pkt_sent: %ld\n", virtio_state, virtio_state->pkt_sent);
-#endif 
+#ifdef CONFIG_VNET_PROFILE
+    if (virtio_state->pkt_sent % 10000 == 0){
+           PrintError("Virtio NIC: sent: %ld, rxed: %ld, dropped: %ld\n",
+                       virtio_state->pkt_sent,
+                       virtio_state->pkt_recv,
+                       virtio_state->pkt_drop);
+    }
+#endif
 
     return 0;
 }
 
-static int virtio_setup_queue(struct virtio_net_state * virtio_state, struct virtio_queue * queue, addr_t pfn, addr_t page_addr) {
+
+static int virtio_setup_queue(struct guest_info *core, 
+                                                       struct virtio_net_state * virtio_state, 
+                                                       struct virtio_queue * queue, 
+                                                       addr_t pfn, 
+                                                       addr_t page_addr) {
     queue->pfn = pfn;
                
     queue->ring_desc_addr = page_addr;
@@ -381,20 +272,20 @@ static int virtio_setup_queue(struct virtio_net_state * virtio_state, struct vir
     queue->ring_used_addr = ((queue->ring_avail_addr) + 
                             (sizeof(struct vring_avail)) + 
                             (queue->queue_size * sizeof(uint16_t)));
-               
+
     // round up to next page boundary.
     queue->ring_used_addr = (queue->ring_used_addr + 0xfff) & ~0xfff;
-    if (guest_pa_to_host_va(virtio_state->virtio_dev->vm, queue->ring_desc_addr, (addr_t *)&(queue->desc)) == -1) {
+    if (guest_pa_to_host_va(core, queue->ring_desc_addr, (addr_t *)&(queue->desc)) == -1) {
         PrintError("Could not translate ring descriptor address\n");
         return -1;
     }
  
-    if (guest_pa_to_host_va(virtio_state->virtio_dev->vm, queue->ring_avail_addr, (addr_t *)&(queue->avail)) == -1) {
+    if (guest_pa_to_host_va(core, queue->ring_avail_addr, (addr_t *)&(queue->avail)) == -1) {
         PrintError("Could not translate ring available address\n");
         return -1;
     }
 
-    if (guest_pa_to_host_va(virtio_state->virtio_dev->vm, queue->ring_used_addr, (addr_t *)&(queue->used)) == -1) {
+    if (guest_pa_to_host_va(core, queue->ring_used_addr, (addr_t *)&(queue->used)) == -1) {
         PrintError("Could not translate ring used address\n");
         return -1;
     }
@@ -415,6 +306,7 @@ static int virtio_io_write(struct guest_info *core, uint16_t port, void * src, u
     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
     int port_idx = port % virtio->io_range_size;
 
+
     PrintDebug("VIRTIO NIC %p Write for port %d (index=%d) len=%d, value=%x\n", private_data,
               port, port_idx,  length, *(uint32_t *)src);
 
@@ -436,15 +328,18 @@ static int virtio_io_write(struct guest_info *core, uint16_t port, void * src, u
            addr_t pfn = *(uint32_t *)src;
            addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
            uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
+
+           PrintDebug("Virtio Write: pfn: %p, page_addr %p, queue_idx %d\n", (void *)pfn, (void *)page_addr, queue_idx);
+
            switch (queue_idx) {
                case 0:
-                   virtio_setup_queue(virtio, &virtio->rx_vq, pfn, page_addr);
+                   virtio_setup_queue(core, virtio, &virtio->rx_vq, pfn, page_addr);
                    break;
                case 1:
-                   virtio_setup_queue(virtio, &virtio->tx_vq, pfn, page_addr);
+                   virtio_setup_queue(core, virtio, &virtio->tx_vq, pfn, page_addr);
                    break;
                case 2:
-                   virtio_setup_queue(virtio, &virtio->ctrl_vq, pfn, page_addr);
+                   virtio_setup_queue(core, virtio, &virtio->ctrl_vq, pfn, page_addr);
                    break;          
                default:
                    break;
@@ -466,12 +361,12 @@ static int virtio_io_write(struct guest_info *core, uint16_t port, void * src, u
                if (queue_idx == 0){
                    PrintDebug("receive queue notification 0, packet get by Guest\n");
                } else if (queue_idx == 1){
-                   if (handle_pkt_tx(virtio) == -1) {
+                   if (handle_pkt_tx(core, virtio) == -1) {
                        PrintError("Could not handle NIC Notification\n");
                        return -1;
                    }
                } else if (queue_idx == 2){
-                   if (handle_ctrl(virtio) == -1) {
+                   if (handle_ctrl(core, virtio) == -1) {
                        PrintError("Could not handle NIC Notification\n");
                        return -1;
                    }
@@ -507,7 +402,7 @@ static int virtio_io_read(struct guest_info *core, uint16_t port, void * dst, ui
     int port_idx = port % virtio->io_range_size;
     uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
 
-    PrintDebug("Virtio NIC %p: Read  for port %d (index =%d), length=%d", private_data,
+    PrintDebug("Virtio NIC %p: Read  for port %d (index =%d), length=%d\n", private_data,
               port, port_idx, length);
        
     switch (port_idx) {
@@ -583,6 +478,101 @@ static int virtio_io_read(struct guest_info *core, uint16_t port, void * dst, ui
 }
 
 
+
+
+static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
+    struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
+    struct virtio_queue * q = &(virtio->rx_vq);
+    struct virtio_net_hdr hdr;
+    uint32_t hdr_len = sizeof(struct virtio_net_hdr);
+    uint32_t data_len = size;
+    uint32_t offset = 0;
+    unsigned long flags;
+    int ret_val = -1;
+    int raw = 1;
+
+    flags = v3_lock_irqsave(virtio->lock);
+
+    PrintDebug("VIRTIO NIC: RX on cpu %d to virtio nic %p, size:%d\n", V3_Get_CPU(), virtio, size);
+
+    virtio->pkt_recv ++;
+
+    if (!raw){
+       data_len -= hdr_len;
+    }
+
+    build_receive_header(&hdr, buf, raw);
+
+    if (q->ring_avail_addr == 0) {
+       PrintError("Queue is not set\n");
+       goto exit;
+    }
+
+    if (q->cur_avail_idx != q->avail->index){
+       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;
+
+       hdr_desc = &(q->desc[hdr_idx]);
+       if (guest_pa_to_host_va(&(virtio->virtio_dev->vm->cores[0]), hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
+           PrintError("Could not translate receive buffer address\n");
+           ret_val = -1;
+           goto exit;
+       }
+
+       memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr));
+       if (offset >= data_len) {
+           hdr_desc->flags &= ~VIRTIO_NEXT_FLAG;
+       }
+
+       for (buf_idx = hdr_desc->next; offset < data_len; buf_idx = q->desc[hdr_idx].next) {
+           struct vring_desc * buf_desc = &(q->desc[buf_idx]);
+           uint32_t len = 0;
+
+           len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, buf + offset, data_len - offset);        
+           offset += len;
+           if (offset < data_len) {
+               buf_desc->flags = VIRTIO_NEXT_FLAG;             
+           }
+           buf_desc->length = len;
+       }
+       
+       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++;
+
+       q->cur_avail_idx++;
+    } else {
+       virtio->pkt_drop++;
+       goto exit;
+    }
+
+    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);
+       virtio->virtio_cfg.pci_isr = 0x1;
+    }
+
+    ret_val = offset;
+
+exit:
+       
+#ifdef CONFIG_VNET_PROFILE
+    if (virtio->pkt_recv % 100000 == 0){
+       PrintError("Virtio NIC: sent: %ld, rxed: %ld, dropped: %ld\n",
+               virtio->pkt_sent,
+               virtio->pkt_recv,
+               virtio->pkt_drop);
+    }
+#endif
+
+    v3_unlock_irqrestore(virtio->lock, flags);
+    return ret_val;
+}
+
+
 static struct v3_device_ops dev_ops = {
     .free = virtio_free,
     .reset = NULL,
@@ -673,6 +663,9 @@ static int connect_fn(struct v3_vm_info * info,
     net_state->net_ops = ops;
     net_state->backend_data = private_data;
 
+    ops->recv = virtio_rx;
+    ops->frontend_data = net_state;
+
     return 0;
 }
 
@@ -693,7 +686,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     INIT_LIST_HEAD(&(virtio_state->dev_list));
     virtio_state->pci_bus = pci_bus;
-    //virtio_state->vm = vm;
+    virtio_state->vm = vm;
 
     struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
     if (v3_attach_device(vm, dev) == -1) {