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.


d9fe902fbc969d7a5638f06061dcb76f1ceeac62
[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
353
354
355 /* At the end allocate a route_list
356  * This list will be inserted into the cache so we don't need to free it
357  */
358 static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
359     struct vnet_route_info * route = NULL; 
360     struct route_list * matches = NULL;
361     int num_matches = 0;
362     int max_rank = 0;
363     struct list_head match_list;
364     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
365     //  uint8_t src_type = pkt->src_type;
366     //  uint32_t src_link = pkt->src_id;
367
368 #ifdef V3_CONFIG_DEBUG_VNET
369     {
370         char dst_str[100];
371         char src_str[100];
372
373         mac2str(hdr->src_mac, src_str);  
374         mac2str(hdr->dst_mac, dst_str);
375         PrintDebug("VNET/P Core: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
376     }
377 #endif
378
379     INIT_LIST_HEAD(&match_list);
380     
381 #define UPDATE_MATCHES(rank) do {                               \
382         if (max_rank < (rank)) {                                \
383             max_rank = (rank);                                  \
384             INIT_LIST_HEAD(&match_list);                        \
385                                                                 \
386             list_add(&(route->match_node), &match_list);        \
387             num_matches = 1;                                    \
388         } else if (max_rank == (rank)) {                        \
389             list_add(&(route->match_node), &match_list);        \
390             num_matches++;                                      \
391         }                                                       \
392     } while (0)
393     
394
395     list_for_each_entry(route, &(vnet_state.routes), node) {
396         struct v3_vnet_route * route_def = &(route->route_def);
397
398 /*
399         // CHECK SOURCE TYPE HERE
400         if ( (route_def->src_type != LINK_ANY) && 
401              ( (route_def->src_type != src_type) || 
402                ( (route_def->src_id != src_link) &&
403                  (route_def->src_id != -1)))) {
404             continue;
405         }
406 */
407
408         if ((route_def->dst_mac_qual == MAC_ANY) &&
409             (route_def->src_mac_qual == MAC_ANY)) {      
410             UPDATE_MATCHES(3);
411         }
412         
413         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
414             if (route_def->src_mac_qual != MAC_NOT) {
415                 if (route_def->dst_mac_qual == MAC_ANY) {
416                     UPDATE_MATCHES(6);
417                 } else if (route_def->dst_mac_qual != MAC_NOT &&
418                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
419                     UPDATE_MATCHES(8);
420                 }
421             }
422         }
423             
424         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
425             if (route_def->dst_mac_qual != MAC_NOT) {
426                 if (route_def->src_mac_qual == MAC_ANY) {
427                     UPDATE_MATCHES(6);
428                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
429                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
430                     UPDATE_MATCHES(8);
431                 }
432             }
433         }
434             
435         if ((route_def->dst_mac_qual == MAC_NOT) &&
436             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
437             if (route_def->src_mac_qual == MAC_ANY) {
438                 UPDATE_MATCHES(5);
439             } else if ((route_def->src_mac_qual != MAC_NOT) && 
440                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
441                 UPDATE_MATCHES(7);
442             }
443         }
444         
445         if ((route_def->src_mac_qual == MAC_NOT) &&
446             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
447             if (route_def->dst_mac_qual == MAC_ANY) {
448                 UPDATE_MATCHES(5);
449             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
450                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
451                 UPDATE_MATCHES(7);
452             }
453         }
454         
455         // Default route
456         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &&
457              (route_def->dst_mac_qual == MAC_NONE)) {
458             UPDATE_MATCHES(4);
459         }
460     }
461
462     PrintDebug("VNET/P Core: match_route: Matches=%d\n", num_matches);
463
464     if (num_matches <= 0) {
465         return NULL;
466     }
467
468     matches = (struct route_list *)Vnet_Malloc(sizeof(struct route_list) + 
469                                                (sizeof(struct vnet_route_info *) * num_matches));
470
471
472     if (!matches) {
473         PrintError("VNET/P Core: Unable to allocate matches\n");
474         return NULL;
475     }
476
477     matches->num_routes = num_matches;
478
479     {
480         int i = 0;
481         list_for_each_entry(route, &match_list, match_node) {
482             matches->routes[i++] = route;
483         }
484     }
485
486     return matches;
487 }
488
489 int v3_vnet_query_header(uint8_t src_mac[6], 
490                          uint8_t dest_mac[6],
491                          int     recv,         // 0 = send, 1=recv
492                          struct v3_vnet_header *header)
493 {
494     struct route_list *routes;
495     struct vnet_route_info *r;
496     struct v3_vnet_pkt p;
497
498     p.size=14;
499     p.data=p.header;
500     memcpy(p.header,dest_mac,6);
501     memcpy(p.header+6,src_mac,6);
502     memset(p.header+12,0,2);
503
504     p.src_type = LINK_EDGE;
505     p.src_id = 0;
506
507     memcpy(header->src_mac,src_mac,6);
508     memcpy(header->dst_mac,dest_mac,6);
509
510     
511     look_into_cache(&p,&routes);
512
513     if (!routes) { 
514         routes = match_route(&p);
515         if (!routes) { 
516             PrintError("Cannot match route\n");
517             header->header_type=VNET_HEADER_NOMATCH;
518             header->header_len=0;
519             return -1;
520         } else {
521             add_route_to_cache(&p,routes);
522         }
523     }
524     
525     if (routes->num_routes<1) { 
526         PrintError("Less than one route\n");
527         header->header_type=VNET_HEADER_NOMATCH;
528         header->header_len=0;
529         return -1;
530     }
531
532     if (routes->num_routes>1) { 
533         PrintError("More than one route, building header for the first one only\n");
534     }
535
536     r=routes->routes[0];
537
538     switch (r->route_def.dst_type) {
539         case LINK_EDGE: {
540             // switch based on the link type
541             // for mac-in-udp, we would want to generate a mac, ip, and udp header
542             // direct transmission
543
544             // for now we will say we have no encapsulation
545             //
546             header->header_type=VNET_HEADER_NONE;
547             header->header_len=0;
548             header->src_mac_qual=r->route_def.src_mac_qual;
549             header->dst_mac_qual=r->route_def.dst_mac_qual;
550             
551         }
552             
553             return 0;
554             break;
555             
556
557         case LINK_INTERFACE:
558             // direct transmission
559             // let's guess that it goes to the same interface...
560             header->header_type=VNET_HEADER_NONE;
561             header->header_len=0;
562             header->src_mac_qual=r->route_def.src_mac_qual;
563             header->dst_mac_qual=r->route_def.dst_mac_qual;
564
565             return 0;
566             break;
567
568         default:
569             PrintError("Unknown destination type\n");
570             return -1;
571             break;
572
573     }
574     
575 }
576
577
578
579
580 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
581     struct route_list * matched_routes = NULL;
582     unsigned long flags;
583     int i;
584
585     int cpu = V3_Get_CPU();
586
587     Vnet_Print(2, "VNET/P Core: cpu %d: pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n",
588                cpu, pkt->size, pkt->src_id, 
589                pkt->src_type, pkt->dst_id, pkt->dst_type);
590
591     if(net_debug >= 4){
592         v3_hexdump(pkt->data, pkt->size, NULL, 0);
593     }
594
595     flags = vnet_lock_irqsave(vnet_state.lock);
596
597     vnet_state.stats.rx_bytes += pkt->size;
598     vnet_state.stats.rx_pkts++;
599
600     look_into_cache(pkt, &matched_routes);
601
602     if (matched_routes == NULL) {  
603         PrintDebug("VNET/P Core: sending pkt - matching route\n");
604         
605         matched_routes = match_route(pkt);
606         
607         if (matched_routes) {
608             add_route_to_cache(pkt, matched_routes);
609         } else {
610             PrintDebug("VNET/P Core: Could not find route for packet... discarding packet\n");
611             vnet_unlock_irqrestore(vnet_state.lock, flags);
612             return 0; /* do we return -1 here?*/
613         }
614     }
615
616     vnet_unlock_irqrestore(vnet_state.lock, flags);
617
618     PrintDebug("VNET/P Core: send pkt route matches %d\n", matched_routes->num_routes);
619
620     for (i = 0; i < matched_routes->num_routes; i++) {
621         struct vnet_route_info * route = matched_routes->routes[i];
622         
623         if (route->route_def.dst_type == LINK_EDGE) {
624             struct vnet_brg_dev * bridge = vnet_state.bridge;
625             pkt->dst_type = LINK_EDGE;
626             pkt->dst_id = route->route_def.dst_id;
627
628             if (bridge == NULL) {
629                 Vnet_Print(2, "VNET/P Core: No active bridge to sent data to\n");
630                 continue;
631             }
632
633             if(bridge->brg_ops.input(bridge->vm, pkt, bridge->private_data) < 0){
634                 Vnet_Print(2, "VNET/P Core: Packet not sent properly to bridge\n");
635                 continue;
636             }         
637             vnet_state.stats.tx_bytes += pkt->size;
638             vnet_state.stats.tx_pkts ++;
639         } else if (route->route_def.dst_type == LINK_INTERFACE) {
640             if (route->dst_dev == NULL){
641                   Vnet_Print(2, "VNET/P Core: No active device to sent data to\n");
642                 continue;
643             }
644
645             if(route->dst_dev->dev_ops.input(route->dst_dev->vm, pkt, route->dst_dev->private_data) < 0) {
646                 Vnet_Print(2, "VNET/P Core: Packet not sent properly\n");
647                 continue;
648             }
649             vnet_state.stats.tx_bytes += pkt->size;
650             vnet_state.stats.tx_pkts ++;
651         } else {
652             Vnet_Print(0, "VNET/P Core: Wrong dst type\n");
653         }
654     }
655     
656     return 0;
657 }
658
659
660 int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, 
661                     struct v3_vnet_dev_ops * ops, int quote, int poll_state,
662                     void * priv_data){
663     struct vnet_dev * new_dev = NULL;
664     unsigned long flags;
665
666     new_dev = (struct vnet_dev *)Vnet_Malloc(sizeof(struct vnet_dev)); 
667
668     if (new_dev == NULL) {
669         Vnet_Print(0, "VNET/P Core: Unable to allocate a new device\n");
670         return -1;
671     }
672    
673     memcpy(new_dev->mac_addr, mac, 6);
674     new_dev->dev_ops.input = ops->input;
675     new_dev->dev_ops.poll = ops->poll;
676     new_dev->private_data = priv_data;
677     new_dev->vm = vm;
678     new_dev->dev_id = 0;
679     new_dev->quote = quote<VNET_MAX_QUOTE ? quote : VNET_MAX_QUOTE;
680     new_dev->poll = poll_state;
681
682     flags = vnet_lock_irqsave(vnet_state.lock);
683
684     if (dev_by_mac(mac) == NULL) {
685         list_add(&(new_dev->node), &(vnet_state.devs));
686         new_dev->dev_id = ++ vnet_state.dev_idx;
687         vnet_state.num_devs ++;
688
689         if(new_dev->poll) {
690             v3_enqueue(vnet_state.poll_devs, (addr_t)new_dev);
691         }
692     } else {
693         PrintError("VNET/P: Device with the same MAC has already been added\n");
694     }
695
696     vnet_unlock_irqrestore(vnet_state.lock, flags);
697
698     /* if the device was found previosly the id should still be 0 */
699     if (new_dev->dev_id == 0) {
700         Vnet_Print(0, "VNET/P Core: Device Already exists\n");
701         return -1;
702     }
703
704     PrintDebug("VNET/P Core: Add Device: dev_id %d\n", new_dev->dev_id);
705
706     return new_dev->dev_id;
707 }
708
709
710 int v3_vnet_del_dev(int dev_id){
711     struct vnet_dev * dev = NULL;
712     unsigned long flags;
713
714     flags = vnet_lock_irqsave(vnet_state.lock);
715         
716     dev = dev_by_id(dev_id);
717     if (dev != NULL){
718         list_del(&(dev->node));
719         //del_routes_by_dev(dev_id);
720         vnet_state.num_devs --;
721     }
722         
723     vnet_unlock_irqrestore(vnet_state.lock, flags);
724
725     Vnet_Free(dev);
726
727     PrintDebug("VNET/P Core: Removed Device: dev_id %d\n", dev_id);
728
729     return 0;
730 }
731
732
733 int v3_vnet_stat(struct vnet_stat * stats){
734     stats->rx_bytes = vnet_state.stats.rx_bytes;
735     stats->rx_pkts = vnet_state.stats.rx_pkts;
736     stats->tx_bytes = vnet_state.stats.tx_bytes;
737     stats->tx_pkts = vnet_state.stats.tx_pkts;
738
739     return 0;
740 }
741
742 static void deinit_devices_list(){
743     struct vnet_dev * dev, * tmp; 
744
745     list_for_each_entry_safe(dev, tmp, &(vnet_state.devs), node) {
746         list_del(&(dev->node));
747         Vnet_Free(dev);
748     }
749 }
750
751 static void deinit_routes_list(){
752     struct vnet_route_info * route, * tmp; 
753
754     list_for_each_entry_safe(route, tmp, &(vnet_state.routes), node) {
755         list_del(&(route->node));
756         list_del(&(route->match_node));
757         Vnet_Free(route);
758     }
759 }
760
761 int v3_vnet_add_bridge(struct v3_vm_info * vm,
762                        struct v3_vnet_bridge_ops * ops,
763                        uint8_t type,
764                        void * priv_data) {
765     unsigned long flags;
766     int bridge_free = 0;
767     struct vnet_brg_dev * tmp_bridge = NULL;    
768     
769     flags = vnet_lock_irqsave(vnet_state.lock);
770     if (vnet_state.bridge == NULL) {
771         bridge_free = 1;
772         vnet_state.bridge = (void *)1;
773     }
774     vnet_unlock_irqrestore(vnet_state.lock, flags);
775
776     if (bridge_free == 0) {
777         PrintError("VNET/P Core: Bridge already set\n");
778         return -1;
779     }
780
781     tmp_bridge = (struct vnet_brg_dev *)Vnet_Malloc(sizeof(struct vnet_brg_dev));
782
783     if (tmp_bridge == NULL) {
784         PrintError("VNET/P Core: Unable to allocate new bridge\n");
785         vnet_state.bridge = NULL;
786         return -1;
787     }
788     
789     tmp_bridge->vm = vm;
790     tmp_bridge->brg_ops.input = ops->input;
791     tmp_bridge->brg_ops.poll = ops->poll;
792     tmp_bridge->private_data = priv_data;
793     tmp_bridge->type = type;
794         
795     /* make this atomic to avoid possible race conditions */
796     flags = vnet_lock_irqsave(vnet_state.lock);
797     vnet_state.bridge = tmp_bridge;
798     vnet_unlock_irqrestore(vnet_state.lock, flags);
799
800     return 0;
801 }
802
803
804 void v3_vnet_del_bridge(uint8_t type) {
805     unsigned long flags;
806     struct vnet_brg_dev * tmp_bridge = NULL;    
807     
808     flags = vnet_lock_irqsave(vnet_state.lock);
809         
810     if (vnet_state.bridge != NULL && vnet_state.bridge->type == type) {
811         tmp_bridge = vnet_state.bridge;
812         vnet_state.bridge = NULL;
813     }
814         
815     vnet_unlock_irqrestore(vnet_state.lock, flags);
816
817     if (tmp_bridge) {
818         Vnet_Free(tmp_bridge);
819     }
820 }
821
822
823 /* can be instanieoued to multiple threads
824   * that runs on multiple cores 
825   * or it could be running on a dedicated side core
826   */
827 static int vnet_tx_flush(void * args){
828     struct vnet_dev * dev = NULL;
829     int more;
830     int rc;
831
832     Vnet_Print(0, "VNET/P Polling Thread Starting ....\n");
833
834     // since there are multiple instances of this thread, and only
835     // one queue of pollable devices, our model here will be to synchronize
836     // on that queue, removing devices as we go, and keeping them
837     // then putting them back on the queue when we are done
838     // in this way, multiple instances of this function will never
839     // be polling the same device at the same time
840
841     struct v3_queue * tq = v3_create_queue();
842
843     if (!tq) { 
844         PrintError("VNET/P polling thread cannot allocate queue\n");
845         return -1;
846     }
847
848
849     while (!vnet_thread_should_stop()) {
850
851         more=0; // will indicate if any device has more work for us to do
852
853         while ((dev = (struct vnet_dev *)v3_dequeue(vnet_state.poll_devs))) { 
854             // we are handling this device
855             v3_enqueue(tq,(addr_t)dev);
856             
857             if (dev->poll && dev->dev_ops.poll) {
858                 // The device's poll function MUST NOT BLOCK
859                 rc = dev->dev_ops.poll(dev->vm, dev->quote, dev->private_data);
860
861                 if (rc<0) { 
862                     Vnet_Print(0, "VNET/P: poll from device %p error (ignoring) !\n", dev);
863                 } else {
864                     more |= rc;  
865                 }
866             }
867         }
868         
869         while ((dev = (struct vnet_dev *)v3_dequeue(tq))) { 
870             // now someone else can handle it
871             v3_enqueue(vnet_state.poll_devs, (addr_t)dev); 
872         }
873
874         // Yield regardless of whether we handled any devices - need
875         // to allow other threads to run
876         if (more) { 
877             // we have more to do, so we want to get back asap
878             V3_Yield();
879         } else {
880             // put ourselves briefly to sleep if we we don't have more
881             V3_Yield_Timed(VNET_YIELD_USEC);
882         }
883
884     }
885
886     Vnet_Free(tq);
887     
888     Vnet_Print(0, "VNET/P Polling Thread Done.\n");
889
890     return 0;
891 }
892
893 int v3_init_vnet() {
894     memset(&vnet_state, 0, sizeof(vnet_state));
895         
896     INIT_LIST_HEAD(&(vnet_state.routes));
897     INIT_LIST_HEAD(&(vnet_state.devs));
898
899     vnet_state.num_devs = 0;
900     vnet_state.num_routes = 0;
901
902     if (vnet_lock_init(&(vnet_state.lock)) == -1){
903         PrintError("VNET/P: Fails to initiate lock\n");
904     }
905
906     vnet_state.route_cache = vnet_create_htable(0, &hash_fn, &hash_eq);
907     if (vnet_state.route_cache == NULL) {
908         PrintError("VNET/P: Fails to initiate route cache\n");
909         return -1;
910     }
911
912     vnet_state.poll_devs = v3_create_queue();
913
914     vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "vnetd-1");
915
916     PrintDebug("VNET/P is initiated\n");
917
918     return 0;
919 }
920
921
922 void v3_deinit_vnet(){
923
924     PrintDebug("Stopping flush thread\n");
925     // This will pause until the flush thread is gone
926     vnet_thread_stop(vnet_state.pkt_flush_thread);
927     // At this point there should be no lock-holder
928
929     Vnet_Free(vnet_state.poll_devs);
930
931
932     PrintDebug("Deiniting Device List\n");
933     // close any devices we have open
934     deinit_devices_list();  
935     
936     PrintDebug("Deiniting Route List\n");
937     // remove any routes we have
938     deinit_routes_list();
939
940     PrintDebug("Freeing hash table\n");
941     // remove the hash table
942     vnet_free_htable(vnet_state.route_cache, 1, 1);
943
944     
945     PrintDebug("Removing Bridge\n");
946     // remove bridge if it was added
947     if (vnet_state.bridge) { 
948         Vnet_Free(vnet_state.bridge);
949     }
950
951     PrintDebug("Deleting lock\n");
952     // eliminate the lock
953     vnet_lock_deinit(&(vnet_state.lock));
954
955 }
956
957