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.


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