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.


c2ebaf0b2a0694896233ea4bbad4c73541491108
[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
258     if (!new_route) {
259         PrintError("Cannot allocate new route\n");
260         return -1;
261     }
262
263     memset(new_route, 0, sizeof(struct vnet_route_info));
264
265 #ifdef V3_CONFIG_DEBUG_VNET
266     PrintDebug("VNET/P Core: add_route_entry:\n");
267     print_route(&route);
268 #endif
269     
270     memcpy(new_route->route_def.src_mac, route.src_mac, ETH_ALEN);
271     memcpy(new_route->route_def.dst_mac, route.dst_mac, ETH_ALEN);
272     new_route->route_def.src_mac_qual = route.src_mac_qual;
273     new_route->route_def.dst_mac_qual = route.dst_mac_qual;
274     new_route->route_def.dst_type = route.dst_type;
275     new_route->route_def.src_type = route.src_type;
276     new_route->route_def.src_id = route.src_id;
277     new_route->route_def.dst_id = route.dst_id;
278
279     if (new_route->route_def.dst_type == LINK_INTERFACE) {
280         new_route->dst_dev = dev_by_id(new_route->route_def.dst_id);
281     }
282
283     if (new_route->route_def.src_type == LINK_INTERFACE) {
284         new_route->src_dev = dev_by_id(new_route->route_def.src_id);
285     }
286
287
288     flags = vnet_lock_irqsave(vnet_state.lock);
289
290     list_add(&(new_route->node), &(vnet_state.routes));
291     new_route->idx = ++ vnet_state.route_idx;
292     vnet_state.num_routes ++;
293         
294     vnet_unlock_irqrestore(vnet_state.lock, flags);
295
296     clear_hash_cache();
297
298 #ifdef V3_CONFIG_DEBUG_VNET
299     dump_routes();
300 #endif
301
302     return new_route->idx;
303 }
304
305
306 void v3_vnet_del_route(uint32_t route_idx){
307     struct vnet_route_info * route = NULL;
308     unsigned long flags; 
309
310     flags = vnet_lock_irqsave(vnet_state.lock);
311
312     list_for_each_entry(route, &(vnet_state.routes), node) {
313         Vnet_Print(0, "v3_vnet_del_route, route idx: %d\n", route->idx);
314         if(route->idx == route_idx){
315             list_del(&(route->node));
316             Vnet_Free(route);
317             break;    
318         }
319     }
320
321     vnet_unlock_irqrestore(vnet_state.lock, flags);
322     clear_hash_cache();
323
324 #ifdef V3_CONFIG_DEBUG_VNET
325     dump_routes();
326 #endif  
327 }
328
329
330 /* delete all route entries with specfied src or dst device id */ 
331 static void inline del_routes_by_dev(int dev_id){
332     struct vnet_route_info * route, *tmp_route;
333     unsigned long flags; 
334
335     flags = vnet_lock_irqsave(vnet_state.lock);
336
337     list_for_each_entry_safe(route, tmp_route, &(vnet_state.routes), node) {
338         if((route->route_def.dst_type == LINK_INTERFACE &&
339              route->route_def.dst_id == dev_id) ||
340              (route->route_def.src_type == LINK_INTERFACE &&
341               route->route_def.src_id == dev_id)){
342               
343             list_del(&(route->node));
344             list_del(&(route->match_node));
345             Vnet_Free(route);    
346         }
347     }
348
349     vnet_unlock_irqrestore(vnet_state.lock, flags);
350 }
351
352 /* At the end allocate a route_list
353  * This list will be inserted into the cache so we don't need to free it
354  */
355 static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
356     struct vnet_route_info * route = NULL; 
357     struct route_list * matches = NULL;
358     int num_matches = 0;
359     int max_rank = 0;
360     struct list_head match_list;
361     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
362     //  uint8_t src_type = pkt->src_type;
363     //  uint32_t src_link = pkt->src_id;
364
365 #ifdef V3_CONFIG_DEBUG_VNET
366     {
367         char dst_str[100];
368         char src_str[100];
369
370         mac2str(hdr->src_mac, src_str);  
371         mac2str(hdr->dst_mac, dst_str);
372         PrintDebug("VNET/P Core: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
373     }
374 #endif
375
376     INIT_LIST_HEAD(&match_list);
377     
378 #define UPDATE_MATCHES(rank) do {                               \
379         if (max_rank < (rank)) {                                \
380             max_rank = (rank);                                  \
381             INIT_LIST_HEAD(&match_list);                        \
382                                                                 \
383             list_add(&(route->match_node), &match_list);        \
384             num_matches = 1;                                    \
385         } else if (max_rank == (rank)) {                        \
386             list_add(&(route->match_node), &match_list);        \
387             num_matches++;                                      \
388         }                                                       \
389     } while (0)
390     
391
392     list_for_each_entry(route, &(vnet_state.routes), node) {
393         struct v3_vnet_route * route_def = &(route->route_def);
394
395 /*
396         // CHECK SOURCE TYPE HERE
397         if ( (route_def->src_type != LINK_ANY) && 
398              ( (route_def->src_type != src_type) || 
399                ( (route_def->src_id != src_link) &&
400                  (route_def->src_id != -1)))) {
401             continue;
402         }
403 */
404
405         if ((route_def->dst_mac_qual == MAC_ANY) &&
406             (route_def->src_mac_qual == MAC_ANY)) {      
407             UPDATE_MATCHES(3);
408         }
409         
410         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
411             if (route_def->src_mac_qual != MAC_NOT) {
412                 if (route_def->dst_mac_qual == MAC_ANY) {
413                     UPDATE_MATCHES(6);
414                 } else if (route_def->dst_mac_qual != MAC_NOT &&
415                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
416                     UPDATE_MATCHES(8);
417                 }
418             }
419         }
420             
421         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
422             if (route_def->dst_mac_qual != MAC_NOT) {
423                 if (route_def->src_mac_qual == MAC_ANY) {
424                     UPDATE_MATCHES(6);
425                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
426                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
427                     UPDATE_MATCHES(8);
428                 }
429             }
430         }
431             
432         if ((route_def->dst_mac_qual == MAC_NOT) &&
433             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
434             if (route_def->src_mac_qual == MAC_ANY) {
435                 UPDATE_MATCHES(5);
436             } else if ((route_def->src_mac_qual != MAC_NOT) && 
437                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
438                 UPDATE_MATCHES(7);
439             }
440         }
441         
442         if ((route_def->src_mac_qual == MAC_NOT) &&
443             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
444             if (route_def->dst_mac_qual == MAC_ANY) {
445                 UPDATE_MATCHES(5);
446             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
447                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
448                 UPDATE_MATCHES(7);
449             }
450         }
451         
452         // Default route
453         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &&
454              (route_def->dst_mac_qual == MAC_NONE)) {
455             UPDATE_MATCHES(4);
456         }
457     }
458
459     PrintDebug("VNET/P Core: match_route: Matches=%d\n", num_matches);
460
461     if (num_matches <= 0) {
462         return NULL;
463     }
464
465     matches = (struct route_list *)Vnet_Malloc(sizeof(struct route_list) + 
466                                                (sizeof(struct vnet_route_info *) * num_matches));
467
468
469     if (!matches) {
470         PrintError("VNET/P Core: Unable to allocate matches\n");
471         return NULL;
472     }
473
474     matches->num_routes = num_matches;
475
476     {
477         int i = 0;
478         list_for_each_entry(route, &match_list, match_node) {
479             matches->routes[i++] = route;
480         }
481     }
482
483     return matches;
484 }
485
486
487 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
488     struct route_list * matched_routes = NULL;
489     unsigned long flags;
490     int i;
491
492     int cpu = V3_Get_CPU();
493
494     Vnet_Print(2, "VNET/P Core: cpu %d: pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n",
495                cpu, pkt->size, pkt->src_id, 
496                pkt->src_type, pkt->dst_id, pkt->dst_type);
497
498     if(net_debug >= 4){
499         v3_hexdump(pkt->data, pkt->size, NULL, 0);
500     }
501
502     flags = vnet_lock_irqsave(vnet_state.lock);
503
504     vnet_state.stats.rx_bytes += pkt->size;
505     vnet_state.stats.rx_pkts++;
506
507     look_into_cache(pkt, &matched_routes);
508
509     if (matched_routes == NULL) {  
510         PrintDebug("VNET/P Core: sending pkt - matching route\n");
511         
512         matched_routes = match_route(pkt);
513         
514         if (matched_routes) {
515             add_route_to_cache(pkt, matched_routes);
516         } else {
517             PrintDebug("VNET/P Core: Could not find route for packet... discarding packet\n");
518             vnet_unlock_irqrestore(vnet_state.lock, flags);
519             return 0; /* do we return -1 here?*/
520         }
521     }
522
523     vnet_unlock_irqrestore(vnet_state.lock, flags);
524
525     PrintDebug("VNET/P Core: send pkt route matches %d\n", matched_routes->num_routes);
526
527     for (i = 0; i < matched_routes->num_routes; i++) {
528         struct vnet_route_info * route = matched_routes->routes[i];
529         
530         if (route->route_def.dst_type == LINK_EDGE) {
531             struct vnet_brg_dev * bridge = vnet_state.bridge;
532             pkt->dst_type = LINK_EDGE;
533             pkt->dst_id = route->route_def.dst_id;
534
535             if (bridge == NULL) {
536                 Vnet_Print(2, "VNET/P Core: No active bridge to sent data to\n");
537                 continue;
538             }
539
540             if(bridge->brg_ops.input(bridge->vm, pkt, bridge->private_data) < 0){
541                 Vnet_Print(2, "VNET/P Core: Packet not sent properly to bridge\n");
542                 continue;
543             }         
544             vnet_state.stats.tx_bytes += pkt->size;
545             vnet_state.stats.tx_pkts ++;
546         } else if (route->route_def.dst_type == LINK_INTERFACE) {
547             if (route->dst_dev == NULL){
548                   Vnet_Print(2, "VNET/P Core: No active device to sent data to\n");
549                 continue;
550             }
551
552             if(route->dst_dev->dev_ops.input(route->dst_dev->vm, pkt, route->dst_dev->private_data) < 0) {
553                 Vnet_Print(2, "VNET/P Core: Packet not sent properly\n");
554                 continue;
555             }
556             vnet_state.stats.tx_bytes += pkt->size;
557             vnet_state.stats.tx_pkts ++;
558         } else {
559             Vnet_Print(0, "VNET/P Core: Wrong dst type\n");
560         }
561     }
562     
563     return 0;
564 }
565
566
567 int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, 
568                     struct v3_vnet_dev_ops * ops, int quote, int poll_state,
569                     void * priv_data){
570     struct vnet_dev * new_dev = NULL;
571     unsigned long flags;
572
573     new_dev = (struct vnet_dev *)Vnet_Malloc(sizeof(struct vnet_dev)); 
574
575     if (new_dev == NULL) {
576         Vnet_Print(0, "VNET/P Core: Unable to allocate a new device\n");
577         return -1;
578     }
579    
580     memcpy(new_dev->mac_addr, mac, 6);
581     new_dev->dev_ops.input = ops->input;
582     new_dev->dev_ops.poll = ops->poll;
583     new_dev->private_data = priv_data;
584     new_dev->vm = vm;
585     new_dev->dev_id = 0;
586     new_dev->quote = quote<VNET_MAX_QUOTE ? quote : VNET_MAX_QUOTE;
587     new_dev->poll = poll_state;
588
589     flags = vnet_lock_irqsave(vnet_state.lock);
590
591     if (dev_by_mac(mac) == NULL) {
592         list_add(&(new_dev->node), &(vnet_state.devs));
593         new_dev->dev_id = ++ vnet_state.dev_idx;
594         vnet_state.num_devs ++;
595
596         if(new_dev->poll) {
597             v3_enqueue(vnet_state.poll_devs, (addr_t)new_dev);
598         }
599     } else {
600         PrintError("VNET/P: Device with the same MAC has already been added\n");
601     }
602
603     vnet_unlock_irqrestore(vnet_state.lock, flags);
604
605     /* if the device was found previosly the id should still be 0 */
606     if (new_dev->dev_id == 0) {
607         Vnet_Print(0, "VNET/P Core: Device Already exists\n");
608         return -1;
609     }
610
611     PrintDebug("VNET/P Core: Add Device: dev_id %d\n", new_dev->dev_id);
612
613     return new_dev->dev_id;
614 }
615
616
617 int v3_vnet_del_dev(int dev_id){
618     struct vnet_dev * dev = NULL;
619     unsigned long flags;
620
621     flags = vnet_lock_irqsave(vnet_state.lock);
622         
623     dev = dev_by_id(dev_id);
624     if (dev != NULL){
625         list_del(&(dev->node));
626         //del_routes_by_dev(dev_id);
627         vnet_state.num_devs --;
628     }
629         
630     vnet_unlock_irqrestore(vnet_state.lock, flags);
631
632     Vnet_Free(dev);
633
634     PrintDebug("VNET/P Core: Removed Device: dev_id %d\n", dev_id);
635
636     return 0;
637 }
638
639
640 int v3_vnet_stat(struct vnet_stat * stats){
641     stats->rx_bytes = vnet_state.stats.rx_bytes;
642     stats->rx_pkts = vnet_state.stats.rx_pkts;
643     stats->tx_bytes = vnet_state.stats.tx_bytes;
644     stats->tx_pkts = vnet_state.stats.tx_pkts;
645
646     return 0;
647 }
648
649 static void deinit_devices_list(){
650     struct vnet_dev * dev, * tmp; 
651
652     list_for_each_entry_safe(dev, tmp, &(vnet_state.devs), node) {
653         list_del(&(dev->node));
654         Vnet_Free(dev);
655     }
656 }
657
658 static void deinit_routes_list(){
659     struct vnet_route_info * route, * tmp; 
660
661     list_for_each_entry_safe(route, tmp, &(vnet_state.routes), node) {
662         list_del(&(route->node));
663         list_del(&(route->match_node));
664         Vnet_Free(route);
665     }
666 }
667
668 int v3_vnet_add_bridge(struct v3_vm_info * vm,
669                        struct v3_vnet_bridge_ops * ops,
670                        uint8_t type,
671                        void * priv_data) {
672     unsigned long flags;
673     int bridge_free = 0;
674     struct vnet_brg_dev * tmp_bridge = NULL;    
675     
676     flags = vnet_lock_irqsave(vnet_state.lock);
677     if (vnet_state.bridge == NULL) {
678         bridge_free = 1;
679         vnet_state.bridge = (void *)1;
680     }
681     vnet_unlock_irqrestore(vnet_state.lock, flags);
682
683     if (bridge_free == 0) {
684         PrintError("VNET/P Core: Bridge already set\n");
685         return -1;
686     }
687
688     tmp_bridge = (struct vnet_brg_dev *)Vnet_Malloc(sizeof(struct vnet_brg_dev));
689
690     if (tmp_bridge == NULL) {
691         PrintError("VNET/P Core: Unable to allocate new bridge\n");
692         vnet_state.bridge = NULL;
693         return -1;
694     }
695     
696     tmp_bridge->vm = vm;
697     tmp_bridge->brg_ops.input = ops->input;
698     tmp_bridge->brg_ops.poll = ops->poll;
699     tmp_bridge->private_data = priv_data;
700     tmp_bridge->type = type;
701         
702     /* make this atomic to avoid possible race conditions */
703     flags = vnet_lock_irqsave(vnet_state.lock);
704     vnet_state.bridge = tmp_bridge;
705     vnet_unlock_irqrestore(vnet_state.lock, flags);
706
707     return 0;
708 }
709
710
711 void v3_vnet_del_bridge(uint8_t type) {
712     unsigned long flags;
713     struct vnet_brg_dev * tmp_bridge = NULL;    
714     
715     flags = vnet_lock_irqsave(vnet_state.lock);
716         
717     if (vnet_state.bridge != NULL && vnet_state.bridge->type == type) {
718         tmp_bridge = vnet_state.bridge;
719         vnet_state.bridge = NULL;
720     }
721         
722     vnet_unlock_irqrestore(vnet_state.lock, flags);
723
724     if (tmp_bridge) {
725         Vnet_Free(tmp_bridge);
726     }
727 }
728
729
730 /* can be instanieoued to multiple threads
731   * that runs on multiple cores 
732   * or it could be running on a dedicated side core
733   */
734 static int vnet_tx_flush(void * args){
735     struct vnet_dev * dev = NULL;
736     int more;
737     int rc;
738
739     Vnet_Print(0, "VNET/P Polling Thread Starting ....\n");
740
741     // since there are multiple instances of this thread, and only
742     // one queue of pollable devices, our model here will be to synchronize
743     // on that queue, removing devices as we go, and keeping them
744     // then putting them back on the queue when we are done
745     // in this way, multiple instances of this function will never
746     // be polling the same device at the same time
747
748     struct v3_queue * tq = v3_create_queue();
749
750     if (!tq) { 
751         PrintError("VNET/P polling thread cannot allocate queue\n");
752         return -1;
753     }
754
755
756     while (!vnet_thread_should_stop()) {
757
758         more=0; // will indicate if any device has more work for us to do
759
760         while ((dev = (struct vnet_dev *)v3_dequeue(vnet_state.poll_devs))) { 
761             // we are handling this device
762             v3_enqueue(tq,(addr_t)dev);
763             
764             if (dev->poll && dev->dev_ops.poll) {
765                 // The device's poll function MUST NOT BLOCK
766                 rc = dev->dev_ops.poll(dev->vm, dev->quote, dev->private_data);
767
768                 if (rc<0) { 
769                     Vnet_Print(0, "VNET/P: poll from device %p error (ignoring) !\n", dev);
770                 } else {
771                     more |= rc;  
772                 }
773             }
774         }
775         
776         while ((dev = (struct vnet_dev *)v3_dequeue(tq))) { 
777             // now someone else can handle it
778             v3_enqueue(vnet_state.poll_devs, (addr_t)dev); 
779         }
780
781         // Yield regardless of whether we handled any devices - need
782         // to allow other threads to run
783         if (more) { 
784             // we have more to do, so we want to get back asap
785             V3_Yield();
786         } else {
787             // put ourselves briefly to sleep if we we don't have more
788             V3_Yield_Timed(VNET_YIELD_USEC);
789         }
790
791     }
792
793     Vnet_Free(tq);
794     
795     Vnet_Print(0, "VNET/P Polling Thread Done.\n");
796
797     return 0;
798 }
799
800 int v3_init_vnet() {
801     memset(&vnet_state, 0, sizeof(vnet_state));
802         
803     INIT_LIST_HEAD(&(vnet_state.routes));
804     INIT_LIST_HEAD(&(vnet_state.devs));
805
806     vnet_state.num_devs = 0;
807     vnet_state.num_routes = 0;
808
809     if (vnet_lock_init(&(vnet_state.lock)) == -1){
810         PrintError("VNET/P: Fails to initiate lock\n");
811     }
812
813     vnet_state.route_cache = vnet_create_htable(0, &hash_fn, &hash_eq);
814     if (vnet_state.route_cache == NULL) {
815         PrintError("VNET/P: Fails to initiate route cache\n");
816         return -1;
817     }
818
819     vnet_state.poll_devs = v3_create_queue();
820
821     vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "vnetd-1");
822
823     PrintDebug("VNET/P is initiated\n");
824
825     return 0;
826 }
827
828
829 void v3_deinit_vnet(){
830
831     PrintDebug("Stopping flush thread\n");
832     // This will pause until the flush thread is gone
833     vnet_thread_stop(vnet_state.pkt_flush_thread);
834     // At this point there should be no lock-holder
835
836     Vnet_Free(vnet_state.poll_devs);
837
838
839     PrintDebug("Deiniting Device List\n");
840     // close any devices we have open
841     deinit_devices_list();  
842     
843     PrintDebug("Deiniting Route List\n");
844     // remove any routes we have
845     deinit_routes_list();
846
847     PrintDebug("Freeing hash table\n");
848     // remove the hash table
849     vnet_free_htable(vnet_state.route_cache, 1, 1);
850
851     
852     PrintDebug("Removing Bridge\n");
853     // remove bridge if it was added
854     if (vnet_state.bridge) { 
855         Vnet_Free(vnet_state.bridge);
856     }
857
858     PrintDebug("Deleting lock\n");
859     // eliminate the lock
860     vnet_lock_deinit(&(vnet_state.lock));
861
862 }
863
864