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.


Configurable yielding strategies in VNET bridge thread and tx kick threads
[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_NUM_TX_KICK_THREADS 2
35
36 #define VNET_ADAPTIVE_TX_KICK 0         // set to 1 to try to sleep when there is nothing to do
37 #define VNET_NOPROGRESS_LIMIT 1000      //   ... after this many tries
38 #define VNET_YIELD_USEC       1000      //   ... and go to sleep for this long
39
40
41 int net_debug = 0;
42
43 struct eth_hdr {
44     uint8_t dst_mac[ETH_ALEN];
45     uint8_t src_mac[ETH_ALEN];
46     uint16_t type; /* indicates layer 3 protocol type */
47 } __attribute__((packed));
48
49
50 struct vnet_dev {
51     int dev_id;
52     uint8_t mac_addr[ETH_ALEN];
53     struct v3_vm_info * vm;
54     struct v3_vnet_dev_ops dev_ops;
55
56     int poll;
57
58 #define VNET_MAX_QUOTE 64
59     int quote;
60         
61     void * private_data;
62
63     struct list_head node;
64 } __attribute__((packed));
65
66
67 struct vnet_brg_dev {
68     struct v3_vm_info * vm;
69     struct v3_vnet_bridge_ops brg_ops;
70
71     uint8_t type;
72
73     void * private_data;
74 } __attribute__((packed));
75
76
77
78 struct vnet_route_info {
79     struct v3_vnet_route route_def;
80
81     struct vnet_dev * dst_dev;
82     struct vnet_dev * src_dev;
83
84     uint32_t idx;
85
86     struct list_head node;
87     struct list_head match_node; // used for route matching
88 };
89
90
91 struct route_list {
92     uint8_t hash_buf[VNET_HASH_SIZE];
93
94     uint32_t num_routes;
95     struct vnet_route_info * routes[0];
96 } __attribute__((packed));
97
98
99 struct queue_entry{
100     uint8_t use;
101     struct v3_vnet_pkt pkt;
102     uint8_t * data;
103     uint32_t size_alloc;
104 };
105
106
107 static struct {
108     struct list_head routes;
109     struct list_head devs;
110
111     uint8_t status; 
112    
113     uint32_t num_routes;
114     uint32_t route_idx;
115     uint32_t num_devs;
116     uint32_t dev_idx;
117
118     struct vnet_brg_dev * bridge;
119
120     vnet_lock_t lock;
121     struct vnet_stat stats;
122
123    /* device queue that are waiting to be polled */
124     struct v3_queue * poll_devs;
125
126     struct vnet_thread * pkt_flush_thread[VNET_NUM_TX_KICK_THREADS];
127
128     struct hashtable * route_cache;
129
130 } vnet_state;
131         
132
133 #ifdef V3_CONFIG_DEBUG_VNET
134 static inline void mac2str(uint8_t * mac, char * buf) {
135     snprintf(buf, 100, "%2x:%2x:%2x:%2x:%2x:%2x", 
136              mac[0], mac[1], mac[2],
137              mac[3], mac[4], mac[5]);
138 }
139
140 static void print_route(struct v3_vnet_route * route){
141     char str[50];
142
143     mac2str(route->src_mac, str);
144     PrintDebug("Src Mac (%s),  src_qual (%d)\n", 
145                str, route->src_mac_qual);
146     mac2str(route->dst_mac, str);
147     PrintDebug("Dst Mac (%s),  dst_qual (%d)\n", 
148                str, route->dst_mac_qual);
149     PrintDebug("Src dev id (%d), src type (%d)", 
150                route->src_id, 
151                route->src_type);
152     PrintDebug("Dst dev id (%d), dst type (%d)\n", 
153                route->dst_id, 
154                route->dst_type);
155 }
156
157 static void dump_routes(){
158     struct vnet_route_info *route;
159
160     PrintDebug("\n========Dump routes starts ============\n");
161     list_for_each_entry(route, &(vnet_state.routes), node) {
162         PrintDebug("\nroute %d:\n", route->idx);
163                 
164         print_route(&(route->route_def));
165         if (route->route_def.dst_type == LINK_INTERFACE) {
166             PrintDebug("dst_dev (%p), dst_dev_id (%d), dst_dev_ops(%p), dst_dev_data (%p)\n",
167                 route->dst_dev,
168                 route->dst_dev->dev_id,
169                 (void *)&(route->dst_dev->dev_ops),
170                 route->dst_dev->private_data);
171         }
172     }
173
174     PrintDebug("\n========Dump routes end ============\n");
175 }
176
177 #endif
178
179
180 /* 
181  * A VNET packet is a packed struct with the hashed fields grouped together.
182  * This means we can generate the hash from an offset into the pkt struct
183  */
184 static inline uint_t hash_fn(addr_t hdr_ptr) {    
185     uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
186
187     return vnet_hash_buffer(hdr_buf, VNET_HASH_SIZE);
188 }
189
190 static inline int hash_eq(addr_t key1, addr_t key2) {   
191     return (memcmp((uint8_t *)key1, (uint8_t *)key2, VNET_HASH_SIZE) == 0);
192 }
193
194 static int add_route_to_cache(const struct v3_vnet_pkt * pkt, struct route_list * routes) {
195     memcpy(routes->hash_buf, pkt->hash_buf, VNET_HASH_SIZE);    
196
197     if (vnet_htable_insert(vnet_state.route_cache, (addr_t)routes->hash_buf, (addr_t)routes) == 0) {
198         PrintError("VNET/P Core: Failed to insert new route entry to the cache\n");
199         return -1;
200     }
201     
202     return 0;
203 }
204
205 static int clear_hash_cache() {
206     vnet_free_htable(vnet_state.route_cache, 1, 1);
207     vnet_state.route_cache = vnet_create_htable(0, &hash_fn, &hash_eq);
208
209     return 0;
210 }
211
212 static int look_into_cache(const struct v3_vnet_pkt * pkt, 
213                            struct route_list ** routes) {
214     *routes = (struct route_list *)vnet_htable_search(vnet_state.route_cache, (addr_t)(pkt->hash_buf));
215    
216     return 0;
217 }
218
219
220 static struct vnet_dev * dev_by_id(int idx) {
221     struct vnet_dev * dev = NULL; 
222
223     list_for_each_entry(dev, &(vnet_state.devs), node) {
224         if (dev->dev_id == idx) {
225             return dev;
226         }
227     }
228
229     return NULL;
230 }
231
232 static struct vnet_dev * dev_by_mac(uint8_t * mac) {
233     struct vnet_dev * dev = NULL; 
234     
235     list_for_each_entry(dev, &(vnet_state.devs), node) {
236         if (!compare_ethaddr(dev->mac_addr, mac)){
237             return dev;
238         }
239     }
240
241     return NULL;
242 }
243
244
245 int v3_vnet_find_dev(uint8_t  * mac) {
246     struct vnet_dev * dev = NULL;
247
248     dev = dev_by_mac(mac);
249
250     if(dev != NULL) {
251         return dev->dev_id;
252     }
253
254     return -1;
255 }
256
257
258 int v3_vnet_add_route(struct v3_vnet_route route) {
259     struct vnet_route_info * new_route = NULL;
260     vnet_intr_flags_t flags; 
261
262     new_route = (struct vnet_route_info *)Vnet_Malloc(sizeof(struct vnet_route_info));
263
264     if (!new_route) {
265         PrintError("Cannot allocate new route\n");
266         return -1;
267     }
268
269     memset(new_route, 0, sizeof(struct vnet_route_info));
270
271 #ifdef V3_CONFIG_DEBUG_VNET
272     PrintDebug("VNET/P Core: add_route_entry:\n");
273     print_route(&route);
274 #endif
275     
276     memcpy(new_route->route_def.src_mac, route.src_mac, ETH_ALEN);
277     memcpy(new_route->route_def.dst_mac, route.dst_mac, ETH_ALEN);
278     new_route->route_def.src_mac_qual = route.src_mac_qual;
279     new_route->route_def.dst_mac_qual = route.dst_mac_qual;
280     new_route->route_def.dst_type = route.dst_type;
281     new_route->route_def.src_type = route.src_type;
282     new_route->route_def.src_id = route.src_id;
283     new_route->route_def.dst_id = route.dst_id;
284
285     if (new_route->route_def.dst_type == LINK_INTERFACE) {
286         new_route->dst_dev = dev_by_id(new_route->route_def.dst_id);
287     }
288
289     if (new_route->route_def.src_type == LINK_INTERFACE) {
290         new_route->src_dev = dev_by_id(new_route->route_def.src_id);
291     }
292
293
294     flags = vnet_lock_irqsave(vnet_state.lock);
295
296     list_add(&(new_route->node), &(vnet_state.routes));
297     new_route->idx = ++ vnet_state.route_idx;
298     vnet_state.num_routes ++;
299         
300     vnet_unlock_irqrestore(vnet_state.lock, flags);
301
302     clear_hash_cache();
303
304 #ifdef V3_CONFIG_DEBUG_VNET
305     dump_routes();
306 #endif
307
308     return new_route->idx;
309 }
310
311
312 void v3_vnet_del_route(uint32_t route_idx){
313     struct vnet_route_info * route = NULL;
314     vnet_intr_flags_t flags; 
315
316     flags = vnet_lock_irqsave(vnet_state.lock);
317
318     list_for_each_entry(route, &(vnet_state.routes), node) {
319         Vnet_Print(0, "v3_vnet_del_route, route idx: %d\n", route->idx);
320         if(route->idx == route_idx){
321             list_del(&(route->node));
322             Vnet_Free(route);
323             break;    
324         }
325     }
326
327     vnet_unlock_irqrestore(vnet_state.lock, flags);
328     clear_hash_cache();
329
330 #ifdef V3_CONFIG_DEBUG_VNET
331     dump_routes();
332 #endif  
333 }
334
335
336 /* delete all route entries with specfied src or dst device id */ 
337 static void inline del_routes_by_dev(int dev_id){
338     struct vnet_route_info * route, *tmp_route;
339     vnet_intr_flags_t flags; 
340
341     flags = vnet_lock_irqsave(vnet_state.lock);
342
343     list_for_each_entry_safe(route, tmp_route, &(vnet_state.routes), node) {
344         if((route->route_def.dst_type == LINK_INTERFACE &&
345              route->route_def.dst_id == dev_id) ||
346              (route->route_def.src_type == LINK_INTERFACE &&
347               route->route_def.src_id == dev_id)){
348               
349             list_del(&(route->node));
350             list_del(&(route->match_node));
351             Vnet_Free(route);    
352         }
353     }
354     
355     vnet_unlock_irqrestore(vnet_state.lock, flags);
356 }
357
358
359 // Match classes, must be in order
360 #define NUM_MATCH_CLASSES 4
361 #define NUM_MATCH_CLASSES_BOUND 3
362 #define NONE    0
363 #define NOT     1
364 #define ANY     2
365 #define DIRECT  3
366
367
368 static inline uint8_t match_mac(uint8_t test_mac[ETH_ALEN], 
369                                 uint8_t route_mac[ETH_ALEN], 
370                                 uint8_t route_qual)
371 {
372     switch (route_qual) { 
373         case MAC_NOSET:
374             return NONE;
375             break;
376         case MAC_NONE:
377             return NONE;
378             break;
379         case MAC_ANY:
380             return ANY;
381             break;
382         case MAC_NOT:
383             if (memcmp(test_mac,route_mac,ETH_ALEN)) { 
384                 return NOT;
385             } else {
386                 return NONE;
387             }
388             break;
389         case MAC_ADDR:
390             if (memcmp(test_mac,route_mac,ETH_ALEN)) { 
391                 return NONE;
392             } else {
393                 return DIRECT;
394             }
395             break;
396         default:
397             PrintError("Unknown qualifier %u\n",route_qual);
398             return NONE;
399             break;
400     }
401
402 }
403
404 #define QUAL_TO_STR(q)  (       \
405 (q)==MAC_NOSET ? "MAC_NOSET" :  \
406 (q)==MAC_NONE ? "MAC_NONE" :    \
407 (q)==MAC_ANY ? "MAC_ANY" :      \
408 (q)==MAC_NOT ? "MAC_NOT" :      \
409 (q)==MAC_ADDR ? "MAC_ADDR" :    \
410 "***UNDEFINED****"              \
411     )                           \
412
413 #define MATCH_CLASS_TO_STR(c)  (       \
414 (c)==NONE ? "NONE" :  \
415 (c)==NOT ? "NOT" :    \
416 (c)==ANY ? "ANY" :      \
417 (c)==DIRECT ? "DIRECT" :      \
418 "***UNDEFINED****"              \
419     )                           \
420
421
422
423 /*
424
425 Original priority behavior... 
426   
427 priority   src  srcqual   dst  dstqual
428 3              ANY            ANY
429 4        X                    NONE
430 5              ANY     X      NOT
431 5        X     NOT            ANY
432 6        X     ~NOT           ANY
433 6              ANY     X      ~NOT
434 7        X     ~NOT    X      NOT
435 7        X     NOT     X      ~NOT
436 8        X     ~NOT    X      ~NOT
437 8        X     ~NOT    X      ~NOT
438
439 */
440
441 /*
442   Current priority order is given in the following table
443 */
444
445 // [src][dst] => priority
446 static int priority_map[NUM_MATCH_CLASSES][NUM_MATCH_CLASSES] = 
447 {
448     [NONE] = { [ 0 ... NUM_MATCH_CLASSES_BOUND ] = -1},   // ignore if it's not a source match
449     [NOT][NONE]                          = -1,            // ignore it if there is no destination match   
450     [NOT][NOT]                           = 3,                                   
451     [NOT][ANY]                           = 5,
452     [NOT][DIRECT]                        = 7,
453     [ANY][NONE]                          = -1,            // ignore if there is no destination match
454     [ANY][NOT]                           = 5,
455     [ANY][ANY]                           = 6,
456     [ANY][DIRECT]                        = 6,
457     [DIRECT][NONE]                       = -1,            // ignore if there is no destination match
458     [DIRECT][NOT]                        = 7,            
459     [DIRECT][ANY]                        = 8,            
460     [DIRECT][DIRECT]                     = 8,            
461 };
462
463
464
465
466 static inline int match_priority(uint8_t src_mac[ETH_ALEN],
467                                  uint8_t dst_mac[ETH_ALEN],
468                                  uint8_t route_src_mac[ETH_ALEN],
469                                  uint8_t route_src_qual,
470                                  uint8_t route_dst_mac[ETH_ALEN],
471                                  uint8_t route_dst_qual)
472
473 {
474
475     return priority_map[match_mac(src_mac,route_src_mac,route_src_qual)][match_mac(dst_mac,route_dst_mac,route_dst_qual)];
476 }
477
478
479 /*
480   Route matching will return the list of the highest priority routes that
481   match.  It's a list because it's possible to have multiple high priority routes
482  */ 
483 static struct route_list * match_route(const struct v3_vnet_pkt * pkt) 
484 {
485     int i;
486     struct vnet_route_info * route = NULL; 
487     struct route_list * matches = NULL;
488     int num_matches = 0;
489     int max_priority = -1;
490     struct list_head match_list;
491     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
492
493     //
494     //
495     // NOTE: USING THE MATCH_NODE in the route list to record a match list
496     // IS A DISASTER WAITING TO HAPPEN
497     //
498     
499 #ifdef V3_CONFIG_DEBUG_VNET
500     {
501         char dst_str[32], src_str[32];
502         mac2str(hdr->src_mac, src_str);  
503         mac2str(hdr->dst_mac, dst_str);
504         PrintDebug("VNET/P Core: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
505     }
506 #endif
507     
508     INIT_LIST_HEAD(&match_list);                        
509     
510     
511     list_for_each_entry(route, &(vnet_state.routes), node) {
512         
513         struct v3_vnet_route * route_def = &(route->route_def);
514         
515         int priority;
516         
517         priority = match_priority(hdr->src_mac,
518                                   hdr->dst_mac,
519                                   route_def->src_mac,
520                                   route_def->src_mac_qual,
521                                   route_def->dst_mac,
522                                   route_def->dst_mac_qual);
523
524         
525
526 #ifdef V3_CONFIG_DEBUG_VNET
527         {
528             char dst_str[32];
529             char src_str[32];
530             
531             mac2str(route_def->src_mac, src_str);  
532             mac2str(route_def->dst_mac, dst_str);
533             
534             PrintDebug("Tested match against SRC(%s) SRC_QUAL(%s), DEST(%s) DST_QUAL(%s): "
535                        "SRC_MATCH=%s  DEST_MATCH=%s PRIORITY=%d\n", 
536                        src_str, QUAL_TO_STR(route_def->src_mac_qual), 
537                        dst_str, QUAL_TO_STR(route_def->dst_mac_qual),
538                        MATCH_CLASS_TO_STR(match_mac(hdr->src_mac,route_def->src_mac,route_def->src_mac_qual)),
539                        MATCH_CLASS_TO_STR(match_mac(hdr->dst_mac,route_def->dst_mac,route_def->dst_mac_qual)),
540                    priority);
541         }
542 #endif
543
544         if (priority<0) { 
545             PrintDebug("No match to this rule\n");
546             continue;
547         }
548
549         if (priority > max_priority) { 
550             PrintDebug("New highest priority match, reseting list\n");
551             max_priority = priority;
552
553             struct vnet_route_info *my_route, *tmp_route;
554
555             list_for_each_entry_safe(my_route, tmp_route, &match_list,match_node) {
556                 list_del(&(my_route->match_node));
557             }
558
559             list_add(&(route->match_node), &match_list);        
560             num_matches = 1;                                    
561             
562         } else if (priority == max_priority) {                      
563             PrintDebug("Equal priority match, adding to list\n");
564             
565             list_add(&(route->match_node), &match_list);        
566             num_matches++;                                      
567         }                                                       
568         
569     }
570
571     PrintDebug("VNET/P Core: match_route: Matches=%d\n", num_matches);
572
573     if (num_matches <= 0) {
574         return NULL;
575     }
576     
577     matches = (struct route_list *)Vnet_Malloc(sizeof(struct route_list) + 
578                                                (sizeof(struct vnet_route_info *) * num_matches));
579
580
581     if (!matches) {
582         PrintError("VNET/P Core: Unable to allocate matches\n");
583         return NULL;
584     }
585
586     matches->num_routes = num_matches;
587
588     i=0;
589     list_for_each_entry(route, &match_list, match_node) {
590         if (i==num_matches) { 
591             // the list should never have more than num_matches on it...
592             PrintError("Weird list behavior\n");
593             break;
594         } else {
595             matches->routes[i++] = route;
596         }
597        
598     }
599
600     return matches;
601 }
602
603 int v3_vnet_query_header(uint8_t src_mac[ETH_ALEN], 
604                          uint8_t dest_mac[ETH_ALEN],
605                          int     recv,         // 0 = send, 1=recv
606                          struct v3_vnet_header *header)
607 {
608     struct route_list *routes;
609     struct vnet_route_info *r;
610     struct v3_vnet_pkt p;
611     void *flags;
612
613     p.size=14;
614     p.data=p.header;
615     memcpy(p.header,dest_mac,ETH_ALEN);
616     memcpy(p.header+ETH_ALEN,src_mac,ETH_ALEN);
617     memset(p.header+12,0,2);
618
619     p.src_type = LINK_EDGE;
620     p.src_id = 0;
621
622     memcpy(header->src_mac,src_mac,ETH_ALEN);
623     memcpy(header->dst_mac,dest_mac,ETH_ALEN);
624
625
626     flags = vnet_lock_irqsave(vnet_state.lock);
627     
628     look_into_cache(&p,&routes);
629
630     if (!routes) { 
631         routes = match_route(&p);
632         if (!routes) { 
633             vnet_unlock_irqrestore(vnet_state.lock,flags);
634             PrintError("Cannot match route\n");
635             header->header_type=VNET_HEADER_NOMATCH;
636             header->header_len=0;
637             return -1;
638         } else {
639             add_route_to_cache(&p,routes);
640         }
641     }
642
643     vnet_unlock_irqrestore(vnet_state.lock,flags);
644     
645     if (routes->num_routes<1) { 
646         PrintError("Less than one route\n");
647         header->header_type=VNET_HEADER_NOMATCH;
648         header->header_len=0;
649         return -1;
650     }
651
652     if (routes->num_routes>1) { 
653         PrintError("More than one route, building header for the first one only\n");
654     }
655
656     r=routes->routes[0];
657
658     switch (r->route_def.dst_type) {
659         case LINK_EDGE: {
660             // switch based on the link type
661             // for mac-in-udp, we would want to generate a mac, ip, and udp header
662             // direct transmission
663
664             // for now we will say we have no encapsulation
665             //
666             header->header_type=VNET_HEADER_NONE;
667             header->header_len=0;
668             header->src_mac_qual=r->route_def.src_mac_qual;
669             header->dst_mac_qual=r->route_def.dst_mac_qual;
670             
671         }
672             
673             return 0;
674             break;
675             
676
677         case LINK_INTERFACE:
678             // direct transmission
679             // let's guess that it goes to the same interface...
680             header->header_type=VNET_HEADER_NONE;
681             header->header_len=0;
682             header->src_mac_qual=r->route_def.src_mac_qual;
683             header->dst_mac_qual=r->route_def.dst_mac_qual;
684
685             return 0;
686             break;
687
688         default:
689             PrintError("Unknown destination type\n");
690             return -1;
691             break;
692
693     }
694     
695 }
696
697
698
699
700 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
701     struct route_list * matched_routes = NULL;
702     vnet_intr_flags_t flags;
703     int i;
704
705     int cpu = V3_Get_CPU();
706
707     Vnet_Print(2, "VNET/P Core: cpu %d: pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n",
708                cpu, pkt->size, pkt->src_id, 
709                pkt->src_type, pkt->dst_id, pkt->dst_type);
710
711     if(net_debug >= 4){
712         v3_hexdump(pkt->data, pkt->size, NULL, 0);
713     }
714
715     flags = vnet_lock_irqsave(vnet_state.lock);
716
717     vnet_state.stats.rx_bytes += pkt->size;
718     vnet_state.stats.rx_pkts++;
719
720     look_into_cache(pkt, &matched_routes);
721
722     if (matched_routes == NULL) {  
723         PrintDebug("VNET/P Core: sending pkt - matching route\n");
724         
725         matched_routes = match_route(pkt);
726         
727         if (matched_routes) {
728             add_route_to_cache(pkt, matched_routes);
729         } else {
730             PrintDebug("VNET/P Core: Could not find route for packet... discarding packet\n");
731             vnet_unlock_irqrestore(vnet_state.lock, flags);
732             return 0; /* do we return -1 here?*/
733         }
734     }
735
736     vnet_unlock_irqrestore(vnet_state.lock, flags);
737
738     PrintDebug("VNET/P Core: send pkt route matches %d\n", matched_routes->num_routes);
739
740     for (i = 0; i < matched_routes->num_routes; i++) {
741         struct vnet_route_info * route = matched_routes->routes[i];
742         
743         if (route->route_def.dst_type == LINK_EDGE) {
744             struct vnet_brg_dev * bridge = vnet_state.bridge;
745             pkt->dst_type = LINK_EDGE;
746             pkt->dst_id = route->route_def.dst_id;
747
748             if (bridge == NULL) {
749                 Vnet_Print(2, "VNET/P Core: No active bridge to sent data to\n");
750                 continue;
751             }
752
753             if(bridge->brg_ops.input(bridge->vm, pkt, bridge->private_data) < 0){
754                 Vnet_Print(2, "VNET/P Core: Packet not sent properly to bridge\n");
755                 continue;
756             }         
757             vnet_state.stats.tx_bytes += pkt->size;
758             vnet_state.stats.tx_pkts ++;
759         } else if (route->route_def.dst_type == LINK_INTERFACE) {
760             if (route->dst_dev == NULL){
761                   Vnet_Print(2, "VNET/P Core: No active device to sent data to\n");
762                 continue;
763             }
764
765             if(route->dst_dev->dev_ops.input(route->dst_dev->vm, pkt, route->dst_dev->private_data) < 0) {
766                 Vnet_Print(2, "VNET/P Core: Packet not sent properly\n");
767                 continue;
768             }
769             vnet_state.stats.tx_bytes += pkt->size;
770             vnet_state.stats.tx_pkts ++;
771         } else {
772             Vnet_Print(0, "VNET/P Core: Wrong dst type\n");
773         }
774     }
775     
776     return 0;
777 }
778
779
780 int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, 
781                     struct v3_vnet_dev_ops * ops, int quote, int poll_state,
782                     void * priv_data){
783     struct vnet_dev * new_dev = NULL;
784     vnet_intr_flags_t flags;
785
786     new_dev = (struct vnet_dev *)Vnet_Malloc(sizeof(struct vnet_dev)); 
787
788     if (new_dev == NULL) {
789         Vnet_Print(0, "VNET/P Core: Unable to allocate a new device\n");
790         return -1;
791     }
792    
793     memcpy(new_dev->mac_addr, mac, ETH_ALEN);
794     new_dev->dev_ops.input = ops->input;
795     new_dev->dev_ops.poll = ops->poll;
796     new_dev->private_data = priv_data;
797     new_dev->vm = vm;
798     new_dev->dev_id = 0;
799     new_dev->quote = quote<VNET_MAX_QUOTE ? quote : VNET_MAX_QUOTE;
800     new_dev->poll = poll_state;
801
802     flags = vnet_lock_irqsave(vnet_state.lock);
803
804     if (dev_by_mac(mac) == NULL) {
805         list_add(&(new_dev->node), &(vnet_state.devs));
806         new_dev->dev_id = ++ vnet_state.dev_idx;
807         vnet_state.num_devs ++;
808
809         if(new_dev->poll) {
810             v3_enqueue(vnet_state.poll_devs, (addr_t)new_dev);
811         }
812     } else {
813         PrintError("VNET/P: Device with the same MAC has already been added\n");
814     }
815
816     vnet_unlock_irqrestore(vnet_state.lock, flags);
817
818     /* if the device was found previosly the id should still be 0 */
819     if (new_dev->dev_id == 0) {
820         Vnet_Print(0, "VNET/P Core: Device Already exists\n");
821         return -1;
822     }
823
824     PrintDebug("VNET/P Core: Add Device: dev_id %d\n", new_dev->dev_id);
825
826     return new_dev->dev_id;
827 }
828
829
830 int v3_vnet_del_dev(int dev_id){
831     struct vnet_dev * dev = NULL;
832     vnet_intr_flags_t flags;
833
834     flags = vnet_lock_irqsave(vnet_state.lock);
835         
836     dev = dev_by_id(dev_id);
837     if (dev != NULL){
838         list_del(&(dev->node));
839         //del_routes_by_dev(dev_id);
840         vnet_state.num_devs --;
841     }
842         
843     vnet_unlock_irqrestore(vnet_state.lock, flags);
844
845     Vnet_Free(dev);
846
847     PrintDebug("VNET/P Core: Removed Device: dev_id %d\n", dev_id);
848
849     return 0;
850 }
851
852
853 int v3_vnet_stat(struct vnet_stat * stats){
854     stats->rx_bytes = vnet_state.stats.rx_bytes;
855     stats->rx_pkts = vnet_state.stats.rx_pkts;
856     stats->tx_bytes = vnet_state.stats.tx_bytes;
857     stats->tx_pkts = vnet_state.stats.tx_pkts;
858
859     return 0;
860 }
861
862 static void deinit_devices_list(){
863     struct vnet_dev * dev, * tmp; 
864
865     list_for_each_entry_safe(dev, tmp, &(vnet_state.devs), node) {
866         list_del(&(dev->node));
867         Vnet_Free(dev);
868     }
869 }
870
871 static void deinit_routes_list(){
872     struct vnet_route_info * route, * tmp; 
873
874     list_for_each_entry_safe(route, tmp, &(vnet_state.routes), node) {
875         list_del(&(route->node));
876         list_del(&(route->match_node));
877         Vnet_Free(route);
878     }
879 }
880
881 int v3_vnet_add_bridge(struct v3_vm_info * vm,
882                        struct v3_vnet_bridge_ops * ops,
883                        uint8_t type,
884                        void * priv_data) {
885     vnet_intr_flags_t flags;
886     int bridge_free = 0;
887     struct vnet_brg_dev * tmp_bridge = NULL;    
888     
889     flags = vnet_lock_irqsave(vnet_state.lock);
890     if (vnet_state.bridge == NULL) {
891         bridge_free = 1;
892         vnet_state.bridge = (void *)1;
893     }
894     vnet_unlock_irqrestore(vnet_state.lock, flags);
895
896     if (bridge_free == 0) {
897         PrintError("VNET/P Core: Bridge already set\n");
898         return -1;
899     }
900
901     tmp_bridge = (struct vnet_brg_dev *)Vnet_Malloc(sizeof(struct vnet_brg_dev));
902
903     if (tmp_bridge == NULL) {
904         PrintError("VNET/P Core: Unable to allocate new bridge\n");
905         vnet_state.bridge = NULL;
906         return -1;
907     }
908     
909     tmp_bridge->vm = vm;
910     tmp_bridge->brg_ops.input = ops->input;
911     tmp_bridge->brg_ops.poll = ops->poll;
912     tmp_bridge->private_data = priv_data;
913     tmp_bridge->type = type;
914         
915     /* make this atomic to avoid possible race conditions */
916     flags = vnet_lock_irqsave(vnet_state.lock);
917     vnet_state.bridge = tmp_bridge;
918     vnet_unlock_irqrestore(vnet_state.lock, flags);
919
920     return 0;
921 }
922
923
924 void v3_vnet_del_bridge(uint8_t type) {
925     vnet_intr_flags_t flags;
926     struct vnet_brg_dev * tmp_bridge = NULL;    
927     
928     flags = vnet_lock_irqsave(vnet_state.lock);
929         
930     if (vnet_state.bridge != NULL && vnet_state.bridge->type == type) {
931         tmp_bridge = vnet_state.bridge;
932         vnet_state.bridge = NULL;
933     }
934         
935     vnet_unlock_irqrestore(vnet_state.lock, flags);
936
937     if (tmp_bridge) {
938         Vnet_Free(tmp_bridge);
939     }
940 }
941
942
943 /* can be instanieoued to multiple threads
944   * that runs on multiple cores 
945   * or it could be running on a dedicated side core
946   */
947 static int vnet_tx_flush(void * args){
948     struct vnet_dev * dev = NULL;
949     int more;
950     int rc;
951     uint64_t noprogress_count;
952
953     Vnet_Print(0, "VNET/P Polling Thread Starting ....\n");
954
955     // since there are multiple instances of this thread, and only
956     // one queue of pollable devices, our model here will be to synchronize
957     // on that queue, removing devices as we go, and keeping them
958     // then putting them back on the queue when we are done
959     // in this way, multiple instances of this function will never
960     // be polling the same device at the same time
961
962     struct v3_queue * tq = v3_create_queue();
963
964     if (!tq) { 
965         PrintError("VNET/P polling thread cannot allocate queue\n");
966         return -1;
967     }
968
969     noprogress_count = 0;
970     
971     while (!vnet_thread_should_stop()) {
972
973         more=0; // will indicate if any device has more work for us to do
974
975         while ((dev = (struct vnet_dev *)v3_dequeue(vnet_state.poll_devs))) { 
976             // we are handling this device
977             v3_enqueue(tq,(addr_t)dev);
978             
979             if (dev->poll && dev->dev_ops.poll) {
980                 // The device's poll function MUST NOT BLOCK
981                 rc = dev->dev_ops.poll(dev->vm, dev->quote, dev->private_data);
982
983                 if (rc<0) { 
984                     Vnet_Print(0, "VNET/P: poll from device %p error (ignoring) !\n", dev);
985                 } else {
986                     more |= rc;  
987                 }
988             }
989         }
990         
991         while ((dev = (struct vnet_dev *)v3_dequeue(tq))) { 
992             // now someone else can handle it
993             v3_enqueue(vnet_state.poll_devs, (addr_t)dev); 
994         }
995
996
997         if (more) { 
998             noprogress_count=0;
999         } else {
1000             if ( ! ((noprogress_count+1) < noprogress_count)) {
1001                 noprogress_count++;
1002             }
1003         }
1004
1005         // adaptively yield 
1006         if ((!VNET_ADAPTIVE_TX_KICK) || (noprogress_count < VNET_NOPROGRESS_LIMIT)) { 
1007             V3_Yield();
1008         } else {
1009             V3_Yield_Timed(VNET_YIELD_USEC);
1010         }
1011
1012     }
1013
1014     Vnet_Free(tq);
1015     
1016     Vnet_Print(0, "VNET/P Polling Thread Done.\n");
1017
1018     return 0;
1019 }
1020
1021 int v3_init_vnet() 
1022 {
1023     int i;
1024
1025     memset(&vnet_state, 0, sizeof(vnet_state));
1026         
1027     INIT_LIST_HEAD(&(vnet_state.routes));
1028     INIT_LIST_HEAD(&(vnet_state.devs));
1029
1030     vnet_state.num_devs = 0;
1031     vnet_state.num_routes = 0;
1032
1033     if (vnet_lock_init(&(vnet_state.lock)) == -1){
1034         PrintError("VNET/P: Fails to initiate lock\n");
1035     }
1036
1037     vnet_state.route_cache = vnet_create_htable(0, &hash_fn, &hash_eq);
1038     if (vnet_state.route_cache == NULL) {
1039         PrintError("VNET/P: Fails to initiate route cache\n");
1040         return -1;
1041     }
1042
1043     vnet_state.poll_devs = v3_create_queue();
1044
1045     for (i=0; i<VNET_NUM_TX_KICK_THREADS;i++) { 
1046         char name[32];
1047         snprintf(name,32,"vnetd-%d",i);
1048         vnet_state.pkt_flush_thread[i] = vnet_start_thread(vnet_tx_flush, NULL, name);
1049     }
1050
1051     PrintDebug("VNET/P is initiated (%d tx kick threads active)\n",VNET_NUM_TX_KICK_THREADS);
1052
1053     return 0;
1054 }
1055
1056
1057 void v3_deinit_vnet() 
1058 {
1059     int i;
1060
1061     v3_deinit_queue(vnet_state.poll_devs);
1062     Vnet_Free(vnet_state.poll_devs);
1063
1064     for (i=0; i<VNET_NUM_TX_KICK_THREADS;i++) { 
1065         PrintDebug("Stopping tx kick thread %d\n",i);
1066         // This will pause until the flush thread is gone
1067         vnet_thread_stop(vnet_state.pkt_flush_thread[i]);
1068     }
1069
1070     // At this point there should be no lock-holder
1071
1072     Vnet_Free(vnet_state.poll_devs);
1073
1074
1075     PrintDebug("Deiniting Device List\n");
1076     // close any devices we have open
1077     deinit_devices_list();  
1078     
1079     PrintDebug("Deiniting Route List\n");
1080     // remove any routes we have
1081     deinit_routes_list();
1082
1083     PrintDebug("Freeing hash table\n");
1084     // remove the hash table
1085     vnet_free_htable(vnet_state.route_cache, 1, 1);
1086
1087     
1088     PrintDebug("Removing Bridge\n");
1089     // remove bridge if it was added
1090     if (vnet_state.bridge) { 
1091         Vnet_Free(vnet_state.bridge);
1092     }
1093
1094     PrintDebug("Deleting lock\n");
1095     // eliminate the lock
1096     vnet_lock_deinit(&(vnet_state.lock));
1097
1098 }
1099
1100