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.


compile fix
[palacios.git] / palacios / src / devices / lnx_virtio_nic.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2010, Lei Xia <lxia@northwestern.edu>
11  * Copyright (c) 2010, Cui Zheng <cuizheng@cs.unm.edu>
12  * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Author: Lei Xia <lxia@northwestern.edu>
16  *         Cui Zheng <cuizheng@cs.unm.edu>
17  *               
18  *
19  * This is free software.  You are permitted to use,
20  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21  */
22  
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_dev_mgr.h>
25 #include <devices/lnx_virtio_pci.h>
26 #include <palacios/vm_guest_mem.h>
27 #include <palacios/vmm_sprintf.h>
28 #include <palacios/vmm_vnet.h>
29 #include <palacios/vmm_lock.h>
30 #include <palacios/vmm_util.h>
31 #include <devices/pci.h>
32 #include <palacios/vmm_ethernet.h>
33 #include <palacios/vmm_time.h>
34
35
36 #ifndef CONFIG_DEBUG_VIRTIO_NET
37 #undef PrintDebug
38 #define PrintDebug(fmt, args...)
39 #endif
40
41 #define TX_QUEUE_SIZE 4096
42 #define RX_QUEUE_SIZE 4096
43 #define CTRL_QUEUE_SIZE 64
44
45 /* The feature bitmap for virtio nic
46   * from Linux */
47 #define VIRTIO_NET_F_CSUM       0       /* Host handles pkts w/ partial csum */
48 #define VIRTIO_NET_F_GUEST_CSUM 1       /* Guest handles pkts w/ partial csum */
49 #define VIRTIO_NET_F_MAC        5       /* Host has given MAC address. */
50 #define VIRTIO_NET_F_GSO        6       /* Host handles pkts w/ any GSO type */
51 #define VIRTIO_NET_F_GUEST_TSO4 7       /* Guest can handle TSOv4 in. */
52 #define VIRTIO_NET_F_GUEST_TSO6 8       /* Guest can handle TSOv6 in. */
53 #define VIRTIO_NET_F_GUEST_ECN  9       /* Guest can handle TSO[6] w/ ECN in. */
54 #define VIRTIO_NET_F_GUEST_UFO  10      /* Guest can handle UFO in. */
55 #define VIRTIO_NET_F_HOST_TSO4  11      /* Host can handle TSOv4 in. */
56 #define VIRTIO_NET_F_HOST_TSO6  12      /* Host can handle TSOv6 in. */
57 #define VIRTIO_NET_F_HOST_ECN   13      /* Host can handle TSO[6] w/ ECN in. */
58 #define VIRTIO_NET_F_HOST_UFO   14      /* Host can handle UFO in. */
59 #define VIRTIO_NET_F_MRG_RXBUF  15      /* Host can merge receive buffers. */
60 #define VIRTIO_NET_F_STATUS     16      /* virtio_net_config.status available */
61
62 /* Port to get virtio config */
63 #define VIRTIO_NET_CONFIG 20  
64
65 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
66
67 /* for gso_type in virtio_net_hdr */
68 #define VIRTIO_NET_HDR_GSO_NONE         0      
69 #define VIRTIO_NET_HDR_GSO_TCPV4        1     /* GSO frame, IPv4 TCP (TSO) */
70 #define VIRTIO_NET_HDR_GSO_UDP          3       /* GSO frame, IPv4 UDP (UFO) */
71 #define VIRTIO_NET_HDR_GSO_TCPV6        4       /* GSO frame, IPv6 TCP */
72 #define VIRTIO_NET_HDR_GSO_ECN          0x80    /* TCP has ECN set */   
73
74
75 /* for flags in virtio_net_hdr */
76 #define VIRTIO_NET_HDR_F_NEEDS_CSUM     1       /* Use csum_start, csum_offset */
77
78
79 /* First element of the scatter-gather list, used with GSO or CSUM features */
80 struct virtio_net_hdr
81 {
82     uint8_t flags;
83     uint8_t gso_type;
84     uint16_t hdr_len;           /* Ethernet + IP + tcp/udp hdrs */
85     uint16_t gso_size;          /* Bytes to append to hdr_len per frame */
86     uint16_t csum_start;        /* Position to start checksumming from */
87     uint16_t csum_offset;       /* Offset after that to place checksum */
88 }__attribute__((packed));
89
90
91 /* The header to use when the MRG_RXBUF 
92  * feature has been negotiated. */
93 struct virtio_net_hdr_mrg_rxbuf {
94     struct virtio_net_hdr hdr;
95     uint16_t num_buffers;       /* Number of merged rx buffers */
96 };
97
98 struct virtio_net_config
99 {
100     uint8_t mac[ETH_ALEN];      /* VIRTIO_NET_F_MAC */
101     uint16_t status;
102 } __attribute__((packed));
103
104 struct virtio_dev_state {
105     struct vm_device * pci_bus;
106     struct list_head dev_list;
107     struct v3_vm_info *vm;
108
109     uint8_t mac[ETH_ALEN];
110 };
111
112 struct virtio_net_state {
113     struct virtio_net_config net_cfg;
114     struct virtio_config virtio_cfg;
115
116     struct v3_vm_info * vm;
117     struct vm_device * dev;
118     struct pci_device * pci_dev; 
119     int io_range_size;
120     
121     struct virtio_queue rx_vq;          /* idx 0*/
122     struct virtio_queue tx_vq;          /* idx 1*/
123     struct virtio_queue ctrl_vq;        /* idx 2*/
124
125     struct v3_timer * timer;
126     void * poll_thread;
127
128     struct nic_statistics stats;
129
130     struct v3_dev_net_ops * net_ops;
131     v3_lock_t rx_lock, tx_lock;
132
133     uint8_t tx_notify, rx_notify;
134     uint32_t tx_pkts, rx_pkts;
135     uint64_t past_us;
136
137     void * backend_data;
138     struct virtio_dev_state * virtio_dev;
139     struct list_head dev_link;
140 };
141
142
143 static int virtio_init_state(struct virtio_net_state * virtio) 
144 {
145     virtio->rx_vq.queue_size = RX_QUEUE_SIZE;
146     virtio->tx_vq.queue_size = TX_QUEUE_SIZE;
147     virtio->ctrl_vq.queue_size = CTRL_QUEUE_SIZE;
148
149     virtio->rx_vq.ring_desc_addr = 0;
150     virtio->rx_vq.ring_avail_addr = 0;
151     virtio->rx_vq.ring_used_addr = 0;
152     virtio->rx_vq.pfn = 0;
153     virtio->rx_vq.cur_avail_idx = 0;
154
155     virtio->tx_vq.ring_desc_addr = 0;
156     virtio->tx_vq.ring_avail_addr = 0;
157     virtio->tx_vq.ring_used_addr = 0;
158     virtio->tx_vq.pfn = 0;
159     virtio->tx_vq.cur_avail_idx = 0;
160
161     virtio->ctrl_vq.ring_desc_addr = 0;
162     virtio->ctrl_vq.ring_avail_addr = 0;
163     virtio->ctrl_vq.ring_used_addr = 0;
164     virtio->ctrl_vq.pfn = 0;
165     virtio->ctrl_vq.cur_avail_idx = 0;
166
167     virtio->virtio_cfg.pci_isr = 0;
168         
169     virtio->virtio_cfg.host_features = 0 | (1 << VIRTIO_NET_F_MAC);
170         //                                 (1 << VIRTIO_NET_F_GSO) | 
171         //                                 (1 << VIRTIO_NET_F_HOST_UFO) | 
172                 //                         (1 << VIRTIO_NET_F_HOST_TSO4);
173
174     if ((v3_lock_init(&(virtio->rx_lock)) == -1) ||
175         (v3_lock_init(&(virtio->tx_lock)) == -1)){
176         PrintError("Virtio NIC: Failure to init locks for net_state\n");
177     }
178
179     return 0;
180 }
181
182 static int tx_one_pkt(struct guest_info * core, 
183                       struct virtio_net_state * virtio, 
184                       struct vring_desc * buf_desc) 
185 {
186     uint8_t * buf = NULL;
187     uint32_t len = buf_desc->length;
188     int synchronize = 1; // (virtio->tx_notify == 1)?1:0;
189
190     if (v3_gpa_to_hva(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
191         PrintDebug("Could not translate buffer address\n");
192         return -1;
193     }
194
195     V3_Net_Print(2, "Virtio-NIC: virtio_tx: size: %d\n", len);
196     if(v3_net_debug >= 4){
197         v3_hexdump(buf, len, NULL, 0);
198     }
199
200     if(virtio->net_ops->send(buf, len, synchronize, virtio->backend_data) < 0){
201         virtio->stats.tx_dropped ++;
202         return -1;
203     }
204
205     virtio->stats.tx_pkts ++;
206     virtio->stats.tx_bytes += len;
207
208     return 0;
209 }
210
211
212 static inline int copy_data_to_desc(struct guest_info * core, 
213                   struct virtio_net_state * virtio_state, 
214                   struct vring_desc * desc, 
215                   uchar_t * buf, 
216                   uint_t buf_len,
217                   uint_t offset)
218 {
219     uint32_t len;
220     uint8_t * desc_buf = NULL;
221
222     if (v3_gpa_to_hva(core, desc->addr_gpa, (addr_t *)&(desc_buf)) == -1) {
223         PrintDebug("Could not translate buffer address\n");
224         return -1;
225     }
226     len = (desc->length < buf_len)?(desc->length - offset):buf_len;
227     memcpy(desc_buf+offset, buf, len);
228
229     return len;
230 }
231
232
233 static inline int get_desc_count(struct virtio_queue * q, int index) {
234     struct vring_desc * tmp_desc = &(q->desc[index]);
235     int cnt = 1;
236     
237     while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
238         tmp_desc = &(q->desc[tmp_desc->next]);
239         cnt++;
240     }
241
242     return cnt;
243 }
244
245 static inline void enable_cb(struct virtio_queue *queue){
246     queue->used->flags &= ~ VRING_NO_NOTIFY_FLAG;
247 }
248
249 static inline void disable_cb(struct virtio_queue *queue) {
250     queue->used->flags |= VRING_NO_NOTIFY_FLAG;
251 }
252
253 static int handle_pkt_tx(struct guest_info * core, 
254                          struct virtio_net_state * virtio_state) 
255 {
256     struct virtio_queue *q = &(virtio_state->tx_vq);
257     int txed = 0;
258     unsigned long flags;
259
260     if (!q->ring_avail_addr) {
261         return -1;
262     }
263
264     flags = v3_lock_irqsave(virtio_state->tx_lock);
265     while (q->cur_avail_idx != q->avail->index) {
266         struct virtio_net_hdr *hdr = NULL;
267         struct vring_desc * hdr_desc = NULL;
268         addr_t hdr_addr = 0;
269         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
270         int desc_cnt = get_desc_count(q, desc_idx);
271
272         if(desc_cnt > 2){
273             PrintError("VNIC: merged rx buffer not supported, desc_cnt %d\n", desc_cnt);
274             goto exit_error;
275         }
276
277         hdr_desc = &(q->desc[desc_idx]);
278         if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
279             PrintError("Could not translate block header address\n");
280             goto exit_error;
281         }
282
283         hdr = (struct virtio_net_hdr *)hdr_addr;
284         desc_idx = hdr_desc->next;
285
286         /* here we assumed that one ethernet pkt is not splitted into multiple buffer */        
287         struct vring_desc * buf_desc = &(q->desc[desc_idx]);
288         if (tx_one_pkt(core, virtio_state, buf_desc) == -1) {
289             PrintError("Virtio NIC: Error handling nic operation\n");
290             goto exit_error;
291         }
292             
293         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
294         q->used->ring[q->used->index % q->queue_size].length = buf_desc->length; /* What do we set this to???? */
295         q->used->index ++;
296         
297         q->cur_avail_idx ++;
298
299         txed ++;
300     }
301
302     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
303         
304     if (virtio_state->virtio_cfg.pci_isr == 0 && 
305           txed && !(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
306         v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 0, virtio_state->pci_dev);
307         virtio_state->virtio_cfg.pci_isr = 0x1;
308
309         virtio_state->stats.rx_interrupts ++;
310     }
311
312     if(txed > 0) {
313         V3_Net_Print(2, "Virtio Handle TX: txed pkts: %d\n", txed);
314     }
315
316     return 0;
317
318 exit_error:
319         
320     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
321     return -1;
322 }
323
324
325 static int virtio_setup_queue(struct guest_info *core, 
326                               struct virtio_net_state * virtio_state, 
327                               struct virtio_queue * queue, 
328                               addr_t pfn, addr_t page_addr) {
329     queue->pfn = pfn;
330                 
331     queue->ring_desc_addr = page_addr;
332     queue->ring_avail_addr = page_addr + (queue->queue_size * sizeof(struct vring_desc));
333     queue->ring_used_addr = ((queue->ring_avail_addr) + 
334                              (sizeof(struct vring_avail)) + 
335                              (queue->queue_size * sizeof(uint16_t)));
336
337     // round up to next page boundary.
338     queue->ring_used_addr = (queue->ring_used_addr + 0xfff) & ~0xfff;
339     if (v3_gpa_to_hva(core, queue->ring_desc_addr, (addr_t *)&(queue->desc)) == -1) {
340         PrintError("Could not translate ring descriptor address\n");
341          return -1;
342     }
343  
344     if (v3_gpa_to_hva(core, queue->ring_avail_addr, (addr_t *)&(queue->avail)) == -1) {
345         PrintError("Could not translate ring available address\n");
346         return -1;
347     }
348
349     if (v3_gpa_to_hva(core, queue->ring_used_addr, (addr_t *)&(queue->used)) == -1) {
350         PrintError("Could not translate ring used address\n");
351         return -1;
352     }
353
354     PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
355                (void *)(queue->ring_desc_addr),
356                (void *)(queue->ring_avail_addr),
357                (void *)(queue->ring_used_addr));
358     
359     PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n", 
360                queue->desc, queue->avail, queue->used);
361     
362     return 0;
363 }
364
365 static int virtio_io_write(struct guest_info *core, 
366                            uint16_t port, void * src, 
367                            uint_t length, void * private_data) 
368 {
369     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
370     int port_idx = port % virtio->io_range_size;
371
372     PrintDebug("VIRTIO NIC %p Write for port %d (index=%d) len=%d, value=%x\n", private_data,
373                port, port_idx,  length, *(uint32_t *)src);
374
375     switch (port_idx) {
376         case GUEST_FEATURES_PORT:
377             if (length != 4) {
378                 PrintError("Illegal write length for guest features\n");
379                 return -1;
380             }       
381             virtio->virtio_cfg.guest_features = *(uint32_t *)src;
382             break;
383                 
384         case VRING_PG_NUM_PORT:
385             if (length != 4) {
386                 PrintError("Illegal write length for page frame number\n");
387                 return -1;
388             }
389             addr_t pfn = *(uint32_t *)src;
390             addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
391             uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
392             switch (queue_idx) {
393                 case 0:
394                     virtio_setup_queue(core, virtio, &virtio->rx_vq, pfn, page_addr);
395                     break;
396                 case 1:
397                     virtio_setup_queue(core, virtio, &virtio->tx_vq, pfn, page_addr);
398                     if(virtio->tx_notify == 0){
399                         disable_cb(&virtio->tx_vq);
400                         V3_THREAD_WAKEUP(virtio->poll_thread);
401                     }
402                     break;
403                 case 2:
404                     virtio_setup_queue(core, virtio, &virtio->ctrl_vq, pfn, page_addr);
405                     break;          
406                 default:
407                     break;
408             }
409             break;
410                 
411         case VRING_Q_SEL_PORT:
412             virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
413             if (virtio->virtio_cfg.vring_queue_selector > 2) {
414                 PrintError("Virtio NIC: wrong queue idx: %d\n", 
415                            virtio->virtio_cfg.vring_queue_selector);
416                 return -1;
417             }
418             break;
419                 
420         case VRING_Q_NOTIFY_PORT: 
421             {
422                 uint16_t queue_idx = *(uint16_t *)src;                  
423                 if (queue_idx == 0){
424                     /* receive queue refill */
425                     virtio->stats.tx_interrupts ++;
426                 } else if (queue_idx == 1){
427                     if (handle_pkt_tx(core, virtio) == -1) {
428                         PrintError("Could not handle Virtio NIC tx kick\n");
429                         return -1;
430                     }
431                     virtio->stats.tx_interrupts ++;
432                 } else if (queue_idx == 2){
433                     /* ctrl */
434                 } else {
435                     PrintError("Wrong queue index %d\n", queue_idx);
436                 }       
437                 break;          
438             }
439         
440         case VIRTIO_STATUS_PORT:
441             virtio->virtio_cfg.status = *(uint8_t *)src;
442             if (virtio->virtio_cfg.status == 0) {
443                 virtio_init_state(virtio);
444             }
445             break;
446
447         case VIRTIO_ISR_PORT:
448             virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
449             break;
450                 
451         default:
452             return -1;
453             break;
454     }
455
456     return length;
457 }
458
459 static int virtio_io_read(struct guest_info *core, 
460                           uint16_t port, void * dst, 
461                           uint_t length, void * private_data) 
462 {
463     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
464     int port_idx = port % virtio->io_range_size;
465     uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
466
467     PrintDebug("Virtio NIC %p: Read  for port 0x%x (index =%d), length=%d\n", private_data,
468                port, port_idx, length);
469         
470     switch (port_idx) {
471         case HOST_FEATURES_PORT:
472             if (length != 4) {
473                 PrintError("Illegal read length for host features\n");
474                 //return -1;
475             }
476             *(uint32_t *)dst = virtio->virtio_cfg.host_features;
477             break;
478
479         case VRING_PG_NUM_PORT:
480             if (length != 4) {
481                 PrintError("Illegal read length for page frame number\n");
482                 return -1;
483             }
484             switch (queue_idx) {
485                 case 0:
486                     *(uint32_t *)dst = virtio->rx_vq.pfn;
487                     break;
488                 case 1:
489                     *(uint32_t *)dst = virtio->tx_vq.pfn;
490                     break;      
491                 case 2:
492                     *(uint32_t *)dst = virtio->ctrl_vq.pfn;
493                     break;
494                 default:
495                     break;
496             }
497             break;
498
499         case VRING_SIZE_PORT:
500             if (length != 2) {
501                 PrintError("Illegal read length for vring size\n");
502                 return -1;
503             }
504             switch (queue_idx) {
505                 case 0:
506                     *(uint16_t *)dst = virtio->rx_vq.queue_size;
507                     break;
508                 case 1:
509                     *(uint16_t *)dst = virtio->tx_vq.queue_size;
510                     break;      
511                 case 2:
512                     *(uint16_t *)dst = virtio->ctrl_vq.queue_size;
513                     break;
514                 default:
515                     break;
516             }
517             break;
518
519         case VIRTIO_STATUS_PORT:
520             if (length != 1) {
521                 PrintError("Illegal read length for status\n");
522                 return -1;
523             }
524             *(uint8_t *)dst = virtio->virtio_cfg.status;
525             break;
526                 
527         case VIRTIO_ISR_PORT:
528             *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
529             virtio->virtio_cfg.pci_isr = 0;
530             v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
531             break;
532
533         case VIRTIO_NET_CONFIG ... VIRTIO_NET_CONFIG + ETH_ALEN:
534             *(uint8_t *)dst = virtio->net_cfg.mac[port_idx-VIRTIO_NET_CONFIG];
535             break;
536
537         default:
538             PrintError("Virtio NIC: Read of Unhandled Virtio Read:%d\n", port_idx);
539             return -1;
540     }
541
542     return length;
543 }
544
545
546 /* receiving raw ethernet pkt from backend */
547 static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
548     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
549     struct virtio_queue * q = &(virtio->rx_vq);
550     struct virtio_net_hdr_mrg_rxbuf hdr;
551     uint32_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
552     uint32_t data_len;
553     //uint32_t offset = 0;
554     unsigned long flags;
555
556     V3_Net_Print(2, "Virtio-NIC: virtio_rx: size: %d\n", size);
557     if(v3_net_debug >= 4){
558         v3_hexdump(buf, size, NULL, 0);
559     }
560
561     flags = v3_lock_irqsave(virtio->rx_lock);
562
563     data_len = size;
564     memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf));
565
566     if (q->ring_avail_addr == 0) {
567         V3_Net_Print(2, "Virtio NIC: RX Queue not set\n");
568         virtio->stats.rx_dropped ++;
569         goto err_exit;
570     }
571
572     if (q->cur_avail_idx != q->avail->index){
573         addr_t hdr_addr = 0;
574         uint16_t buf_idx = 0;
575         uint16_t hdr_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
576         struct vring_desc * hdr_desc = NULL;
577         struct vring_desc * buf_desc = NULL;
578         uint32_t len;
579
580         hdr_desc = &(q->desc[hdr_idx]);
581         if (v3_gpa_to_hva(&(virtio->virtio_dev->vm->cores[0]), hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
582             V3_Net_Print(2, "Virtio NIC: Could not translate receive buffer address\n");
583             virtio->stats.rx_dropped ++;
584             goto err_exit;
585         }
586
587 #if 0 /* merged buffer */
588         for(buf_idx = hdr_desc->next; offset < data_len; buf_idx = q->desc[hdr_idx].next) {
589             uint32_t len = 0;
590             buf_desc = &(q->desc[buf_idx]);
591
592             len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, buf + offset, data_len - offset, 0);     
593             offset += len;
594             if (offset < data_len) {
595                 buf_desc->flags = VIRTIO_NEXT_FLAG;             
596             }
597             buf_desc->length = len;
598             hdr.num_buffers ++;
599         }
600         buf_desc->flags &= ~VIRTIO_NEXT_FLAG;
601         memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr_mrg_rxbuf));
602 #endif
603
604         hdr.num_buffers = 1;
605         memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr_mrg_rxbuf));
606         if (data_len == 0) {
607             hdr_desc->flags &= ~VIRTIO_NEXT_FLAG;
608         }
609
610         buf_idx = hdr_desc->next;
611         buf_desc = &(q->desc[buf_idx]);
612         len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, buf, data_len, 0);           
613         if (len < data_len) {
614             V3_Net_Print(2, "Virtio NIC: ring buffer len less than pkt size, merged buffer not supported\n");
615             virtio->stats.rx_dropped ++;
616                 
617             goto err_exit;
618         }
619         buf_desc->flags &= ~VIRTIO_NEXT_FLAG;
620
621         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
622         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) */
623         q->used->index++;
624         q->cur_avail_idx++;
625
626         virtio->stats.rx_pkts ++;
627         virtio->stats.rx_bytes += size;
628     } else {
629         V3_Net_Print(2, "Virtio NIC: Guest RX queue is full\n");
630         virtio->stats.rx_dropped ++;
631
632         /* kick guest to refill the queue */
633         virtio->virtio_cfg.pci_isr = 0x1;       
634         v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
635         v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].cpu_id, 0);
636         virtio->stats.rx_interrupts ++;
637         
638         goto err_exit;
639     }
640
641     if (virtio->virtio_cfg.pci_isr == 0 && 
642         !(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
643         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
644
645         virtio->virtio_cfg.pci_isr = 0x1;       
646         v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
647
648         virtio->stats.rx_interrupts ++;
649     }
650
651     v3_unlock_irqrestore(virtio->rx_lock, flags);
652
653     /* notify guest if it is in guest mode */
654     /* ISSUE: What is gonna happen if guest thread is running on the same core as this thread? */
655     if(virtio->rx_notify == 1){
656         v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].cpu_id, 0);
657     }
658
659     return 0;
660
661 err_exit:
662
663     v3_unlock_irqrestore(virtio->rx_lock, flags);
664  
665     return -1;
666 }
667
668 static int virtio_free(struct virtio_dev_state * virtio) {
669     struct virtio_net_state * backend = NULL;
670     struct virtio_net_state * tmp = NULL;
671
672
673     list_for_each_entry_safe(backend, tmp, &(virtio->dev_list), dev_link) {
674
675         // unregister from PCI
676
677         list_del(&(backend->dev_link));
678         V3_Free(backend);
679     }
680
681     V3_Free(virtio);
682     return 0;
683 }
684
685
686 static struct v3_device_ops dev_ops = {
687     .free = (int (*)(void *))virtio_free,
688 };
689
690
691 static int virtio_tx_flush(void * args){
692     struct virtio_net_state *virtio  = (struct virtio_net_state *)args;
693
694     V3_Print("Virtio TX Poll Thread Starting for %s\n", virtio->vm->name);
695
696     while(1){
697         if(virtio->tx_notify == 0){
698             handle_pkt_tx(&(virtio->vm->cores[0]), virtio);
699             v3_yield(NULL);
700         }else {
701             V3_THREAD_SLEEP();
702         }
703     }
704
705     return 0;
706 }
707
708 static int register_dev(struct virtio_dev_state * virtio, 
709                         struct virtio_net_state * net_state) 
710 {
711     struct pci_device * pci_dev = NULL;
712     struct v3_pci_bar bars[6];
713     int num_ports = sizeof(struct virtio_config);
714     int tmp_ports = num_ports;
715     int i;
716
717     // This gets the number of ports, rounded up to a power of 2
718     net_state->io_range_size = 1; // must be a power of 2
719     while (tmp_ports > 0) {
720         tmp_ports >>= 1;
721         net_state->io_range_size <<= 1;
722     }
723         
724     /* this is to account for any low order bits being set in num_ports
725       * if there are none, then num_ports was already a power of 2 so we shift right to reset it
726       */
727     if ((num_ports & ((net_state->io_range_size >> 1) - 1)) == 0) {
728         net_state->io_range_size >>= 1;
729     }
730     
731     for (i = 0; i < 6; i++) {
732         bars[i].type = PCI_BAR_NONE;
733     }
734     
735     PrintDebug("Virtio-NIC io_range_size = %d\n", net_state->io_range_size);
736     
737     bars[0].type = PCI_BAR_IO;
738     bars[0].default_base_port = -1;
739     bars[0].num_ports = net_state->io_range_size;
740     bars[0].io_read = virtio_io_read;
741     bars[0].io_write = virtio_io_write;
742     bars[0].private_data = net_state;
743     
744     pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE, 
745                                      0, 4/*PCI_AUTO_DEV_NUM*/, 0,
746                                      "LNX_VIRTIO_NIC", bars,
747                                      NULL, NULL, NULL, net_state);
748     
749     if (!pci_dev) {
750         PrintError("Virtio NIC: Could not register PCI Device\n");
751         return -1;
752     }
753
754     PrintDebug("Virtio NIC:  registered to PCI bus\n");
755     
756     pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
757     pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
758         
759
760     pci_dev->config_header.device_id = VIRTIO_NET_DEV_ID;
761     pci_dev->config_header.class = PCI_CLASS_NETWORK;
762     pci_dev->config_header.subclass = PCI_NET_SUBCLASS_OTHER;  
763     pci_dev->config_header.subsystem_id = VIRTIO_NET_SUBDEVICE_ID;
764     pci_dev->config_header.intr_pin = 1;
765     pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
766
767     net_state->pci_dev = pci_dev;
768     net_state->virtio_dev = virtio;
769
770     memcpy(net_state->net_cfg.mac, virtio->mac, 6);                           
771         
772     virtio_init_state(net_state);
773
774     /* Add backend to list of devices */
775     list_add(&(net_state->dev_link), &(virtio->dev_list));
776
777     return 0;
778 }
779
780 #define RATE_UPPER_THRESHOLD 10  /* 10000 pkts per second, around 100Mbits */
781 #define RATE_LOWER_THRESHOLD 1
782 #define PROFILE_PERIOD 10000 /*us*/
783
784 static void virtio_nic_timer(struct guest_info * core, 
785                              uint64_t cpu_cycles, uint64_t cpu_freq, 
786                              void * priv_data) {
787     struct virtio_net_state * net_state = (struct virtio_net_state *)priv_data;
788     uint64_t period_us;
789     static int profile_ms = 0;
790
791     period_us = (1000*cpu_cycles)/cpu_freq;
792     net_state->past_us += period_us;
793
794 #if 0
795     if(net_state->past_us > PROFILE_PERIOD){ 
796         uint32_t tx_rate, rx_rate;
797         
798         tx_rate = (net_state->stats.tx_pkts - net_state->tx_pkts)/(net_state->past_us/1000); /* pkts/per ms */
799         rx_rate = (net_state->stats.rx_pkts - net_state->rx_pkts)/(net_state->past_us/1000);
800
801         net_state->tx_pkts = net_state->stats.tx_pkts;
802         net_state->rx_pkts = net_state->stats.rx_pkts;
803
804         if(tx_rate > RATE_UPPER_THRESHOLD && net_state->tx_notify == 1){
805             V3_Print("Virtio NIC: Switch TX to VMM driven mode\n");
806             disable_cb(&(net_state->tx_vq));
807             net_state->tx_notify = 0;
808             V3_THREAD_WAKEUP(net_state->poll_thread);
809         }
810
811         if(tx_rate < RATE_LOWER_THRESHOLD && net_state->tx_notify == 0){
812             V3_Print("Virtio NIC: Switch TX to Guest  driven mode\n");
813             enable_cb(&(net_state->tx_vq));
814             net_state->tx_notify = 1;
815         }
816
817         if(rx_rate > RATE_UPPER_THRESHOLD && net_state->rx_notify == 1){
818             V3_Print("Virtio NIC: Switch RX to VMM None notify mode\n");
819             net_state->rx_notify = 0;
820         }
821
822         if(rx_rate < RATE_LOWER_THRESHOLD && net_state->rx_notify == 0){
823             V3_Print("Virtio NIC: Switch RX to VMM notify mode\n");
824             net_state->rx_notify = 1;
825         }
826
827         net_state->past_us = 0;
828     }
829 #endif
830
831     profile_ms += period_us/1000;
832     if(profile_ms > 20000){
833         V3_Net_Print(1, "Virtio NIC: TX: Pkt: %lld, Bytes: %lld\n\t\tRX Pkt: %lld. Bytes: %lld\n\t\tDropped: tx %lld, rx %lld\nInterrupts: tx %d, rx %d\nTotal Exit: %lld\n",
834                 net_state->stats.tx_pkts, net_state->stats.tx_bytes,
835                 net_state->stats.rx_pkts, net_state->stats.rx_bytes,
836                 net_state->stats.tx_dropped, net_state->stats.rx_dropped,
837                 net_state->stats.tx_interrupts, net_state->stats.rx_interrupts,
838                 net_state->vm->cores[0].num_exits);
839         profile_ms = 0;
840     }
841 }
842
843 static struct v3_timer_ops timer_ops = {
844     .update_timer = virtio_nic_timer,
845 };
846
847
848 static int connect_fn(struct v3_vm_info * info, 
849                       void * frontend_data, 
850                       struct v3_dev_net_ops * ops, 
851                       v3_cfg_tree_t * cfg, 
852                       void * private_data) {
853     struct virtio_dev_state * virtio = (struct virtio_dev_state *)frontend_data;
854     struct virtio_net_state * net_state  = (struct virtio_net_state *)V3_Malloc(sizeof(struct virtio_net_state));
855
856     memset(net_state, 0, sizeof(struct virtio_net_state));
857     register_dev(virtio, net_state);
858
859     net_state->vm = info;
860     net_state->net_ops = ops;
861     net_state->backend_data = private_data;
862     net_state->virtio_dev = virtio;
863     net_state->tx_notify = 0;
864     net_state->rx_notify = 0;
865         
866     net_state->timer = v3_add_timer(&(info->cores[0]),&timer_ops,net_state);
867
868     ops->recv = virtio_rx;
869     ops->frontend_data = net_state;
870     memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN);
871
872     net_state->poll_thread = V3_CREATE_THREAD(virtio_tx_flush, (void *)net_state, "Virtio_Poll");
873
874     return 0;
875 }
876
877 static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
878     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
879     struct virtio_dev_state * virtio_state = NULL;
880     char * dev_id = v3_cfg_val(cfg, "ID");
881     char macstr[128];
882     char * str = v3_cfg_val(cfg, "mac");
883     memcpy(macstr, str, strlen(str));
884
885     if (pci_bus == NULL) {
886         PrintError("Virtio NIC: VirtIO devices require a PCI Bus");
887         return -1;
888     }
889
890     virtio_state  = (struct virtio_dev_state *)V3_Malloc(sizeof(struct virtio_dev_state));
891     memset(virtio_state, 0, sizeof(struct virtio_dev_state));
892
893     INIT_LIST_HEAD(&(virtio_state->dev_list));
894     virtio_state->pci_bus = pci_bus;
895     virtio_state->vm = vm;
896
897     if (macstr != NULL && !str2mac(macstr, virtio_state->mac)) {
898         PrintDebug("Virtio NIC: Mac specified %s\n", macstr);
899     }else {
900         random_ethaddr(virtio_state->mac);
901     }
902
903     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
904
905     if (dev == NULL) {
906         PrintError("Virtio NIC: Could not attach device %s\n", dev_id);
907         V3_Free(virtio_state);
908         return -1;
909     }
910
911     if (v3_dev_add_net_frontend(vm, dev_id, connect_fn, (void *)virtio_state) == -1) {
912         PrintError("Virtio NIC: Could not register %s as net frontend\n", dev_id);
913         v3_remove_device(dev);
914         return -1;
915     }
916         
917     return 0;
918 }
919
920 device_register("LNX_VIRTIO_NIC", virtio_init)
921