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.


1ec015ee8ab7cc2f100365ba9080da5fd6f7d3f6
[palacios.git] / palacios / src / palacios / vmm_vnet.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 <palacios/vmm_vnet.h>
23 #include <palacios/vm_guest_mem.h>
24 #include <palacios/vmm_lock.h>
25 #include <palacios/vmm_queue.h>
26 #include <palacios/vmm_sprintf.h>
27
28 #ifndef CONFIG_DEBUG_VNET
29 #undef PrintDebug
30 #define PrintDebug(fmt, args...)
31 #endif
32
33
34 /* for UDP encapuslation */
35 struct eth_header {
36     uchar_t dest[6];
37     uchar_t src[6];
38     uint16_t type;
39 }__attribute__((packed));
40
41 struct ip_header {
42     uint8_t version: 4;
43     uint8_t hdr_len: 4;
44     uchar_t tos;
45     uint16_t total_len;
46     uint16_t id;
47     uint8_t flags:     3;
48     uint16_t offset: 13;
49     uchar_t ttl;
50     uchar_t proto;
51     uint16_t cksum;
52     uint32_t src_addr;
53     uint32_t dst_addr;
54 }__attribute__((packed));
55
56 struct udp_header {
57     uint16_t src_port;
58     uint16_t dst_port;
59     uint16_t len;
60     uint16_t csum;//set to zero, disable the xsum
61 }__attribute__((packed));
62
63 struct udp_link_header {
64     struct eth_header eth_hdr;
65     struct ip_header ip_hdr;
66     struct udp_header udp_hdr;
67 }__attribute__((packed));
68 /* end with UDP encapuslation structures */
69
70
71
72
73 struct eth_hdr {
74     uint8_t dst_mac[6];
75     uint8_t src_mac[6];
76     uint16_t type; /* indicates layer 3 protocol type */
77 } __attribute__((packed));
78
79
80 struct vnet_dev {
81     int dev_id;
82     uint8_t mac_addr[6];
83     struct v3_vm_info * vm;
84     struct v3_vnet_dev_ops dev_ops;
85     void * private_data;
86
87     int rx_disabled;
88     
89     struct list_head node;
90 } __attribute__((packed));
91
92
93 struct vnet_brg_dev {
94     struct v3_vm_info * vm;
95     struct v3_vnet_bridge_ops brg_ops;
96
97     int disabled;
98     void * private_data;
99 } __attribute__((packed));
100
101
102
103 struct vnet_route_info {
104     struct v3_vnet_route route_def;
105
106     struct vnet_dev * dst_dev;
107     struct vnet_dev * src_dev;
108
109     struct list_head node;
110     struct list_head match_node; // used for route matching
111 };
112
113
114 struct route_list {
115     uint8_t hash_buf[VNET_HASH_SIZE];
116
117     uint32_t num_routes;
118     struct vnet_route_info * routes[0];
119 } __attribute__((packed));
120
121
122 #define BUF_SIZE 4096
123 struct pkts_buf {
124     int start, end;
125     int num; 
126     v3_lock_t lock;
127     struct v3_vnet_pkt pkts[BUF_SIZE];
128 };
129
130
131 static struct {
132     struct list_head routes;
133     struct list_head devs;
134     
135     int num_routes;
136     int num_devs;
137
138     struct vnet_brg_dev *bridge;
139
140     v3_lock_t lock;
141
142     uint8_t sidecores; /* 0 -vnet not running on sidecore, > 0, number of extra cores that can be used by VNET */
143     uint64_t cores_map; /* bitmaps for which cores can be used by VNET for sidecore, maxium 64 */
144
145     struct hashtable * route_cache;
146 } vnet_state;
147
148
149
150
151 #ifdef CONFIG_DEBUG_VNET
152 static inline void mac_to_string(char mac[6], char * buf) {
153     snprintf(buf, 100, "%d:%d:%d:%d:%d:%d", 
154              mac[0], mac[1], mac[2],
155              mac[3], mac[4], mac[5]);
156 }
157
158 static void print_route(struct vnet_route_info *route){
159     char str[50];
160
161     mac_to_string(route->route_def.src_mac, str);
162     PrintDebug("Src Mac (%s),  src_qual (%d)\n", 
163                         str, route->route_def.src_mac_qual);
164     mac_to_string(route->route_def.dst_mac, str);
165     PrintDebug("Dst Mac (%s),  dst_qual (%d)\n", 
166                         str, route->route_def.dst_mac_qual);
167     PrintDebug("Src dev id (%d), src type (%d)", 
168                         route->route_def.src_id, 
169                         route->route_def.src_type);
170     PrintDebug("Dst dev id (%d), dst type (%d)\n", 
171                         route->route_def.dst_id, 
172                         route->route_def.dst_type);
173     if (route->route_def.dst_type == LINK_INTERFACE) {
174         PrintDebug("dst_dev (%p), dst_dev_id (%d), dst_dev_ops(%p), dst_dev_data (%p)\n",
175                                         route->dst_dev,
176                                         route->dst_dev->dev_id,
177                                         (void *)&(route->dst_dev->dev_ops),
178                                         route->dst_dev->private_data);
179     }
180 }
181
182 static void dump_routes(){
183         struct vnet_route_info *route;
184
185         int i = 0;
186         PrintDebug("\n========Dump routes starts ============\n");
187         list_for_each_entry(route, &(vnet_state.routes), node) {
188                 PrintDebug("\nroute %d:\n", ++i);
189                 
190                 print_route(route);
191         }
192         PrintDebug("\n========Dump routes end ============\n");
193 }
194
195 #endif
196
197
198 /* 
199  * A VNET packet is a packed struct with the hashed fields grouped together.
200  * This means we can generate the hash from an offset into the pkt struct
201  */
202 static inline uint_t hash_fn(addr_t hdr_ptr) {    
203     uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
204
205     return v3_hash_buffer(hdr_buf, VNET_HASH_SIZE);
206 }
207
208 static inline int hash_eq(addr_t key1, addr_t key2) {   
209     return (memcmp((uint8_t *)key1, (uint8_t *)key2, VNET_HASH_SIZE) == 0);
210 }
211
212 static int add_route_to_cache(const struct v3_vnet_pkt * pkt, struct route_list * routes) {
213     memcpy(routes->hash_buf, pkt->hash_buf, VNET_HASH_SIZE);    
214
215     if (v3_htable_insert(vnet_state.route_cache, (addr_t)routes->hash_buf, (addr_t)routes) == 0) {
216         PrintError("Vnet: Failed to insert new route entry to the cache\n");
217         return -1;
218     }
219     
220     return 0;
221 }
222
223 static int clear_hash_cache() {
224
225     v3_free_htable(vnet_state.route_cache, 1, 1);
226     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
227
228     return 0;
229 }
230
231 static int look_into_cache(const struct v3_vnet_pkt * pkt, struct route_list ** routes) {
232     
233     *routes = (struct route_list *)v3_htable_search(vnet_state.route_cache, (addr_t)(pkt->hash_buf));
234    
235     return 0;
236 }
237
238
239 static struct vnet_dev * find_dev_by_id(int idx) {
240     struct vnet_dev * dev = NULL; 
241
242     list_for_each_entry(dev, &(vnet_state.devs), node) {
243         int dev_id = dev->dev_id;
244
245         if (dev_id == idx)
246             return dev;
247     }
248
249     return NULL;
250 }
251
252 static struct vnet_dev * find_dev_by_mac(char mac[6]) {
253     struct vnet_dev * dev = NULL; 
254     
255     list_for_each_entry(dev, &(vnet_state.devs), node) {
256         if (!memcmp(dev->mac_addr, mac, 6))
257             return dev;
258     }
259
260     return NULL;
261 }
262
263 int v3_vnet_id_by_mac(char mac[6]){
264
265     struct vnet_dev *dev = find_dev_by_mac(mac);
266
267     if (dev == NULL)
268         return -1;
269
270     return dev->dev_id;
271 }
272
273
274 int v3_vnet_add_route(struct v3_vnet_route route) {
275     struct vnet_route_info * new_route = NULL;
276     unsigned long flags; 
277
278     new_route = (struct vnet_route_info *)V3_Malloc(sizeof(struct vnet_route_info));
279     memset(new_route, 0, sizeof(struct vnet_route_info));
280
281     PrintDebug("Vnet: vnet_add_route_entry: dst_id: %d, dst_type: %d\n",
282                         route.dst_id, route.dst_type);  
283     
284     memcpy(new_route->route_def.src_mac, route.src_mac, 6);
285     memcpy(new_route->route_def.dst_mac, route.dst_mac, 6);
286     new_route->route_def.src_mac_qual = route.src_mac_qual;
287     new_route->route_def.dst_mac_qual = route.dst_mac_qual;
288     new_route->route_def.dst_id = route.dst_id;
289     new_route->route_def.dst_type = route.dst_type;
290     new_route->route_def.src_id = route.src_id;
291     new_route->route_def.src_type = route.src_type;
292
293     if (new_route->route_def.dst_type == LINK_INTERFACE) {
294         new_route->dst_dev = find_dev_by_id(new_route->route_def.dst_id);
295     }
296
297     if (new_route->route_def.src_type == LINK_INTERFACE) {
298         new_route->src_dev = find_dev_by_id(new_route->route_def.src_id);
299     }
300
301     flags = v3_lock_irqsave(vnet_state.lock);
302
303     list_add(&(new_route->node), &(vnet_state.routes));
304     clear_hash_cache();
305
306     v3_unlock_irqrestore(vnet_state.lock, flags);
307    
308
309 #ifdef CONFIG_DEBUG_VNET
310     dump_routes();
311 #endif
312
313     return 0;
314 }
315
316
317
318 /* At the end allocate a route_list
319  * This list will be inserted into the cache so we don't need to free it
320  */
321 static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
322     struct vnet_route_info * route = NULL; 
323     struct route_list * matches = NULL;
324     int num_matches = 0;
325     int max_rank = 0;
326     struct list_head match_list;
327     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
328     uint8_t src_type = pkt->src_type;
329     uint32_t src_link = pkt->src_id;
330
331 #ifdef CONFIG_DEBUG_VNET
332     {
333         char dst_str[100];
334         char src_str[100];
335
336         mac_to_string(hdr->src_mac, src_str);  
337         mac_to_string(hdr->dst_mac, dst_str);
338         PrintDebug("Vnet: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
339     }
340 #endif
341
342     INIT_LIST_HEAD(&match_list);
343     
344 #define UPDATE_MATCHES(rank) do {                               \
345         if (max_rank < (rank)) {                                \
346             max_rank = (rank);                                  \
347             INIT_LIST_HEAD(&match_list);                        \
348                                                                 \
349             list_add(&(route->match_node), &match_list);        \
350             num_matches = 1;                                    \
351         } else if (max_rank == (rank)) {                        \
352             list_add(&(route->match_node), &match_list);        \
353             num_matches++;                                      \
354         }                                                       \
355     } while (0)
356     
357
358     list_for_each_entry(route, &(vnet_state.routes), node) {
359         struct v3_vnet_route * route_def = &(route->route_def);
360
361         // CHECK SOURCE TYPE HERE
362         if ( (route_def->src_type != LINK_ANY) && 
363              ( (route_def->src_type != src_type) || 
364                ( (route_def->src_id != src_link) &&
365                  (route_def->src_id != (uint32_t)-1)))) {
366             continue;
367         }
368
369
370         if ((route_def->dst_mac_qual == MAC_ANY) &&
371             (route_def->src_mac_qual == MAC_ANY)) {      
372             UPDATE_MATCHES(3);
373         }
374         
375         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
376             if (route_def->src_mac_qual != MAC_NOT) {
377                 if (route_def->dst_mac_qual == MAC_ANY) {
378                     UPDATE_MATCHES(6);
379                 } else if (route_def->dst_mac_qual != MAC_NOT &&
380                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
381                     UPDATE_MATCHES(8);
382                 }
383             }
384         }
385             
386         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
387             if (route_def->dst_mac_qual != MAC_NOT) {
388                 if (route_def->src_mac_qual == MAC_ANY) {
389                     UPDATE_MATCHES(6);
390                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
391                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
392                     UPDATE_MATCHES(8);
393                 }
394             }
395         }
396             
397         if ((route_def->dst_mac_qual == MAC_NOT) &&
398             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
399             if (route_def->src_mac_qual == MAC_ANY) {
400                 UPDATE_MATCHES(5);
401             } else if ((route_def->src_mac_qual != MAC_NOT) && 
402                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
403                 UPDATE_MATCHES(7);
404             }
405         }
406         
407         if ((route_def->src_mac_qual == MAC_NOT) &&
408             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
409             if (route_def->dst_mac_qual == MAC_ANY) {
410                 UPDATE_MATCHES(5);
411             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
412                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
413                 UPDATE_MATCHES(7);
414             }
415         }
416         
417         // Default route
418         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &&
419              (route_def->dst_mac_qual == MAC_NONE)) {
420             UPDATE_MATCHES(4);
421         }
422     }
423
424     PrintDebug("Vnet: match_route: Matches=%d\n", num_matches);
425
426     if (num_matches == 0) {
427         return NULL;
428     }
429
430     matches = (struct route_list *)V3_Malloc(sizeof(struct route_list) + 
431                                 (sizeof(struct vnet_route_info *) * num_matches));
432
433     matches->num_routes = num_matches;
434
435     {
436         int i = 0;
437         list_for_each_entry(route, &match_list, match_node) {
438             matches->routes[i++] = route;
439         }
440     }
441
442     return matches;
443 }
444
445 static int send_to_bridge(struct v3_vnet_pkt * pkt){
446     struct vnet_brg_dev *bridge = vnet_state.bridge;
447
448     if (bridge == NULL) {
449         PrintError("VNET: No bridge to sent data to links\n");
450         return -1;
451     }
452
453     return bridge->brg_ops.input(bridge->vm, pkt, 1, bridge->private_data);
454 }
455
456
457 /* enable a vnet device, notify VNET it can send pkts to it */
458 int v3_vnet_enable_device(int dev_id){
459     struct vnet_dev *dev = find_dev_by_id(dev_id);
460     unsigned long flags;
461
462     if(!dev)
463         return -1;
464
465     if(!dev->rx_disabled)
466         return 0;
467
468     flags = v3_lock_irqsave(vnet_state.lock);
469     dev->rx_disabled = 0;
470     v3_unlock_irqrestore(vnet_state.lock, flags);
471
472     /* TODO: Wake up all other guests who are trying to send pkts */
473     dev = NULL;
474     list_for_each_entry(dev, &(vnet_state.devs), node) {
475         if (dev->dev_id != dev_id)
476             dev->dev_ops.start_tx(dev->private_data);
477     }
478
479     return 0;
480 }
481
482 /* Notify VNET to stop sending pkts to it */
483 int v3_vnet_disable_device(int dev_id){
484     struct vnet_dev *dev = find_dev_by_id(dev_id);
485     unsigned long flags;
486
487     if(!dev)
488         return -1;
489
490     flags = v3_lock_irqsave(vnet_state.lock);
491     dev->rx_disabled = 1;
492     v3_unlock_irqrestore(vnet_state.lock, flags);
493
494
495     /* TODO: Notify all other guests to stop send pkts */
496     dev = NULL;
497     list_for_each_entry(dev, &(vnet_state.devs), node) {
498         if (dev->dev_id != dev_id)
499             dev->dev_ops.stop_tx(dev->private_data);
500     }
501
502     return 0;
503 }
504
505 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
506     struct route_list * matched_routes = NULL;
507     unsigned long flags;
508     int i;
509
510 #ifdef CONFIG_DEBUG_VNET
511    {
512         struct eth_hdr * hdr = (struct eth_hdr *)(pkt->header);
513         char dest_str[100];
514         char src_str[100];
515
516         mac_to_string(hdr->src_mac, src_str);  
517         mac_to_string(hdr->dst_mac, dest_str);
518         int cpu = V3_Get_CPU();
519         PrintDebug("Vnet: on cpu %d, HandleDataOverLink. SRC(%s), DEST(%s), pkt size: %d\n", cpu, src_str, dest_str, pkt->size);
520    }
521 #endif
522
523     flags = v3_lock_irqsave(vnet_state.lock);
524
525     look_into_cache(pkt, &matched_routes);
526         
527     if (matched_routes == NULL) {  
528         PrintError("Vnet: send pkt Looking into routing table\n");
529         
530         matched_routes = match_route(pkt);
531         
532         if (matched_routes) {
533             add_route_to_cache(pkt, matched_routes);
534         } else {
535             PrintDebug("Could not find route for packet... discards packet\n");
536             v3_unlock_irqrestore(vnet_state.lock, flags);
537             return 0; /* do we return -1 here?*/
538         }
539     }
540
541     v3_unlock_irqrestore(vnet_state.lock, flags);
542
543     PrintDebug("Vnet: send pkt route matches %d\n", matched_routes->num_routes);
544
545     for (i = 0; i < matched_routes->num_routes; i++) {
546          struct vnet_route_info * route = matched_routes->routes[i];
547         
548         if (route->route_def.dst_type == LINK_EDGE) {                   
549             pkt->dst_type = LINK_EDGE;
550             pkt->dst_id = route->route_def.dst_id;
551
552             if (send_to_bridge(pkt) == -1) {
553                 PrintDebug("VNET: Packet not sent properly to bridge\n");
554                 continue;
555              }         
556         } else if (route->route_def.dst_type == LINK_INTERFACE) {
557             if (!route->dst_dev->rx_disabled){ 
558                   if(route->dst_dev->dev_ops.input(route->dst_dev->vm, pkt, route->dst_dev->private_data) == -1) {
559                         PrintDebug("VNET: Packet not sent properly\n");
560                         continue;
561                   }
562              }
563         } else {
564             PrintError("VNET: Wrong Edge type\n");
565         }
566
567         PrintDebug("VNET: Forward one packet according to Route %d\n", i);
568     }
569     
570     return 0;
571 }
572
573 int v3_vnet_add_dev(struct v3_vm_info *vm, uint8_t mac[6], 
574                     struct v3_vnet_dev_ops *ops,
575                     void * priv_data){
576     struct vnet_dev * new_dev = NULL;
577     unsigned long flags;
578
579     new_dev = (struct vnet_dev *)V3_Malloc(sizeof(struct vnet_dev)); 
580
581     if (new_dev == NULL) {
582         PrintError("VNET: Malloc fails\n");
583         return -1;
584     }
585    
586     memcpy(new_dev->mac_addr, mac, 6);
587     new_dev->dev_ops.input = ops->input;
588     new_dev->dev_ops.poll = ops->poll;
589     new_dev->private_data = priv_data;
590     new_dev->vm = vm;
591     new_dev->dev_id = 0;        
592
593     flags = v3_lock_irqsave(vnet_state.lock);
594
595     if (!find_dev_by_mac(mac)) {
596         list_add(&(new_dev->node), &(vnet_state.devs));
597         new_dev->dev_id = ++vnet_state.num_devs;
598     }
599
600     v3_unlock_irqrestore(vnet_state.lock, flags);
601
602     /* if the device was found previosly the id should still be 0 */
603     if (new_dev->dev_id == 0) {
604         PrintError("Device Alrady exists\n");
605         return -1;
606     }
607
608     PrintDebug("Vnet: Add Device: dev_id %d\n", new_dev->dev_id);
609
610     return new_dev->dev_id;
611 }
612
613
614 /* TODO: Still need to figure out how to handle this multicore part --Lei
615   */
616 void  v3_vnet_poll(struct v3_vm_info *vm){
617     struct vnet_dev * dev = NULL; 
618
619     switch (vnet_state.sidecores) {
620         case 0:
621                 list_for_each_entry(dev, &(vnet_state.devs), node) {
622                     if(dev->vm == vm){
623                         dev->dev_ops.poll(vm, dev->private_data);
624                     }
625                }
626                 break;
627         case 1:
628                 break;
629         case 2:
630             list_for_each_entry(dev, &(vnet_state.devs), node) {
631                 int cpu_id = vm->cores[0].cpu_id + 2; /* temporary here, should use vnet_state.cores_map */
632                 struct v3_vnet_dev_xcall_args dev_args; /* could cause problem here -LX */
633                 dev_args.vm = vm;
634                 dev_args.private_data = dev->private_data;
635                 V3_Call_On_CPU(cpu_id, dev->dev_ops.poll_xcall, (void *)&dev_args);
636             }
637             break;
638         default:
639             break;
640     }
641 }
642
643 int v3_vnet_add_bridge(struct v3_vm_info * vm,
644                        struct v3_vnet_bridge_ops *ops,
645                        void * priv_data) {
646     unsigned long flags;
647     int bridge_free = 0;
648     struct vnet_brg_dev * tmp_bridge = NULL;    
649     
650     flags = v3_lock_irqsave(vnet_state.lock);
651
652     if (vnet_state.bridge == NULL) {
653         bridge_free = 1;
654         vnet_state.bridge = (void *)1;
655     }
656
657     v3_unlock_irqrestore(vnet_state.lock, flags);
658
659     if (bridge_free == 0) {
660         PrintError("Bridge already set\n");
661         return -1;
662     }
663
664     tmp_bridge = (struct vnet_brg_dev *)V3_Malloc(sizeof(struct vnet_brg_dev));
665
666     if (tmp_bridge == NULL) {
667         PrintError("Malloc Fails\n");
668         vnet_state.bridge = NULL;
669         return -1;
670     }
671     
672     tmp_bridge->vm = vm;
673     tmp_bridge->brg_ops.input = ops->input;
674     tmp_bridge->brg_ops.xcall_input = ops->xcall_input;
675     tmp_bridge->brg_ops.polling_pkt = ops->polling_pkt;
676     tmp_bridge->private_data = priv_data;
677     tmp_bridge->disabled = 0;
678         
679     /* make this atomic to avoid possible race conditions */
680     flags = v3_lock_irqsave(vnet_state.lock);
681     vnet_state.bridge = tmp_bridge;
682     v3_unlock_irqrestore(vnet_state.lock, flags);
683
684     return 0;
685 }
686
687
688 #if 0
689 int v3_vnet_disable_bridge() {
690     unsigned long flags; 
691     
692     flags = v3_lock_irqsave(vnet_state.lock);
693
694     if (vnet_state.bridge != NULL) {
695         vnet_state.bridge->disabled = 1;
696     }
697
698     v3_unlock_irqrestore(vnet_state.lock, flags);
699
700     return 0;
701 }
702
703
704 int v3_vnet_enable_bridge() {
705     unsigned long flags; 
706     
707     flags = v3_lock_irqsave(vnet_state.lock);
708
709     if (vnet_state.bridge != NULL) {
710         vnet_state.bridge->disabled = 0;
711     }
712
713     v3_unlock_irqrestore(vnet_state.lock, flags);
714
715     return 0;
716 }
717 #endif
718
719 int v3_init_vnet() {
720     memset(&vnet_state, 0, sizeof(vnet_state));
721         
722     INIT_LIST_HEAD(&(vnet_state.routes));
723     INIT_LIST_HEAD(&(vnet_state.devs));
724
725     vnet_state.num_devs = 0;
726     vnet_state.num_routes = 0;
727
728     PrintDebug("VNET: Links and Routes tables initiated\n");
729
730     if (v3_lock_init(&(vnet_state.lock)) == -1){
731         PrintError("VNET: Failure to init lock for routes table\n");
732     }
733     PrintDebug("VNET: Locks initiated\n");
734
735     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
736
737     if (vnet_state.route_cache == NULL) {
738         PrintError("Vnet: Route Cache Init Fails\n");
739         return -1;
740     }
741
742     vnet_state.sidecores = 0;
743     vnet_state.cores_map = 0;
744
745     PrintDebug("VNET: initiated\n");
746
747     return 0;
748 }