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.


Updates to VNET. Most importantly, better yielding in the transmit kick threads and...
[palacios.git] / palacios / src / vnet / vnet_core.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) 2009, Yuan Tang <ytang@northwestern.edu>  
12  * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved
14  *
15  * Author: Lei Xia <lxia@northwestern.edu>
16  *         Yuan Tang <ytang@northwestern.edu>
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21  
22 #include <vnet/vnet.h>
23 #include <vnet/vnet_hashtable.h>
24 #include <vnet/vnet_host.h>
25 #include <vnet/vnet_vmm.h>
26
27 #include <palacios/vmm_queue.h>
28
29 #ifndef V3_CONFIG_DEBUG_VNET
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34 #define VNET_YIELD_USEC 1000
35
36 int net_debug = 0;
37
38 struct eth_hdr {
39     uint8_t dst_mac[ETH_ALEN];
40     uint8_t src_mac[ETH_ALEN];
41     uint16_t type; /* indicates layer 3 protocol type */
42 } __attribute__((packed));
43
44
45 struct vnet_dev {
46     int dev_id;
47     uint8_t mac_addr[ETH_ALEN];
48     struct v3_vm_info * vm;
49     struct v3_vnet_dev_ops dev_ops;
50
51     int poll;
52
53 #define VNET_MAX_QUOTE 64
54     int quote;
55         
56     void * private_data;
57
58     struct list_head node;
59 } __attribute__((packed));
60
61
62 struct vnet_brg_dev {
63     struct v3_vm_info * vm;
64     struct v3_vnet_bridge_ops brg_ops;
65
66     uint8_t type;
67
68     void * private_data;
69 } __attribute__((packed));
70
71
72
73 struct vnet_route_info {
74     struct v3_vnet_route route_def;
75
76     struct vnet_dev * dst_dev;
77     struct vnet_dev * src_dev;
78
79     uint32_t idx;
80
81     struct list_head node;
82     struct list_head match_node; // used for route matching
83 };
84
85
86 struct route_list {
87     uint8_t hash_buf[VNET_HASH_SIZE];
88
89     uint32_t num_routes;
90     struct vnet_route_info * routes[0];
91 } __attribute__((packed));
92
93
94 struct queue_entry{
95     uint8_t use;
96     struct v3_vnet_pkt pkt;
97     uint8_t * data;
98     uint32_t size_alloc;
99 };
100
101
102 static struct {
103     struct list_head routes;
104     struct list_head devs;
105
106     uint8_t status; 
107    
108     uint32_t num_routes;
109     uint32_t route_idx;
110     uint32_t num_devs;
111     uint32_t dev_idx;
112
113     struct vnet_brg_dev * bridge;
114
115     vnet_lock_t lock;
116     struct vnet_stat stats;
117
118    /* device queue that are waiting to be polled */
119     struct v3_queue * poll_devs;
120
121     struct vnet_thread * pkt_flush_thread;
122
123     struct hashtable * route_cache;
124 } vnet_state;
125         
126
127 #ifdef V3_CONFIG_DEBUG_VNET
128 static inline void mac2str(uint8_t * mac, char * buf) {
129     snprintf(buf, 100, "%2x:%2x:%2x:%2x:%2x:%2x", 
130              mac[0], mac[1], mac[2],
131              mac[3], mac[4], mac[5]);
132 }
133
134 static void print_route(struct v3_vnet_route * route){
135     char str[50];
136
137     mac2str(route->src_mac, str);
138     PrintDebug("Src Mac (%s),  src_qual (%d)\n", 
139                str, route->src_mac_qual);
140     mac2str(route->dst_mac, str);
141     PrintDebug("Dst Mac (%s),  dst_qual (%d)\n", 
142                str, route->dst_mac_qual);
143     PrintDebug("Src dev id (%d), src type (%d)", 
144                route->src_id, 
145                route->src_type);
146     PrintDebug("Dst dev id (%d), dst type (%d)\n", 
147                route->dst_id, 
148                route->dst_type);
149 }
150
151 static void dump_routes(){
152     struct vnet_route_info *route;
153
154     PrintDebug("\n========Dump routes starts ============\n");
155     list_for_each_entry(route, &(vnet_state.routes), node) {
156         PrintDebug("\nroute %d:\n", route->idx);
157                 
158         print_route(&(route->route_def));
159         if (route->route_def.dst_type == LINK_INTERFACE) {
160             PrintDebug("dst_dev (%p), dst_dev_id (%d), dst_dev_ops(%p), dst_dev_data (%p)\n",
161                 route->dst_dev,
162                 route->dst_dev->dev_id,
163                 (void *)&(route->dst_dev->dev_ops),
164                 route->dst_dev->private_data);
165         }
166     }
167
168     PrintDebug("\n========Dump routes end ============\n");
169 }
170
171 #endif
172
173
174 /* 
175  * A VNET packet is a packed struct with the hashed fields grouped together.
176  * This means we can generate the hash from an offset into the pkt struct
177  */
178 static inline uint_t hash_fn(addr_t hdr_ptr) {    
179     uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
180
181     return vnet_hash_buffer(hdr_buf, VNET_HASH_SIZE);
182 }
183
184 static inline int hash_eq(addr_t key1, addr_t key2) {   
185     return (memcmp((uint8_t *)key1, (uint8_t *)key2, VNET_HASH_SIZE) == 0);
186 }
187
188 static int add_route_to_cache(const struct v3_vnet_pkt * pkt, struct route_list * routes) {
189     memcpy(routes->hash_buf, pkt->hash_buf, VNET_HASH_SIZE);    
190
191     if (vnet_htable_insert(vnet_state.route_cache, (addr_t)routes->hash_buf, (addr_t)routes) == 0) {
192         PrintError("VNET/P Core: Failed to insert new route entry to the cache\n");
193         return -1;
194     }
195     
196     return 0;
197 }
198
199 static int clear_hash_cache() {
200     vnet_free_htable(vnet_state.route_cache, 1, 1);
201     vnet_state.route_cache = vnet_create_htable(0, &hash_fn, &hash_eq);
202
203     return 0;
204 }
205
206 static int look_into_cache(const struct v3_vnet_pkt * pkt, 
207                            struct route_list ** routes) {
208     *routes = (struct route_list *)vnet_htable_search(vnet_state.route_cache, (addr_t)(pkt->hash_buf));
209    
210     return 0;
211 }
212
213
214 static struct vnet_dev * dev_by_id(int idx) {
215     struct vnet_dev * dev = NULL; 
216
217     list_for_each_entry(dev, &(vnet_state.devs), node) {
218         if (dev->dev_id == idx) {
219             return dev;
220         }
221     }
222
223     return NULL;
224 }
225
226 static struct vnet_dev * dev_by_mac(uint8_t * mac) {
227     struct vnet_dev * dev = NULL; 
228     
229     list_for_each_entry(dev, &(vnet_state.devs), node) {
230         if (!compare_ethaddr(dev->mac_addr, mac)){
231             return dev;
232         }
233     }
234
235     return NULL;
236 }
237
238
239 int v3_vnet_find_dev(uint8_t  * mac) {
240     struct vnet_dev * dev = NULL;
241
242     dev = dev_by_mac(mac);
243
244     if(dev != NULL) {
245         return dev->dev_id;
246     }
247
248     return -1;
249 }
250
251
252 int v3_vnet_add_route(struct v3_vnet_route route) {
253     struct vnet_route_info * new_route = NULL;
254     unsigned long flags; 
255
256     new_route = (struct vnet_route_info *)Vnet_Malloc(sizeof(struct vnet_route_info));
257     memset(new_route, 0, sizeof(struct vnet_route_info));
258
259 #ifdef V3_CONFIG_DEBUG_VNET
260     PrintDebug("VNET/P Core: add_route_entry:\n");
261     print_route(&route);
262 #endif
263     
264     memcpy(new_route->route_def.src_mac, route.src_mac, ETH_ALEN);
265     memcpy(new_route->route_def.dst_mac, route.dst_mac, ETH_ALEN);
266     new_route->route_def.src_mac_qual = route.src_mac_qual;
267     new_route->route_def.dst_mac_qual = route.dst_mac_qual;
268     new_route->route_def.dst_type = route.dst_type;
269     new_route->route_def.src_type = route.src_type;
270     new_route->route_def.src_id = route.src_id;
271     new_route->route_def.dst_id = route.dst_id;
272
273     if (new_route->route_def.dst_type == LINK_INTERFACE) {
274         new_route->dst_dev = dev_by_id(new_route->route_def.dst_id);
275     }
276
277     if (new_route->route_def.src_type == LINK_INTERFACE) {
278         new_route->src_dev = dev_by_id(new_route->route_def.src_id);
279     }
280
281
282     flags = vnet_lock_irqsave(vnet_state.lock);
283
284     list_add(&(new_route->node), &(vnet_state.routes));
285     new_route->idx = ++ vnet_state.route_idx;
286     vnet_state.num_routes ++;
287         
288     vnet_unlock_irqrestore(vnet_state.lock, flags);
289
290     clear_hash_cache();
291
292 #ifdef V3_CONFIG_DEBUG_VNET
293     dump_routes();
294 #endif
295
296     return new_route->idx;
297 }
298
299
300 void v3_vnet_del_route(uint32_t route_idx){
301     struct vnet_route_info * route = NULL;
302     unsigned long flags; 
303
304     flags = vnet_lock_irqsave(vnet_state.lock);
305
306     list_for_each_entry(route, &(vnet_state.routes), node) {
307         Vnet_Print(0, "v3_vnet_del_route, route idx: %d\n", route->idx);
308         if(route->idx == route_idx){
309             list_del(&(route->node));
310             Vnet_Free(route);
311             break;    
312         }
313     }
314
315     vnet_unlock_irqrestore(vnet_state.lock, flags);
316     clear_hash_cache();
317
318 #ifdef V3_CONFIG_DEBUG_VNET
319     dump_routes();
320 #endif  
321 }
322
323
324 /* delete all route entries with specfied src or dst device id */ 
325 static void inline del_routes_by_dev(int dev_id){
326     struct vnet_route_info * route, *tmp_route;
327     unsigned long flags; 
328
329     flags = vnet_lock_irqsave(vnet_state.lock);
330
331     list_for_each_entry_safe(route, tmp_route, &(vnet_state.routes), node) {
332         if((route->route_def.dst_type == LINK_INTERFACE &&
333              route->route_def.dst_id == dev_id) ||
334              (route->route_def.src_type == LINK_INTERFACE &&
335               route->route_def.src_id == dev_id)){
336               
337             list_del(&(route->node));
338             list_del(&(route->match_node));
339             Vnet_Free(route);    
340         }
341     }
342
343     vnet_unlock_irqrestore(vnet_state.lock, flags);
344 }
345
346 /* At the end allocate a route_list
347  * This list will be inserted into the cache so we don't need to free it
348  */
349 static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
350     struct vnet_route_info * route = NULL; 
351     struct route_list * matches = NULL;
352     int num_matches = 0;
353     int max_rank = 0;
354     struct list_head match_list;
355     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
356     //  uint8_t src_type = pkt->src_type;
357     //  uint32_t src_link = pkt->src_id;
358
359 #ifdef V3_CONFIG_DEBUG_VNET
360     {
361         char dst_str[100];
362         char src_str[100];
363
364         mac2str(hdr->src_mac, src_str);  
365         mac2str(hdr->dst_mac, dst_str);
366         PrintDebug("VNET/P Core: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
367     }
368 #endif
369
370     INIT_LIST_HEAD(&match_list);
371     
372 #define UPDATE_MATCHES(rank) do {                               \
373         if (max_rank < (rank)) {                                \
374             max_rank = (rank);                                  \
375             INIT_LIST_HEAD(&match_list);                        \
376                                                                 \
377             list_add(&(route->match_node), &match_list);        \
378             num_matches = 1;                                    \
379         } else if (max_rank == (rank)) {                        \
380             list_add(&(route->match_node), &match_list);        \
381             num_matches++;                                      \
382         }                                                       \
383     } while (0)
384     
385
386     list_for_each_entry(route, &(vnet_state.routes), node) {
387         struct v3_vnet_route * route_def = &(route->route_def);
388
389 /*
390         // CHECK SOURCE TYPE HERE
391         if ( (route_def->src_type != LINK_ANY) && 
392              ( (route_def->src_type != src_type) || 
393                ( (route_def->src_id != src_link) &&
394                  (route_def->src_id != -1)))) {
395             continue;
396         }
397 */
398
399         if ((route_def->dst_mac_qual == MAC_ANY) &&
400             (route_def->src_mac_qual == MAC_ANY)) {      
401             UPDATE_MATCHES(3);
402         }
403         
404         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
405             if (route_def->src_mac_qual != MAC_NOT) {
406                 if (route_def->dst_mac_qual == MAC_ANY) {
407                     UPDATE_MATCHES(6);
408                 } else if (route_def->dst_mac_qual != MAC_NOT &&
409                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
410                     UPDATE_MATCHES(8);
411                 }
412             }
413         }
414             
415         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
416             if (route_def->dst_mac_qual != MAC_NOT) {
417                 if (route_def->src_mac_qual == MAC_ANY) {
418                     UPDATE_MATCHES(6);
419                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
420                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
421                     UPDATE_MATCHES(8);
422                 }
423             }
424         }
425             
426         if ((route_def->dst_mac_qual == MAC_NOT) &&
427             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
428             if (route_def->src_mac_qual == MAC_ANY) {
429                 UPDATE_MATCHES(5);
430             } else if ((route_def->src_mac_qual != MAC_NOT) && 
431                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
432                 UPDATE_MATCHES(7);
433             }
434         }
435         
436         if ((route_def->src_mac_qual == MAC_NOT) &&
437             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
438             if (route_def->dst_mac_qual == MAC_ANY) {
439                 UPDATE_MATCHES(5);
440             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
441                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
442                 UPDATE_MATCHES(7);
443             }
444         }
445         
446         // Default route
447         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &&
448              (route_def->dst_mac_qual == MAC_NONE)) {
449             UPDATE_MATCHES(4);
450         }
451     }
452
453     PrintDebug("VNET/P Core: match_route: Matches=%d\n", num_matches);
454
455     if (num_matches == 0) {
456         return NULL;
457     }
458
459     matches = (struct route_list *)Vnet_Malloc(sizeof(struct route_list) + 
460                                                (sizeof(struct vnet_route_info *) * num_matches));
461
462     matches->num_routes = num_matches;
463
464     {
465         int i = 0;
466         list_for_each_entry(route, &match_list, match_node) {
467             matches->routes[i++] = route;
468         }
469     }
470
471     return matches;
472 }
473
474
475 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
476     struct route_list * matched_routes = NULL;
477     unsigned long flags;
478     int i;
479
480     int cpu = V3_Get_CPU();
481     Vnet_Print(2, "VNET/P Core: cpu %d: pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n",
482                cpu, pkt->size, pkt->src_id, 
483                pkt->src_type, pkt->dst_id, pkt->dst_type);
484     if(net_debug >= 4){
485         v3_hexdump(pkt->data, pkt->size, NULL, 0);
486     }
487
488     flags = vnet_lock_irqsave(vnet_state.lock);
489
490     vnet_state.stats.rx_bytes += pkt->size;
491     vnet_state.stats.rx_pkts++;
492
493     look_into_cache(pkt, &matched_routes);
494     if (matched_routes == NULL) {  
495         PrintDebug("VNET/P Core: send pkt Looking into routing table\n");
496         
497         matched_routes = match_route(pkt);
498         
499         if (matched_routes) {
500             add_route_to_cache(pkt, matched_routes);
501         } else {
502             PrintDebug("VNET/P Core: Could not find route for packet... discards packet\n");
503             vnet_unlock_irqrestore(vnet_state.lock, flags);
504             return 0; /* do we return -1 here?*/
505         }
506     }
507
508     vnet_unlock_irqrestore(vnet_state.lock, flags);
509
510     PrintDebug("VNET/P Core: send pkt route matches %d\n", matched_routes->num_routes);
511
512     for (i = 0; i < matched_routes->num_routes; i++) {
513         struct vnet_route_info * route = matched_routes->routes[i];
514         
515         if (route->route_def.dst_type == LINK_EDGE) {
516             struct vnet_brg_dev * bridge = vnet_state.bridge;
517             pkt->dst_type = LINK_EDGE;
518             pkt->dst_id = route->route_def.dst_id;
519
520             if (bridge == NULL) {
521                 Vnet_Print(2, "VNET/P Core: No active bridge to sent data to\n");
522                 continue;
523             }
524
525             if(bridge->brg_ops.input(bridge->vm, pkt, bridge->private_data) < 0){
526                 Vnet_Print(2, "VNET/P Core: Packet not sent properly to bridge\n");
527                 continue;
528             }         
529             vnet_state.stats.tx_bytes += pkt->size;
530             vnet_state.stats.tx_pkts ++;
531         } else if (route->route_def.dst_type == LINK_INTERFACE) {
532             if (route->dst_dev == NULL){
533                   Vnet_Print(2, "VNET/P Core: No active device to sent data to\n");
534                 continue;
535             }
536
537             if(route->dst_dev->dev_ops.input(route->dst_dev->vm, pkt, route->dst_dev->private_data) < 0) {
538                 Vnet_Print(2, "VNET/P Core: Packet not sent properly\n");
539                 continue;
540             }
541             vnet_state.stats.tx_bytes += pkt->size;
542             vnet_state.stats.tx_pkts ++;
543         } else {
544             Vnet_Print(0, "VNET/P Core: Wrong dst type\n");
545         }
546     }
547     
548     return 0;
549 }
550
551
552 int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, 
553                     struct v3_vnet_dev_ops * ops, int quote, int poll_state,
554                     void * priv_data){
555     struct vnet_dev * new_dev = NULL;
556     unsigned long flags;
557
558     new_dev = (struct vnet_dev *)Vnet_Malloc(sizeof(struct vnet_dev)); 
559
560     if (new_dev == NULL) {
561         Vnet_Print(0, "Malloc fails\n");
562         return -1;
563     }
564    
565     memcpy(new_dev->mac_addr, mac, 6);
566     new_dev->dev_ops.input = ops->input;
567     new_dev->dev_ops.poll = ops->poll;
568     new_dev->private_data = priv_data;
569     new_dev->vm = vm;
570     new_dev->dev_id = 0;
571     new_dev->quote = quote<VNET_MAX_QUOTE?quote:VNET_MAX_QUOTE;
572     new_dev->poll = poll_state;
573
574     flags = vnet_lock_irqsave(vnet_state.lock);
575
576     if (dev_by_mac(mac) == NULL) {
577         list_add(&(new_dev->node), &(vnet_state.devs));
578         new_dev->dev_id = ++ vnet_state.dev_idx;
579         vnet_state.num_devs ++;
580
581         if(new_dev->poll) {
582             v3_enqueue(vnet_state.poll_devs, (addr_t)new_dev);
583         }
584     } else {
585         PrintError("VNET/P: Device with the same MAC is already there\n");
586     }
587
588     vnet_unlock_irqrestore(vnet_state.lock, flags);
589
590     /* if the device was found previosly the id should still be 0 */
591     if (new_dev->dev_id == 0) {
592         Vnet_Print(0, "VNET/P Core: Device Already exists\n");
593         return -1;
594     }
595
596     PrintDebug("VNET/P Core: Add Device: dev_id %d\n", new_dev->dev_id);
597
598     return new_dev->dev_id;
599 }
600
601
602 int v3_vnet_del_dev(int dev_id){
603     struct vnet_dev * dev = NULL;
604     unsigned long flags;
605
606     flags = vnet_lock_irqsave(vnet_state.lock);
607         
608     dev = dev_by_id(dev_id);
609     if (dev != NULL){
610         list_del(&(dev->node));
611         //del_routes_by_dev(dev_id);
612         vnet_state.num_devs --;
613     }
614         
615     vnet_unlock_irqrestore(vnet_state.lock, flags);
616
617     Vnet_Free(dev);
618
619     PrintDebug("VNET/P Core: Remove Device: dev_id %d\n", dev_id);
620
621     return 0;
622 }
623
624
625 int v3_vnet_stat(struct vnet_stat * stats){
626     stats->rx_bytes = vnet_state.stats.rx_bytes;
627     stats->rx_pkts = vnet_state.stats.rx_pkts;
628     stats->tx_bytes = vnet_state.stats.tx_bytes;
629     stats->tx_pkts = vnet_state.stats.tx_pkts;
630
631     return 0;
632 }
633
634 static void deinit_devices_list(){
635     struct vnet_dev * dev, * tmp; 
636
637     list_for_each_entry_safe(dev, tmp, &(vnet_state.devs), node) {
638         list_del(&(dev->node));
639         Vnet_Free(dev);
640     }
641 }
642
643 static void deinit_routes_list(){
644     struct vnet_route_info * route, * tmp; 
645
646     list_for_each_entry_safe(route, tmp, &(vnet_state.routes), node) {
647         list_del(&(route->node));
648         list_del(&(route->match_node));
649         Vnet_Free(route);
650     }
651 }
652
653 int v3_vnet_add_bridge(struct v3_vm_info * vm,
654                        struct v3_vnet_bridge_ops * ops,
655                        uint8_t type,
656                        void * priv_data) {
657     unsigned long flags;
658     int bridge_free = 0;
659     struct vnet_brg_dev * tmp_bridge = NULL;    
660     
661     flags = vnet_lock_irqsave(vnet_state.lock);
662     if (vnet_state.bridge == NULL) {
663         bridge_free = 1;
664         vnet_state.bridge = (void *)1;
665     }
666     vnet_unlock_irqrestore(vnet_state.lock, flags);
667
668     if (bridge_free == 0) {
669         PrintError("VNET/P Core: Bridge already set\n");
670         return -1;
671     }
672
673     tmp_bridge = (struct vnet_brg_dev *)Vnet_Malloc(sizeof(struct vnet_brg_dev));
674
675     if (tmp_bridge == NULL) {
676         PrintError("Malloc Fails\n");
677         vnet_state.bridge = NULL;
678         return -1;
679     }
680     
681     tmp_bridge->vm = vm;
682     tmp_bridge->brg_ops.input = ops->input;
683     tmp_bridge->brg_ops.poll = ops->poll;
684     tmp_bridge->private_data = priv_data;
685     tmp_bridge->type = type;
686         
687     /* make this atomic to avoid possible race conditions */
688     flags = vnet_lock_irqsave(vnet_state.lock);
689     vnet_state.bridge = tmp_bridge;
690     vnet_unlock_irqrestore(vnet_state.lock, flags);
691
692     return 0;
693 }
694
695
696 void v3_vnet_del_bridge(uint8_t type) {
697     unsigned long flags;
698     struct vnet_brg_dev * tmp_bridge = NULL;    
699     
700     flags = vnet_lock_irqsave(vnet_state.lock);
701         
702     if (vnet_state.bridge != NULL && vnet_state.bridge->type == type) {
703         tmp_bridge = vnet_state.bridge;
704        vnet_state.bridge = NULL;
705     }
706         
707     vnet_unlock_irqrestore(vnet_state.lock, flags);
708
709     if (tmp_bridge) {
710         Vnet_Free(tmp_bridge);
711     }
712 }
713
714
715 /* can be instanieoued to multiple threads
716   * that runs on multiple cores 
717   * or it could be running on a dedicated side core
718   */
719 static int vnet_tx_flush(void * args){
720     struct vnet_dev * dev = NULL;
721     int more;
722     int rc;
723
724     Vnet_Print(0, "VNET/P Polling Thread Starting ....\n");
725
726     // since there are multiple instances of this thread, and only
727     // one queue of pollable devices, our model here will be to synchronize
728     // on that queue, removing devices as we go, and keeping them
729     // then putting them back on the queue when we are done
730     // in this way, multiple instances of this function will never
731     // be polling the same device at the same time
732
733     struct v3_queue * tq = v3_create_queue();
734
735     if (!tq) { 
736         PrintError("VNET/P polling thread cannot allocate queue\n");
737         return -1;
738     }
739
740
741     while (!vnet_thread_should_stop()) {
742
743         more=0; // will indicate if any device has more work for us to do
744
745         while ((dev = (struct vnet_dev *)v3_dequeue(vnet_state.poll_devs))) { 
746             // we are handling this device
747             v3_enqueue(tq,(addr_t)dev);
748             
749             if (dev->poll && dev->dev_ops.poll) {
750                 // The device's poll function MUST NOT BLOCK
751                 rc = dev->dev_ops.poll(dev->vm, dev->quote, dev->private_data);
752
753                 if (rc<0) { 
754                     Vnet_Print(0, "VNET/P: poll from device %p error (ignoring) !\n", dev);
755                 } else {
756                     more |= rc;  
757                 }
758             }
759         }
760         
761         while ((dev = (struct vnet_dev *)v3_dequeue(tq))) { 
762             // now someone else can handle it
763             v3_enqueue(vnet_state.poll_devs, (addr_t)dev); 
764         }
765
766         // Yield regardless of whether we handled any devices - need
767         // to allow other threads to run
768         if (more) { 
769             // we have more to do, so we want to get back asap
770             V3_Yield();
771         } else {
772             // put ourselves briefly to sleep if we we don't have more
773             V3_Yield_Timed(VNET_YIELD_USEC);
774         }
775
776     }
777     
778     Vnet_Print(0, "VNET/P Polling Thread Done.\n");
779
780     return 0;
781 }
782
783 int v3_init_vnet() {
784     memset(&vnet_state, 0, sizeof(vnet_state));
785         
786     INIT_LIST_HEAD(&(vnet_state.routes));
787     INIT_LIST_HEAD(&(vnet_state.devs));
788
789     vnet_state.num_devs = 0;
790     vnet_state.num_routes = 0;
791
792     if (vnet_lock_init(&(vnet_state.lock)) == -1){
793         PrintError("VNET/P: Fails to initiate lock\n");
794     }
795
796     vnet_state.route_cache = vnet_create_htable(0, &hash_fn, &hash_eq);
797     if (vnet_state.route_cache == NULL) {
798         PrintError("VNET/P: Fails to initiate route cache\n");
799         return -1;
800     }
801
802     vnet_state.poll_devs = v3_create_queue();
803
804     vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "vnetd-1");
805
806     PrintDebug("VNET/P is initiated\n");
807
808     return 0;
809 }
810
811
812 void v3_deinit_vnet(){
813
814     PrintDebug("Stopping flush thread\n");
815     // This will pause until the flush thread is gone
816     vnet_thread_stop(vnet_state.pkt_flush_thread);
817     // At this point there should be no lock-holder
818
819     PrintDebug("Deiniting Device List\n");
820     // close any devices we have open
821     deinit_devices_list();  
822     
823     PrintDebug("Deiniting Route List\n");
824     // remove any routes we have
825     deinit_routes_list();
826
827     PrintDebug("Freeing hash table\n");
828     // remove the hash table
829     vnet_free_htable(vnet_state.route_cache, 1, 1);
830
831     
832     PrintDebug("Removing Bridge\n");
833     // remove bridge if it was added
834     if (vnet_state.bridge) { 
835         Vnet_Free(vnet_state.bridge);
836     }
837
838     PrintDebug("Deleting lock\n");
839     // eliminate the lock
840     vnet_lock_deinit(&(vnet_state.lock));
841
842 }
843
844