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.


add statistic structure to virtual ethernet devices
[palacios-OLD.git] / palacios / src / devices / lnx_virtio_nic.c
index 4f86bbe..529ce02 100644 (file)
@@ -29,6 +29,7 @@
 #include <palacios/vmm_lock.h>
 #include <palacios/vmm_util.h>
 #include <devices/pci.h>
+#include <palacios/vmm_ethernet.h>
 
 
 #ifndef CONFIG_DEBUG_VIRTIO_NET
@@ -39,6 +40,7 @@
 #define VIRTIO_NET_S_LINK_UP   1       /* Link is up */
 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
 
+
 struct virtio_net_hdr {
        uint8_t flags;
 
@@ -62,13 +64,20 @@ struct virtio_net_hdr_mrg_rxbuf {
 #define TX_QUEUE_SIZE 64
 #define RX_QUEUE_SIZE 1024
 #define CTRL_QUEUE_SIZE 64
-#define ETH_ALEN 6
 
 #define VIRTIO_NET_F_MRG_RXBUF 15      /* Host can merge receive buffers. */
 #define VIRTIO_NET_F_MAC       5       /* Host has given MAC address. */
 #define VIRTIO_NET_F_GSO       6       /* Host handles pkts w/ any GSO type */
 #define VIRTIO_NET_F_HOST_TSO4 11      /* Host can handle TSOv4 in. */
 
+/* this is not how virtio supposed to be,
+ * we may need a separately implemented virtio_pci
+ * In order to make guest to get virtio MAC from host
+ * I added it here  -- Lei
+ */
+ #define VIRTIO_NET_CONFIG 20  
+
+
 struct virtio_net_config
 {
     uint8_t mac[ETH_ALEN];     /* VIRTIO_NET_F_MAC */
@@ -79,6 +88,8 @@ struct virtio_dev_state {
     struct vm_device * pci_bus;
     struct list_head dev_list;
     struct v3_vm_info *vm;
+
+    uint8_t mac[ETH_ALEN];
 };
 
 struct virtio_net_state {
@@ -95,10 +106,8 @@ struct virtio_net_state {
 
     int buffed_rx;
     int tx_disabled;                   /* stop TX pkts from guest */
-    uint16_t cur_notify_tx_idx;        /*for used in update_tx_queue */
 
-    uint64_t pkt_sent, pkt_recv, pkt_drop;
-    uint64_t tx_stop_times, rx_stop_times, tx_poll_times, rx_ipi_num;
+    struct nic_statistics statistics;
 
     struct v3_dev_net_ops * net_ops;
     v3_lock_t rx_lock, tx_lock;
@@ -117,11 +126,7 @@ struct virtio_net_state {
 #define ERR_VIRTIO_TXQ_DISABLED 6
 
 
-static int virtio_free(struct vm_device * dev) 
-{
-       
-    return 0;
-}
+
 
 static int virtio_init_state(struct virtio_net_state * virtio) 
 {
@@ -149,20 +154,22 @@ static int virtio_init_state(struct virtio_net_state * virtio)
 
     virtio->virtio_cfg.pci_isr = 0;
        
-    virtio->virtio_cfg.host_features = 0; // (1 << VIRTIO_NET_F_MAC);
+    virtio->virtio_cfg.host_features = 0 | (1 << VIRTIO_NET_F_MAC);
 
     if ((v3_lock_init(&(virtio->rx_lock)) == -1) ||
-         (v3_lock_init(&(virtio->tx_lock)) == -1)){
+       (v3_lock_init(&(virtio->tx_lock)) == -1)){
         PrintError("Virtio NIC: Failure to init locks for net_state\n");
     }
 
-    virtio->pkt_sent = virtio->pkt_recv = virtio->pkt_drop = 0;
     virtio->buffed_rx = 0;
 
     return 0;
 }
 
-static int pkt_tx(struct guest_info *core, 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;
@@ -172,16 +179,26 @@ static int pkt_tx(struct guest_info *core, struct virtio_net_state * virtio, str
        return -ERR_VIRTIO_OTHER;
     }
 
-    return virtio->net_ops->send(buf, len, virtio->backend_data, NULL);
+    if(virtio->net_ops->send(buf, len, virtio->backend_data) >= 0){
+       virtio->statistics.tx_pkts ++;
+       virtio->statistics.tx_bytes += len;
+
+       return 0;
+    }
+
+    virtio->statistics.tx_dropped ++;
+
+    return -1;
 }
 
 
-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,
-                                       uint_t offset)
+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,
+                 uint_t offset)
 {
     uint32_t len;
     uint8_t * desc_buf = NULL;
@@ -217,6 +234,7 @@ static inline void disable_cb(struct virtio_queue *queue) {
     queue->used->flags |= VRING_NO_NOTIFY_FLAG;
 }
 
+
 /* interrupt the guest, so the guest core get EXIT to Palacios
  * this happens when there are either incoming pkts for the guest
  * or the guest can start TX pkts again */
@@ -226,41 +244,32 @@ static inline void notify_guest(struct virtio_net_state * virtio){
 
 
 /* guest free some pkts from rx queue */
-static int handle_rx_kick(struct guest_info *core, struct virtio_net_state * virtio) 
+static int handle_rx_kick(struct guest_info *core, 
+                         struct virtio_net_state * virtio) 
 {
     unsigned long flags;
 
     flags = v3_lock_irqsave(virtio->rx_lock);
 
-    virtio->net_ops->start_rx(virtio->backend_data);
-    disable_cb(&virtio->rx_vq);
+    if(virtio->net_ops->start_rx != NULL){
+       virtio->net_ops->start_rx(virtio->backend_data);
+    }
+    //disable_cb(&virtio->rx_vq);
 
     v3_unlock_irqrestore(virtio->rx_lock, flags);
        
     return 0;
 }
 
-#ifdef CONFIG_VNET_PROFILE
-static void print_profile_info(struct virtio_net_state *virtio){
-    PrintError("Virtio NIC: %p,  sent: %lld, rxed: %lld, dropped: %lld, \
-                       tx_stop: %lld, rx_stop: %lld, poll_time: %lld, rx_ipi: %lld\n",
-                       virtio,
-                       virtio->pkt_sent,
-                       virtio->pkt_recv,
-                       virtio->pkt_drop, 
-                       virtio->tx_stop_times,
-                       virtio->rx_stop_times,
-                       virtio->tx_poll_times,
-                       virtio->rx_ipi_num);
-}
-#endif
 
-static int handle_ctrl(struct guest_info *core, struct virtio_net_state * virtio) {
+static int handle_ctrl(struct guest_info *core, 
+                      struct virtio_net_state * virtio) {
        
     return 0;
 }
 
-static int handle_pkt_tx(struct guest_info *core, 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;
@@ -307,8 +316,6 @@ static int handle_pkt_tx(struct guest_info *core, struct virtio_net_state * virt
            req_len += buf_desc->length;
            desc_idx = buf_desc->next;
        }
-       virtio_state->pkt_sent ++;
-       recved ++;
 
        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 = req_len; // What do we set this to????
@@ -325,155 +332,23 @@ static int handle_pkt_tx(struct guest_info *core, struct virtio_net_state * virt
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 0, virtio_state->pci_dev);
        virtio_state->virtio_cfg.pci_isr = 0x1;
-    }
-
 
-#ifdef CONFIG_VNET_PROFILE
-       static long min = 1024, max = 0, total=0;
-       static int i=0;
-       total += recved;
-       i ++;
-       if(recved > max) max = recved;
-       if(recved < min) min = recved;
-       if(total > 100000) {
-               PrintError("VNIC: TX polling: %ld, min %ld, max %ld, avg: %ld pkts\n", total, min, max, total/i);
-               min = 1024;
-               max = 0;
-               i = 1; 
-               total = 0;
-       }
-#endif
-
-
-    return 0;
-
-exit_error:
-       
-    v3_unlock_irqrestore(virtio_state->tx_lock, flags);
-    return -ERR_VIRTIO_OTHER;
-}
-
-
-#if 0 //for multicore VNET
-/* used for poll pkt from virtio nic by VNET
- * only when vnet is running on sidecore */
-static int handle_pkt_tx_sidecore(struct guest_info *core, struct virtio_net_state * virtio) 
-{
-    struct virtio_queue * q = &(virtio->tx_vq);
-    struct virtio_net_hdr * hdr = NULL;
-    int recved = 0;
-    unsigned long flags;
-
-    if (!q->ring_avail_addr) {
-       return -ERR_VIRTIO_TXQ_NOSET;
+       virtio_state->statistics.interrupts ++;
     }
 
-    flags = v3_lock_irqsave(virtio->tx_lock);
-
-    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];
-       int desc_cnt = get_desc_count(q, desc_idx);
-       uint32_t req_len = 0;
-       int i = 0;
-
-       hdr_desc = &(q->desc[desc_idx]);
-       if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
-           PrintError("Could not translate block header address\n");
-           goto exit_error;
-       }
-
-       hdr = (struct virtio_net_hdr*)hdr_addr;
-       desc_idx = hdr_desc->next;
-
-       if(desc_cnt > 2){
-           PrintError("VNIC: merged rx buffer not supported\n");
-           goto exit_error;
-       }
-
-       for (i = 0; i < desc_cnt - 1; i++) {    
-           struct vring_desc * buf_desc = &(q->desc[desc_idx]);
-           if (pkt_tx_sidecore(core, virtio, buf_desc) < 0) {
-               PrintError("Error handling nic operation\n");
-               goto exit_error;
-           }
-
-           req_len += buf_desc->length;
-           desc_idx = buf_desc->next;
-       }
-       recved ++;
-       
-       q->cur_avail_idx ++;
-    }
-
-    if(recved) PrintDebug("VNIC: Tx polling %d pkts\n", recved);
-       
-    v3_unlock_irqrestore(virtio->tx_lock, flags);
-
     return 0;
 
 exit_error:
        
-    v3_unlock_irqrestore(virtio->tx_lock, flags);
+    v3_unlock_irqrestore(virtio_state->tx_lock, flags);
     return -ERR_VIRTIO_OTHER;
 }
 
 
-/* called by VNET, to notify Virtio to update the tx_queue used index 
- * used only when vnet running on sidecore */
-static int update_tx_queue(struct virtio_net_state * virtio, int handled_pkt){
-    struct virtio_queue * q = &(virtio->tx_vq);
-    unsigned long flags;
-
-    if (!q->ring_avail_addr) {
-       return -ERR_VIRTIO_TXQ_NOSET;
-    }
-
-    flags = v3_lock_irqsave(virtio->tx_lock);
-    while(handled_pkt > 0){
-       q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[virtio->cur_notify_tx_idx % q->queue_size];
-       q->used->ring[q->used->index % q->queue_size].length = req_len; // TODO:
-       q->used->index ++;
-       virtio->cur_notify_tx_idx ++;
-       handled_pkt --;
-    }
-    v3_unlock_irqrestore(virtio->tx_lock, flags);
-
-    if (handled_pkt && (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG))) {
-       v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
-       virtio->virtio_cfg.pci_isr = 0x1;
-
-       /* do we need to notify here? */
-       notify_guest(virtio);
-    }
-
-    virtio->pkt_sent += handled_pkt;
-       
-#ifdef CONFIG_VNET_PROFILE
-    if (virtio->pkt_sent % 50000 == 0){
-           long cur_time, time;
-           rdtscll(cur_time);
-           time = cur_time - virtio_state->last_sent_time;
-           PrintError("Virtio NIC: last sent 50000 cycles: %ld\n",time);
-           PrintError("Virtio NIC: sent: %ld, rxed: %ld, dropped: %ld\n",
-                       virtio->pkt_sent,
-                       virtio->pkt_recv,
-                       virtio->pkt_drop);
-           rdtscll(virtio->last_sent_time);
-    }
-#endif
-
-
-    return 0;
-}
-#endif
-
 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) {
+                             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;
@@ -510,12 +385,13 @@ static int virtio_setup_queue(struct guest_info *core,
     return 0;
 }
 
-static int virtio_io_write(struct guest_info *core, uint16_t port, void * src, uint_t length, void * private_data) 
+static int virtio_io_write(struct guest_info *core, 
+                          uint16_t port, void * src, 
+                          uint_t length, void * private_data) 
 {
     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);
 
@@ -539,11 +415,11 @@ static int virtio_io_write(struct guest_info *core, uint16_t port, void * src, u
            switch (queue_idx) {
                case 0:
                    virtio_setup_queue(core, virtio, &virtio->rx_vq, pfn, page_addr);
-                   disable_cb(&virtio->rx_vq);
+                   //disable_cb(&virtio->rx_vq);
                    break;
                case 1:
                    virtio_setup_queue(core, virtio, &virtio->tx_vq, pfn, page_addr);
-                   disable_cb(&virtio->tx_vq);
+                   //disable_cb(&virtio->tx_vq);
                    break;
                case 2:
                    virtio_setup_queue(core, virtio, &virtio->ctrl_vq, pfn, page_addr);
@@ -567,9 +443,7 @@ static int virtio_io_write(struct guest_info *core, uint16_t port, void * src, u
                uint16_t queue_idx = *(uint16_t *)src;                  
                if (queue_idx == 0){
                    handle_rx_kick(core, virtio);
-                   PrintError("rx kick\n");
                } else if (queue_idx == 1){
-                   PrintError("tx kick\n");
                    if (handle_pkt_tx(core, virtio) == -1) {
                        PrintError("Could not handle NIC Notification\n");
                        return -1;
@@ -605,13 +479,15 @@ static int virtio_io_write(struct guest_info *core, uint16_t port, void * src, u
     return length;
 }
 
-static int virtio_io_read(struct guest_info *core, uint16_t port, void * dst, uint_t length, void * private_data) 
+static int virtio_io_read(struct guest_info *core, 
+                         uint16_t port, void * dst, 
+                         uint_t length, void * private_data) 
 {
     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
     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\n", private_data,
+    PrintDebug("Virtio NIC %p: Read  for port 0x%x (index =%d), length=%d\n", private_data,
               port, port_idx, length);
        
     switch (port_idx) {
@@ -677,6 +553,10 @@ static int virtio_io_read(struct guest_info *core, uint16_t port, void * dst, ui
            v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
            break;
 
+       case VIRTIO_NET_CONFIG ... VIRTIO_NET_CONFIG + ETH_ALEN:
+           *(uint8_t *)dst = virtio->net_cfg.mac[port_idx-VIRTIO_NET_CONFIG];
+           break;
+
        default:
            PrintError("Virtio NIC: Read of Unhandled Virtio Read:%d\n", port_idx);
            return -1;
@@ -697,9 +577,15 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
     int ret_val = -ERR_VIRTIO_OTHER;
     int raw = 1;
 
+#ifndef CONFIG_DEBUG_VIRTIO_NET
+   {
+       PrintDebug("Virtio-NIC: virtio_rx: size: %d\n", size);  
+       //v3_hexdump(buf, size, NULL, 0);
+   }
+#endif
+
     flags = v3_lock_irqsave(virtio->rx_lock);
 
-    virtio->pkt_recv ++;
     if (!raw)
        data_len -= hdr_len;
 
@@ -757,17 +643,18 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
            (q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
            if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
                  notify_guest(virtio);
-                 virtio->rx_ipi_num ++;
            }
            virtio->buffed_rx = 0;
        }
+
+       virtio->statistics.rx_pkts ++;
+       virtio->statistics.rx_bytes += size;
     } else {
-       virtio->pkt_drop++;
+       virtio->statistics.rx_dropped ++;
+       
        /* RX queue is full,  tell backend to stop RX on this device */
        virtio->net_ops->stop_rx(virtio->backend_data);
        enable_cb(&virtio->rx_vq);
-
-       virtio->rx_stop_times ++;
        
        ret_val = -ERR_VIRTIO_RXQ_FULL;
        goto exit;
@@ -777,6 +664,8 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
        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;
+
+       virtio->statistics.interrupts ++;
     }
 
     ret_val = offset;
@@ -788,205 +677,70 @@ exit:
     return ret_val;
 }
 
+static int virtio_free(struct virtio_dev_state * virtio) {
+    struct virtio_net_state * backend = NULL;
+    struct virtio_net_state * tmp = NULL;
 
-#if 0 /* for encapuslation */
-/* virtio RX with encapulation version */
-static int virtio_rx_encap(uint8_t * data, 
-                                                 uint32_t size, 
-                                                 void * encap_header, 
-                                                 uint16_t encap_len,
-                                                 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_mrg_rxbuf hdr;
-    uint32_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
-    uint32_t data_len = size + encap_len;
-    unsigned long flags;
-    int ret_val = -ERR_VIRTIO_OTHER;
 
-    if (q->ring_avail_addr == 0) {
-       PrintError("Queue is not set\n");
-       ret_val = -ERR_VIRTIO_RXQ_NOSET;
-       goto exit;
-    }
-       
-    memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf));
+    list_for_each_entry_safe(backend, tmp, &(virtio->dev_list), dev_link) {
 
-    flags = v3_lock_irqsave(virtio->rx_lock);
-    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;
-       uint32_t offset = 0;
+       // unregister from PCI
 
-       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");
-           goto exit;
-       }
-       hdr.num_buffers = 1;
-       memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr_mrg_rxbuf));
-       if (offset >= data_len) {
-           hdr_desc->flags &= ~VIRTIO_NEXT_FLAG;
-       }
-
-       struct vring_desc * buf_desc = NULL;
-       uint32_t len = 0;
-       buf_idx = hdr_desc->next;
-       buf_desc = &(q->desc[buf_idx]);
-       
-       if(hdr_len > 0 && !encap_header) {
-           len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, encap_header, encap_len, 0);
-           offset += len;
-       }
-       
-       len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, data + offset, data_len - offset, offset);           
-       offset += len;
-
-       if(data_len < offset)/* if there is large pkt, need merge more buffer */
-           PrintDebug("Virtio NIC: data pkt larger than RX queue buffer\n");
-
-       buf_desc->length = offset;      
-       buf_desc->flags &= ~VIRTIO_NEXT_FLAG;
-       
-       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++;
-
-       /* notify guest 
-         * when it returns from EXIT, guest gets the virtio rx interrupt */
-       if((++virtio->buffed_rx > q->queue_size/2) &&
-           (q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
-           if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
-                 notify_guest(virtio);
-           }
-           virtio->buffed_rx = 0;
-       }
-       ret_val = offset;
-    } else {
-       virtio->pkt_drop++;
-       ret_val = -ERR_VIRTIO_RXQ_FULL;
-       goto exit;
-    }
-    virtio->pkt_recv ++;
-
-    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 CONFIG_VNET_PROFILE
-    if (virtio->pkt_recv % 50000 == 0){
-           long cur_time, time;
-           rdtscll(cur_time);
-           time = cur_time - virtio->last_recv_time;
-           PrintError("Virtio NIC: sent: %ld, rxed: %ld, dropped: %ld\n",
-               virtio->pkt_sent,
-               virtio->pkt_recv,
-               virtio->pkt_drop);
-           rdtscll(virtio->last_recv_time);
+       list_del(&(backend->dev_link));
+       V3_Free(backend);
     }
-#endif
-
-exit:
 
-    v3_unlock_irqrestore(virtio->rx_lock, flags);
-    return ret_val;
+    V3_Free(virtio);
+    return 0;
 }
-#endif 
-
 
 
 static struct v3_device_ops dev_ops = {
-    .free = virtio_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+    .free = (int (*)(void *))virtio_free,
 };
 
-#if 0 //temporary hacking LX
-static struct virtio_net_state *vnic_states[2] = {NULL, NULL};
-static int num_vnic = 0;
-
-void vnic_polling(void *data){
-    struct v3_vm_info *info = (struct v3_vm_info *)data;    
-    if(vnic_states[0] != NULL && info == vnic_states[0]->virtio_dev->vm){
-       handle_pkt_tx(&(info->cores[0]), vnic_states[0]);
-    }
-
-    if(vnic_states[1] != NULL && info == vnic_states[1]->virtio_dev->vm){
-       handle_pkt_tx(&(info->cores[0]), vnic_states[1]);
-    }
-}
-#endif
 
 /* TODO: Issue here: which vm info it needs? calling VM or the device's own VM? */
-static void virtio_nic_poll(struct v3_vm_info *vm, void *data){
-    struct virtio_net_state *virtio = (struct virtio_net_state *)data;
+static void virtio_nic_poll(struct v3_vm_info * vm, void * data){
+    struct virtio_net_state * virtio = (struct virtio_net_state *)data;
        
     handle_pkt_tx(&(vm->cores[0]), virtio);
-
-    virtio->tx_poll_times ++;
-
-#ifdef CONFIG_VNET_PROFILE
-    static uint64_t last_time = 0;
-    uint64_t time;
-    rdtscll(time);
-    if((time - last_time) > 5000000000){
-       last_time = time;
-       print_profile_info(virtio);
-    }
-#endif
-}
-
-#if 0 /* NAPI */
-/* tx one pkt from guest */
-static int virtio_tx_pkt(struct guest_info *core, struct virtio_net_state * virtio_state){
-
-}
-
-static void virtio_nic_poll(struct v3_vm_info *vm, void *data, int budget){
-
-
 }
 
-#endif
-
-
-static void virtio_start_tx(void *data){
+static void virtio_start_tx(void * data){
     struct virtio_net_state * virtio = (struct virtio_net_state *)data;
+    unsigned long flags;
 
-    /* do we need a lock here? */
+    flags = v3_lock_irqsave(virtio->tx_lock);
     virtio->tx_disabled = 0;
 
-    /* notify the device's guest it can start sending pkt */
+    /* notify the device's guest to start sending pkt */
     if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
        notify_guest(virtio);
     }
+    v3_unlock_irqrestore(virtio->tx_lock, flags);      
 }
 
-static void virtio_stop_tx(void *data){
+static void virtio_stop_tx(void * data){
     struct virtio_net_state * virtio = (struct virtio_net_state *)data;
+    unsigned long flags;
 
-    /* do we need a lock here? */
+    flags = v3_lock_irqsave(virtio->tx_lock);
     virtio->tx_disabled = 1;
 
-    /* how do we stop the guest to exit to palacios for sending pkt? */
+    /* stop the guest to exit to palacios for sending pkt? */
     if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
        disable_cb(&virtio->tx_vq);
     }
 
-    virtio->tx_stop_times ++;
+    v3_unlock_irqrestore(virtio->tx_lock, flags);
 }
 
        
 
 
-static int register_dev(struct virtio_dev_state * virtio, struct virtio_net_state * net_state) 
+static int register_dev(struct virtio_dev_state * virtio, 
+                       struct virtio_net_state * net_state) 
 {
     struct pci_device * pci_dev = NULL;
     struct v3_pci_bar bars[6];
@@ -1046,17 +800,12 @@ static int register_dev(struct virtio_dev_state * virtio, struct virtio_net_stat
     net_state->pci_dev = pci_dev;
     net_state->virtio_dev = virtio;
 
-    uchar_t mac[6] = {0x11,0x11,0x11,0x11,0x11,0x11};
-    memcpy(net_state->net_cfg.mac, mac, 6);
-                                                                                                          
-    memcpy(pci_dev->config_data, net_state->net_cfg.mac, ETH_ALEN);
-    
+    memcpy(net_state->net_cfg.mac, virtio->mac, 6);                           
+       
     virtio_init_state(net_state);
 
-#if 0 //temporary hacking LX
-    vnic_states[num_vnic ++] = net_state;
-    PrintError("VNIC: num of vnic %d\n", num_vnic);
-#endif
+    /* Add backend to list of devices */
+    list_add(&(net_state->dev_link), &(virtio->dev_list));
 
     return 0;
 }
@@ -1074,12 +823,15 @@ static int connect_fn(struct v3_vm_info * info,
 
     net_state->net_ops = ops;
     net_state->backend_data = private_data;
+    net_state->virtio_dev = virtio;
+       
 
     ops->recv = virtio_rx;
     ops->poll = virtio_nic_poll;
     ops->start_tx = virtio_start_tx;
     ops->stop_tx = virtio_stop_tx;
     ops->frontend_data = net_state;
+    memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN);
 
     return 0;
 }
@@ -1087,9 +839,8 @@ static int connect_fn(struct v3_vm_info * info,
 static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
     struct virtio_dev_state * virtio_state = NULL;
-    char * name = v3_cfg_val(cfg, "name");
-
-    PrintDebug("Virtio NIC: Initializing VIRTIO Network device: %s\n", name);
+    char * dev_id = v3_cfg_val(cfg, "ID");
+    char * macstr = v3_cfg_val(cfg, "mac");
 
     if (pci_bus == NULL) {
        PrintError("Virtio NIC: VirtIO devices require a PCI Bus");
@@ -1103,14 +854,24 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     virtio_state->pci_bus = pci_bus;
     virtio_state->vm = vm;
 
-    struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
-    if (v3_attach_device(vm, dev) == -1) {
-       PrintError("Virtio NIC: Could not attach device %s\n", name);
+    if (macstr != NULL && !str2mac(macstr, virtio_state->mac)) {
+       PrintDebug("Virtio NIC: Mac specified %s\n", macstr);
+    }else {
+       PrintDebug("Virtio NIC: MAC not specified\n");
+       random_ethaddr(virtio_state->mac);
+    }
+
+    struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
+
+    if (dev == NULL) {
+       PrintError("Virtio NIC: Could not attach device %s\n", dev_id);
+       V3_Free(virtio_state);
        return -1;
     }
 
-    if (v3_dev_add_net_frontend(vm, name, connect_fn, (void *)virtio_state) == -1) {
-       PrintError("Virtio NIC: Could not register %s as net frontend\n", name);
+    if (v3_dev_add_net_frontend(vm, dev_id, connect_fn, (void *)virtio_state) == -1) {
+       PrintError("Virtio NIC: Could not register %s as net frontend\n", dev_id);
+       v3_remove_device(dev);
        return -1;
     }