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.


Add initial code for multicore support VNET
[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) 2009, 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/vmm_hypercall.h>
24 #include <palacios/vm_guest_mem.h>
25 #include <palacios/vmm_lock.h>
26
27 #ifndef CONFIG_DEBUG_VNET
28 #undef PrintDebug
29 #define PrintDebug(fmt, args...)
30 #endif
31
32
33 #define ETHERNET_HEADER_LEN 14
34 #define ETHERNET_DATA_MIN   46
35 #define ETHERNET_DATA_MAX   1500
36 #define ETHERNET_PACKET_LEN (ETHERNET_HEADER_LEN + ETHERNET_DATA_MAX)
37
38
39 typedef enum {TCP_TYPE, UDP_TYPE, NONE_TYPE} prot_type_t;
40
41 #define VNET_INITAB_HCALL 0xca00
42
43 struct eth_header {
44     uchar_t dest[6];
45     uchar_t src[6];
46     uint16_t type; // indicates layer 3 protocol type
47 }__attribute__((packed));
48
49 struct ip_header {
50     uint8_t version: 4;
51     uint8_t hdr_len: 4;
52     uchar_t tos;
53     uint16_t total_len;
54     uint16_t id;
55     uint8_t flags:     3;
56     uint16_t offset: 13;
57     uchar_t ttl;
58     uchar_t proto;
59     uint16_t cksum;
60     uint32_t src_addr;
61     uint32_t dst_addr;
62 }__attribute__((packed));
63
64 struct udp_header {
65     uint16_t src_port;
66     uint16_t dst_port;
67     uint16_t len;
68     uint16_t csum;//set to zero, disable the xsum
69 }__attribute__((packed));
70
71 struct udp_link_header {
72     struct eth_header eth_hdr;
73     struct ip_header ip_hdr;
74     struct udp_header udp_hdr;
75 }__attribute__((packed));
76
77
78 struct ethernet_pkt {
79     uint32_t size; //size of data field
80     uint16_t type;
81     uint8_t use_header;
82     struct udp_link_header ext_hdr;
83     char data[ETHERNET_PACKET_LEN];
84 }__attribute__((packed));
85
86
87 #define DEVICE_NAME_LEN 20
88 struct vnet_if_device {
89     char name[DEVICE_NAME_LEN];
90     uchar_t mac_addr[6];
91     struct v3_vm_info *vm;
92     
93     int (*input)(struct v3_vm_info *vm, uchar_t *data, uint32_t len, void *private_data);
94     
95     void *private_data;
96 }__attribute__((packed));
97
98 struct vnet_if_link {
99     prot_type_t pro_type; //transport layer protocal type of this link
100     unsigned long dest_ip;
101     uint16_t dest_port;
102
103     struct udp_link_header vnet_header; //header applied to the packet in/out from this link
104
105     int (*input)(uchar_t *data, uint32_t len, void *private_data);
106     
107     void *private_data;
108 }__attribute__((packed));
109
110
111 struct link_entry {
112     link_type_t type;
113   
114     union {
115         struct vnet_if_device *dst_dev;
116         struct vnet_if_link *dst_link;
117     } __attribute__((packed));
118
119     int use;
120 }__attribute__((packed));
121
122 //routing table entry
123 struct routing_entry {
124     char src_mac[6];
125     char dest_mac[6];
126
127     mac_type_t src_mac_qual;
128     mac_type_t dest_mac_qual;
129
130     int link_idx; //link[dest] is the link to be used to send pkt
131     link_type_t link_type; //EDGE|INTERFACE|ANY
132  
133     int src_link_idx;
134     link_type_t src_type; //EDGE|INTERFACE|ANY
135 };
136
137
138 // 14 (ethernet frame) + 20 bytes
139 struct in_pkt_header {
140     uchar_t ethernetdest[6];
141     uchar_t ethernetsrc[6];
142     uchar_t ethernettype[2]; //layer 3 protocol type
143     char ip[20];
144 }__attribute__((packed));
145
146
147 #define MAX_LINKS 10
148 #define MAX_ROUTES 10
149 #define HASH_KEY_LEN 16
150 #define MIN_CACHE_SIZE 100
151 #define HASH_KEY_SIZE 16
152
153 struct link_table {
154     struct link_entry * links[MAX_LINKS];
155     uint16_t size;
156     v3_lock_t lock;
157 }__attribute__((packed));
158
159 struct routing_table {
160     struct routing_entry * routes[MAX_ROUTES];
161     uint16_t size;
162     v3_lock_t lock;
163 }__attribute__((packed));
164
165 typedef char * route_hashkey_t;
166
167 struct route_cache_entry {
168     int num_matched_routes;
169     int * matches; 
170 };
171
172 struct vnet_state_t {
173     struct link_table g_links;
174     struct routing_table g_routes;
175     struct gen_queue * g_inpkt_q;
176     struct hashtable * g_route_cache;
177     v3_lock_t cache_lock;
178 };
179
180 static struct vnet_state_t g_vnet_state;//global state for vnet
181
182 static uint16_t ip_xsum(struct ip_header *ip_hdr, int hdr_len){
183     long sum = 0;
184
185     uint16_t *p = (uint16_t*) ip_hdr;
186     while(hdr_len > 1){
187         sum += *(p++);
188         if(sum & 0x80000000)
189             sum = (sum & 0xFFFF) + (sum >> 16);
190             hdr_len -= 2;
191         }
192  
193     if(hdr_len) 
194         sum += (uint16_t) *(uchar_t *)p;
195           
196     while(sum>>16)
197         sum = (sum & 0xFFFF) + (sum >> 16);
198
199     return (uint16_t)~sum;
200 }
201
202 static void ethernet_packet_init(struct ethernet_pkt *pt, 
203                                                               uchar_t *data, 
204                                                               const size_t size) {
205     pt->size = size;
206     pt->use_header = 0;
207     memset(&pt->ext_hdr, 0, sizeof(struct udp_link_header));
208     memcpy(pt->data, data, size);
209 }
210
211 static inline uint_t hash_from_key_fn(addr_t hashkey) {    
212     return v3_hash_buffer((uint8_t *)hashkey, HASH_KEY_LEN);
213 }
214
215 static inline int hash_key_equal(addr_t key1, addr_t key2) {
216     return (memcmp((uint8_t *)key1, (uint8_t *)key2, HASH_KEY_LEN) == 0);
217 }
218
219 static int init_route_cache(struct vnet_state_t *vnet_state) {  
220     vnet_state->g_route_cache = v3_create_htable(MIN_CACHE_SIZE, 
221                                                                       &hash_from_key_fn, 
222                                                                       &hash_key_equal);
223
224     if (vnet_state->g_route_cache == NULL) {
225         PrintError("Vnet: Route Cache Init Fails\n");
226         return -1;
227     }
228
229     return 0;
230 }
231
232 static void make_hash_key(route_hashkey_t hashkey,
233                                                 char src_addr[6],
234                                                 char dest_addr[6],
235                                                 char src_type,
236                                                 int src_index) {
237     int j;
238
239     for (j = 0; j < 6; j++) {
240         hashkey[j] = src_addr[j];
241         hashkey[j + 6] = dest_addr[j] + 1;
242     }
243
244     hashkey[12] = src_type;
245
246     *(int *)(hashkey + 12) = src_index;
247 }
248
249 static int add_route_to_cache(route_hashkey_t hashkey, 
250                                                         int num_matched_r, 
251                                                         int * matches) {
252     struct route_cache_entry * new_entry = NULL;
253     struct vnet_state_t *vnet_state = &g_vnet_state;
254     int i;
255     
256     new_entry = (struct route_cache_entry *)V3_Malloc(sizeof(struct route_cache_entry));
257     if (new_entry == NULL) {
258         PrintError("Vnet: Malloc fails\n");
259         return -1;
260     }
261     
262     new_entry->num_matched_routes = num_matched_r;
263     new_entry->matches = (int *)V3_Malloc(num_matched_r * sizeof(int));
264     
265     if (new_entry->matches == NULL) {
266         PrintError("Vnet: Malloc fails\n");
267         return -1;
268     }
269     
270     for (i = 0; i < num_matched_r; i++) {
271         new_entry->matches[i] = matches[i];
272     }
273     
274     if (v3_htable_insert(vnet_state->g_route_cache, (addr_t)hashkey, (addr_t)new_entry) == 0) {
275         PrintError("Vnet: Failed to insert new route entry to the cache\n");
276         V3_Free(new_entry->matches);
277         V3_Free(new_entry);
278     }
279     
280     return 0;
281 }
282
283 static int clear_hash_cache() {
284     struct vnet_state_t *vnet_state = &g_vnet_state;
285
286     v3_free_htable(vnet_state->g_route_cache, 1, 1);            
287     vnet_state->g_route_cache = v3_create_htable(MIN_CACHE_SIZE, 
288                                                                         hash_from_key_fn, 
289                                                                         hash_key_equal);
290     
291     if (vnet_state->g_route_cache == NULL) {
292         PrintError("Vnet: Route Cache Create Failurely\n");
293         return -1;
294     }
295
296     return 0;
297 }
298
299 static int look_into_cache(route_hashkey_t hashkey, int * matches) {
300     struct route_cache_entry * found = NULL;
301     int n_matches = -1;
302     int i = 0;
303     struct vnet_state_t *vnet_state = &g_vnet_state;
304     
305     found = (struct route_cache_entry *)v3_htable_search(vnet_state->g_route_cache, 
306                                                                                (addr_t)hashkey);
307    
308     if (found != NULL) {
309         n_matches = found->num_matched_routes;
310
311         for (i = 0; i < n_matches; i++) {
312             matches[i] = found->matches[i];
313         }
314     }
315
316     return n_matches;
317 }
318
319
320 #ifdef CONFIG_DEBUG_VNET
321
322 static void print_packet(uchar_t *pkt, int size) {
323     PrintDebug("Vnet: data_packet: size: %d\n", size);
324     v3_hexdump(pkt, size, NULL, 0);
325 }
326
327 static inline uint8_t hex_nybble_to_nybble(const uint8_t hexnybble) {
328     uint8_t x = toupper(hexnybble);
329
330     if (isdigit(x)) {
331         return x - '0';
332     } else {
333         return 10 + (x - 'A');
334     }
335 }
336
337 static inline uint8_t hex_byte_to_byte(const uint8_t hexbyte[2]) {
338     return ((hex_nybble_to_nybble(hexbyte[0]) << 4) + 
339             (hex_nybble_to_nybble(hexbyte[1]) & 0xf));
340 }
341
342 static inline void string_to_mac(const char *str, uint8_t mac[6]) {
343     int k;
344
345     for (k = 0; k < 6; k++) {
346         mac[k] = hex_byte_to_byte(&(str[(2 * k) + k]));
347     }
348 }
349
350 static inline void mac_to_string(char mac[6], char * buf) {
351     snprintf(buf, 20, "%02x:%02x:%02x:%02x:%02x:%02x", 
352              mac[0], mac[1], mac[2],
353              mac[3], mac[4], mac[5]);
354 }
355
356
357 static void print_route(struct routing_entry *route){
358     char dest_str[18];
359     char src_str[18];
360
361     mac_to_string(route->src_mac, src_str);  
362     mac_to_string(route->dest_mac, dest_str);
363
364     PrintDebug("SRC(%s), DEST(%s), src_mac_qual(%d), dst_mac_qual(%d)\n", 
365                  src_str, 
366                  dest_str, 
367                  route->src_mac_qual, 
368                  route->dest_mac_qual);
369     PrintDebug("Src_Link(%d), src_type(%d), dst_link(%d), dst_type(%d)\n\n", 
370                  route->src_link_idx, 
371                  route->src_type, 
372                  route->link_idx, 
373                  route->link_type);
374 }
375         
376
377 static void dump_routes(struct routing_entry **route_tables) {
378     int i;
379
380     PrintDebug("\nVnet: route table dump start =====\n");
381
382     for(i = 0; i < MAX_ROUTES; i++) {
383         if (route_tables[i] != NULL){
384              print_route(route_tables[i]);
385         }
386     }
387
388     PrintDebug("\nVnet: route table dump end =====\n");
389 }
390
391 static void dump_dom0_routes(struct routing_entry routes[], int size) {
392     int i;
393
394     PrintDebug("\nVnet: route table from dom0 guest =====\n");
395
396     for(i = 0; i <size; i++) {
397         print_route(&routes[i]);
398     }
399
400     PrintDebug("\nVnet: route table dom0 guest end =====\n");
401 }
402
403 static void dump_dom0_links(struct vnet_if_link links[], int size) {
404     struct vnet_if_link *link = NULL;
405     int i;
406
407     PrintDebug("\nVnet: link table from dom0 guest =====\n");
408
409     for(i = 0; i <size; i++) {
410         link = &links[i];
411         PrintDebug("link: %d\n", i);
412         PrintDebug("dest_ip(%ld), dst_port(%d), prot_type(%d)\n", 
413                      link->dest_ip, 
414                      link->dest_port, 
415                      link->pro_type);
416         PrintDebug("vnet_header:\n");
417         v3_hexdump(&link->vnet_header, sizeof(struct udp_link_header), NULL, 0);
418     }
419
420     PrintDebug("\nVnet: link table dom0 guest end =====\n");
421 }
422
423 #endif
424
425 static int __add_link_entry(struct link_entry * link) {
426     int idx;
427     struct vnet_state_t *vnet_state = &g_vnet_state;
428
429     v3_lock(vnet_state->g_links.lock);
430     for (idx = 0; idx < MAX_LINKS; idx++) {
431         if (vnet_state->g_links.links[idx] == NULL) {
432             vnet_state->g_links.links[idx] = link;
433             vnet_state->g_links.size++;
434             break;
435         }
436     }
437     v3_unlock(vnet_state->g_links.lock);
438
439     if (idx == MAX_LINKS) {
440         PrintDebug("VNET: No available Link entry for new link\n");
441         return -1;
442     }
443
444     return idx;
445 }
446
447 static int __add_route_entry(struct routing_entry * route) {
448     int idx;
449     struct vnet_state_t *vnet_state = &g_vnet_state;
450
451     v3_lock(vnet_state->g_routes.lock);
452     for (idx = 0; idx < MAX_ROUTES; idx++) {
453         if (vnet_state->g_routes.routes[idx] == NULL) {
454             vnet_state->g_routes.routes[idx] = route;
455             vnet_state->g_routes.size++;
456           break;
457         }
458     }
459     v3_unlock(vnet_state->g_routes.lock);
460
461     if(idx == MAX_LINKS){
462         PrintDebug("VNET: No available route entry for new route\n");
463         return -1;
464     }
465
466 #ifdef CONFIG_DEBUG_VNET
467     dump_routes(vnet_state->g_routes.routes);
468 #endif
469
470     return idx;
471 }
472
473 int v3_vnet_add_route(struct v3_vnet_route *route){
474     struct routing_entry * new_route = (struct routing_entry *)V3_Malloc(sizeof(struct routing_entry));
475     int idx = -1;
476
477     PrintDebug("Vnet: vnet_add_route_entry\n");
478         
479     memset(new_route, 0, sizeof(struct routing_entry));
480     if ((route->src_mac_qual != MAC_ANY)) {
481         memcpy(new_route->src_mac, route->src_mac, 6);
482     }
483             
484     if ((route->dest_mac_qual != MAC_ANY)) {
485         memcpy(new_route->dest_mac, route->dest_mac, 6);
486     }
487             
488     new_route->src_mac_qual = route->src_mac_qual;
489     new_route->dest_mac_qual = route->dest_mac_qual;
490     new_route->link_idx= route->link_idx;
491     new_route->link_type = route->link_type;
492     new_route->src_link_idx = route->src_link_idx;
493     new_route->src_type = route->src_type;
494
495     if ((idx = __add_route_entry(new_route)) == -1) {
496         PrintError("Could not add route entry\n");
497         return -1;
498     }
499     
500     clear_hash_cache();
501
502     return idx;
503 }
504
505 static int match_route(uint8_t * src_mac, 
506                        uint8_t * dst_mac, 
507                        link_type_t src_type, 
508                        int src_index, 
509                        int * matches) {
510     struct routing_entry *route = NULL; 
511     struct vnet_state_t *vnet_state = &g_vnet_state;
512     int matched_routes[MAX_ROUTES];
513     int num_matches = 0;
514     int i;
515
516 #ifdef CONFIG_DEBUG_VNET
517     char dest_str[18];
518     char src_str[18];
519
520     mac_to_string(src_mac, src_str);  
521     mac_to_string(dst_mac, dest_str);
522     PrintDebug("Vnet: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dest_str);
523 #endif
524
525     for(i = 0; i < MAX_ROUTES; i++) {
526         if (vnet_state->g_routes.routes[i] != NULL){
527              route = vnet_state->g_routes.routes[i];
528
529             if(src_type == LINK_ANY && src_index == -1) {
530                  if ((route->dest_mac_qual == MAC_ANY) &&
531                        (route->src_mac_qual == MAC_ANY)) {      
532                     matched_routes[num_matches] = i;
533                     num_matches++;
534                  }
535         
536                 if (memcmp((void *)&route->src_mac, (void *)src_mac, 6) == 0) {
537                      if (route->src_mac_qual !=  MAC_NOT) {
538                           if (route->dest_mac_qual == MAC_ANY) {
539                               matched_routes[num_matches] = i;
540                               num_matches++;
541                           } else if (route->dest_mac_qual != MAC_NOT &&
542                                       memcmp((void *)&route->dest_mac, (void *)dst_mac, 6) == 0) {
543                             matched_routes[num_matches] = i;
544                             num_matches++;
545                         }
546                     }
547                 }
548
549                 if (memcmp((void *)&route->dest_mac, (void *)dst_mac, 6) == 0) {
550                     if (route->dest_mac_qual != MAC_NOT) {
551                         if (route->src_mac_qual == MAC_ANY) {
552                             matched_routes[num_matches] = i;
553                             num_matches++;
554                         } else if ((route->src_mac_qual != MAC_NOT) && 
555                                        (memcmp((void *)&route->src_mac, (void *)src_mac, 6) == 0)) {
556                             matched_routes[num_matches] = i;
557                             num_matches++;
558                         }
559                      }
560                 }
561
562                 if ((route->dest_mac_qual == MAC_NOT) &&
563                        (memcmp((void *)&route->dest_mac, (void *)dst_mac, 6) != 0)) {
564                     if (route->src_mac_qual == MAC_ANY) {
565                         matched_routes[num_matches] = i;            
566                         num_matches++;    
567                     } else if ((route->src_mac_qual != MAC_NOT) && 
568                                    (memcmp((void *)&route->src_mac, (void *)src_mac, 6) == 0)) {     
569                         matched_routes[num_matches] = i;     
570                         num_matches++;
571                       }
572                 }
573
574                 if ((route->src_mac_qual == MAC_NOT) &&
575                        (memcmp((void *)&route->src_mac, (void *)src_mac, 6) != 0)) {
576                     if (route->dest_mac_qual == MAC_ANY) {
577                         matched_routes[num_matches] = i;   
578                         num_matches++;
579                     } else if ((route->dest_mac_qual != MAC_NOT) &&
580                                    (memcmp((void *)&route->dest_mac, (void *)dst_mac, 6) == 0)) {
581                         matched_routes[num_matches] = i;
582                         num_matches++;
583                     }
584                 }
585             }//end if src_type == Link_any
586         }       
587     }//end for
588
589     PrintDebug("Vnet: match_route: Matches=%d\n", num_matches);
590         
591     for (i = 0; i < num_matches; i++) {
592         matches[i] = matched_routes[i];
593     }
594     
595     return num_matches;
596 }
597
598 static int handle_one_pkt(struct ethernet_pkt *pkt) {
599     int src_link_index = -1;    //the value of src_link_index of udp always is 0
600     char src_mac[6];
601     char dst_mac[6];
602     int matches[MAX_ROUTES];
603     int num_matched_routes = 0;
604     struct in_pkt_header header;
605     char hash_key[HASH_KEY_SIZE];
606     struct vnet_state_t *vnet_state = &g_vnet_state;
607     int i;
608
609     // get the ethernet and ip headers from the packet
610     memcpy((void *)&header, (void *)pkt->data, sizeof(header));
611     memcpy(src_mac, header.ethernetsrc, 6);
612     memcpy(dst_mac, header.ethernetdest, 6);
613
614 #ifdef CONFIG_DEBUG_VNET
615     char dest_str[18];
616     char src_str[18];
617
618     mac_to_string(src_mac, src_str);  
619     mac_to_string(dst_mac, dest_str);
620     PrintDebug("Vnet: HandleDataOverLink. SRC(%s), DEST(%s)\n", src_str, dest_str);
621 #endif
622
623     make_hash_key(hash_key, src_mac, dst_mac, LINK_EDGE, src_link_index); 
624     num_matched_routes = look_into_cache((route_hashkey_t)hash_key, matches);
625     
626     if (num_matched_routes == -1) {  
627         num_matched_routes = match_route(src_mac, dst_mac, LINK_ANY, src_link_index, matches);  
628         if (num_matched_routes > 0) {
629              add_route_to_cache(hash_key, num_matched_routes,matches);      
630          }
631     }
632     
633     PrintDebug("Vnet: HandleDataOverLink: Matches=%d\n", num_matched_routes);
634
635     if (num_matched_routes == 0) {
636         return -1;
637     }
638     
639     for (i = 0; i < num_matched_routes; i++) {//send packet to all destinations
640         int route_index = -1;
641         int link_index = -1;
642         int pkt_len = 0;
643         struct link_entry * link = NULL;
644
645         route_index = matches[i];
646         link_index = vnet_state->g_routes.routes[route_index]->link_idx;
647
648         if ((link_index < 0) || (link_index > MAX_LINKS) || 
649              (vnet_state->g_links.links[link_index] == NULL)) {
650              continue;
651          }
652         
653         link = vnet_state->g_links.links[link_index];
654         pkt_len = pkt->size;
655         if (link->type == LINK_EDGE) {
656
657               //apply the header in the beginning of the packet to be sent
658             if (link->dst_link->pro_type == UDP_TYPE) {
659                 struct udp_link_header *hdr = &(link->dst_link->vnet_header);
660                 struct ip_header *ip = &hdr->ip_hdr;
661                 struct udp_header *udp = &hdr->udp_hdr;
662                    udp->len = pkt_len + sizeof(struct udp_header);
663                    ip->total_len = pkt_len + sizeof(struct udp_header) + sizeof(struct ip_header);
664                    ip->cksum = ip_xsum(ip, sizeof(struct ip_header));
665                 
666                 int hdr_size = sizeof(struct udp_link_header);
667                 memcpy(&pkt->ext_hdr, hdr, hdr_size);
668
669                 pkt_len += hdr_size;
670                 if ((link->dst_link->input((uchar_t *)&pkt->ext_hdr, pkt_len, link->dst_link->private_data)) != pkt_len) {
671                     PrintDebug("VNET: Packet not sent properly to link: %d\n", link_index);
672                     continue;
673                 }
674              }else {
675                 PrintDebug("VNET: Link protocol type not support\n");
676                 continue;
677              }
678         } else if (link->type == LINK_INTERFACE) {
679             if ((link->dst_dev->input(link->dst_dev->vm, pkt->data, pkt_len, link->dst_dev->private_data)) != pkt_len) {
680                 PrintDebug("VNET: Packet not sent properly to link: %d\n", link_index);
681                 continue;
682              }
683         } else {
684             PrintDebug("Vnet: Wrong Edge type of link: %d\n", link_index);
685             continue;
686         }
687
688         PrintDebug("Vnet: HandleDataOverLink: Forward packet according to Route entry %d to link %d\n", route_index, link_index);
689     }
690     
691     return 0;
692 }
693
694 static int send_ethernet_pkt(uchar_t *data, int len, void *private_data) {
695     struct ethernet_pkt *pkt;
696     struct vnet_state_t *vnet_state = &g_vnet_state;
697
698     pkt = (struct ethernet_pkt *)V3_Malloc(sizeof(struct ethernet_pkt));
699     if(pkt == NULL){
700         PrintError("VNET: Memory allocate fails\n");
701         return -1;
702     }
703
704     memset(pkt, 0, sizeof(struct ethernet_pkt));
705     ethernet_packet_init(pkt, data, len);
706     v3_enqueue(vnet_state->g_inpkt_q, (addr_t)pkt);
707   
708 #ifdef CONFIG_DEBUG_VNET
709     PrintDebug("VNET: send_pkt: transmitting packet: (size:%d)\n", (int)pkt->size);
710     print_packet((char *)data, len);
711 #endif
712
713     return 0;
714 }
715
716 int v3_vnet_send_rawpkt(uchar_t * buf, 
717                                           int len, 
718                                           void *private_data) {
719     PrintDebug("VNET: In v3_vnet_send_rawpkt: pkt length %d\n", len);
720     
721     return send_ethernet_pkt(buf, len, private_data);
722 }
723
724 //sending the packet from Dom0, should remove the link header
725 int v3_vnet_send_udppkt(uchar_t * buf, 
726                                            int len, 
727                                            void *private_data) {
728     uint_t hdr_len = sizeof(struct udp_link_header);
729         
730     PrintDebug("VNET: In v3_vnet_send_udppkt: pkt length %d\n", len);
731    
732     return send_ethernet_pkt((uchar_t *)(buf+hdr_len), len - hdr_len, private_data);
733 }
734
735 static int search_device(char * device_name) {
736     struct vnet_state_t *vnet_state = &g_vnet_state;
737     int i;
738
739     for (i = 0; i < MAX_LINKS; i++) {
740         if ((vnet_state->g_links.links[i] != NULL) && (vnet_state->g_links.links[i]->type == LINK_INTERFACE)) {
741             if (strcmp(device_name, vnet_state->g_links.links[i]->dst_dev->name) == 0) {
742                 return i;
743             }
744         }
745     }
746
747     return -1;
748 }
749
750 int v3_vnet_add_node(struct v3_vm_info *info, 
751                    char * dev_name, 
752                    uchar_t mac[6], 
753                     int (*netif_input)(struct v3_vm_info * vm, uchar_t * pkt, uint_t size, void * private_data), 
754                     void * priv_data){
755     struct vnet_if_device * if_dev;
756
757     int idx = search_device(dev_name);
758     if (idx != -1) {
759         PrintDebug("VNET: register device: Already has device with the name %s\n", dev_name);
760         return -1;
761     }
762     
763     if_dev = (struct vnet_if_device *)V3_Malloc(sizeof(struct vnet_if_device)); 
764     if (if_dev == NULL) {
765         PrintError("VNET: Malloc fails\n");
766         return -1;
767     }
768     
769     strcpy(if_dev->name, dev_name);
770     strncpy(if_dev->mac_addr, mac, 6);
771     if_dev->input = netif_input;
772     if_dev->private_data = priv_data;
773     if_dev->vm = info;
774
775     struct link_entry * link = (struct link_entry *)V3_Malloc(sizeof(struct link_entry));
776     link->type = LINK_INTERFACE;
777     link->dst_dev = if_dev;
778
779     idx = __add_link_entry(link);
780
781     if (idx < 0) return -1;
782
783     return idx;
784 }
785
786 int v3_vnet_pkt_process() {
787     struct ethernet_pkt * pkt;
788     struct vnet_state_t *vnet_state = &g_vnet_state;
789
790     while ((pkt = (struct ethernet_pkt *)v3_dequeue(vnet_state->g_inpkt_q))!= NULL) {
791         if (handle_one_pkt(pkt) != -1) {
792             PrintDebug("VNET: vnet_check: handle one packet! pt length %d, pt type %d\n", (int)pkt->size, (int)pkt->type);  
793         } else {
794             PrintDebug("VNET: vnet_check: Fail to forward one packet, discard it!\n"); 
795         }
796         
797         V3_Free(pkt); // be careful here
798     }
799     
800     return 0;
801 }
802
803 static void vnet_state_init(struct vnet_state_t *vnet_state) {
804     int i;
805
806     /*initial links table */
807     for (i = 0; i < MAX_LINKS; i++) {
808         vnet_state->g_links.links[i] = NULL;
809     }
810     vnet_state->g_links.size = 0;
811     if(v3_lock_init(&(vnet_state->g_links.lock)) == -1){
812         PrintError("VNET: Failure to init lock for links table\n");
813     }
814     PrintDebug("VNET: Links table initiated\n");
815
816     /*initial routes table */
817     for (i = 0; i < MAX_ROUTES; i++) {
818         vnet_state->g_routes.routes[i] = NULL;
819     }
820     vnet_state->g_routes.size = 0;
821     if(v3_lock_init(&(vnet_state->g_routes.lock)) == -1){
822         PrintError("VNET: Failure to init lock for routes table\n");
823     }
824     PrintDebug("VNET: Routes table initiated\n");
825
826     /*initial pkt receiving queue */
827     vnet_state->g_inpkt_q = v3_create_queue();
828     v3_init_queue(vnet_state->g_inpkt_q);
829     PrintDebug("VNET: Receiving queue initiated\n");
830
831     /*initial routing cache */
832     init_route_cache(vnet_state);
833 }
834
835
836 int v3_init_vnet() {
837     vnet_state_init(&g_vnet_state);
838         
839     PrintDebug("VNET Initialized\n");
840
841     return 0;
842 }
843