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.


188f730865a0e65aadf088ff2bd652ca9811ad26
[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, Zheng Cui <czheng@unm.edu>
13  * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org> 
14  * All rights reserved.
15  *
16  * Author: Lei Xia <lxia@northwestern.edu>
17  *         Yuan Tang <ytang@northwestern.edu>
18  *       Zheng Cui <czheng@unm.edu>
19  *
20  * This is free software.  You are permitted to use,
21  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
22  */
23  
24 #include <palacios/vmm_vnet.h>
25 #include <palacios/vmm_hypercall.h>
26 #include <palacios/vm_guest_mem.h>
27
28 #ifndef CONFIG_DEBUG_VNET
29 #undef PrintDebug
30 #define PrintDebug(fmt, args...)
31 #endif
32
33
34 struct ethernet_pkt {
35     uint32_t size; //size of data
36     uint16_t type;
37     struct udp_link_header ext_hdr; //possible externel header to applied to data before sent
38     char data[ETHERNET_PACKET_LEN];
39 }__attribute__((packed));
40
41
42 // 14 (ethernet frame) + 20 bytes
43 struct in_pkt_header {
44     uchar_t ethernetdest[6];
45     uchar_t ethernetsrc[6];
46     uchar_t ethernettype[2]; //layer 3 protocol type
47     char ip[20];
48 }__attribute__((packed));
49
50 #define VNET_INITAB_HCALL 0xca00  // inital hypercall id
51
52 #define MAX_LINKS 10
53 #define MAX_ROUTES 10
54 #define HASH_KEY_LEN 16
55 #define MIN_CACHE_SIZE 100
56 static const uint_t hash_key_size = 16;
57
58 struct link_table {
59     struct link_entry * links[MAX_LINKS];
60     uint16_t size;
61 }__attribute__((packed));
62
63 struct routing_table {
64     struct routing_entry * routes[MAX_ROUTES];
65     uint16_t size;
66 }__attribute__((packed));
67
68 static struct link_table g_links;
69 static struct routing_table g_routes;
70 static struct gen_queue * g_inpkt_q;
71
72 /* Hash key format:
73  * 0-5:     src_eth_addr
74  * 6-11:    dest_eth_addr
75  * 12:      src type
76  * 13-16:   src index
77  */
78 typedef char * route_hashkey_t;
79
80 // This is the hash value, Format: 0: num_matched_routes, 1...n: matches[] -- TY
81 struct route_cache_entry {
82     int num_matched_routes;
83     int * matches; 
84 };
85
86 // the route cache
87 static struct hashtable * g_route_cache; 
88
89 static uint16_t ip_xsum(struct ip_header *ip_hdr, int hdr_len){
90     long sum = 0;
91
92     uint16_t *p = (uint16_t*) ip_hdr;
93     while(hdr_len > 1){
94         sum += *(p++);
95         if(sum & 0x80000000)
96             sum = (sum & 0xFFFF) + (sum >> 16);
97             hdr_len -= 2;
98         }
99  
100     if(hdr_len) 
101         sum += (uint16_t) *(uchar_t *)p;
102           
103     while(sum>>16)
104         sum = (sum & 0xFFFF) + (sum >> 16);
105
106     return (uint16_t)~sum;
107 }
108
109 static inline void ethernet_packet_init(struct ethernet_pkt *pt, uchar_t *data, const size_t size) {
110     pt->size = size;
111     memcpy(pt->data, data, size);
112 }
113
114 static uint_t hash_from_key_fn(addr_t hashkey) {    
115     uint8_t * key = (uint8_t *)hashkey;
116     return v3_hash_buffer(key, HASH_KEY_LEN);
117 }
118
119 static int hash_key_equal(addr_t key1, addr_t key2) {
120     uint8_t * buf1 = (uint8_t *)key1;
121     uint8_t * buf2 = (uint8_t *)key2;
122     return (memcmp(buf1, buf2, HASH_KEY_LEN) == 0);
123 }
124
125 static int init_route_cache() {
126     g_route_cache = v3_create_htable(MIN_CACHE_SIZE, &hash_from_key_fn, &hash_key_equal);
127
128     if (g_route_cache == NULL) {
129         PrintError("Vnet: Route Cache Initiate Failurely\n");
130         return -1;
131     }
132
133     return 0;
134 }
135
136 static void make_hash_key(route_hashkey_t hashkey,
137                           char src_addr[6],
138                           char dest_addr[6],
139                           char src_type,
140                           int src_index) {
141     int j;
142
143     for (j = 0; j < 6; j++) {
144         hashkey[j] = src_addr[j];
145         hashkey[j + 6] = dest_addr[j] + 1;
146     }
147
148     hashkey[12] = src_type;
149
150     *(int *)(hashkey + 12) = src_index;
151 }
152
153 static int add_route_to_cache(route_hashkey_t hashkey, int num_matched_r, int * matches) {
154     struct route_cache_entry * new_entry = NULL;
155     int i;
156     
157     new_entry = (struct route_cache_entry *)V3_Malloc(sizeof(struct route_cache_entry));
158     if (new_entry == NULL) {
159         PrintError("Vnet: Malloc fails\n");
160         return -1;
161     }
162     
163     new_entry->num_matched_routes = num_matched_r;
164
165     new_entry->matches = (int *)V3_Malloc(num_matched_r * sizeof(int));
166     
167     if (new_entry->matches == NULL) {
168         PrintError("Vnet: Malloc fails\n");
169         return -1;
170     }
171     
172     for (i = 0; i < num_matched_r; i++) {
173         new_entry->matches[i] = matches[i];
174     }
175     
176     // here, when v3_htable_insert return 0, it means insert fails
177     if (v3_htable_insert(g_route_cache, (addr_t)hashkey, (addr_t)new_entry) == 0) {
178         PrintError("Vnet: Insert new route entry to cache failed\n");
179         V3_Free(new_entry->matches);
180         V3_Free(new_entry);
181     }
182     
183     return 0;
184 }
185
186 static int clear_hash_cache() {
187     v3_free_htable(g_route_cache, 1, 1);
188                 
189     g_route_cache = v3_create_htable(MIN_CACHE_SIZE, hash_from_key_fn, hash_key_equal);
190     
191     if (g_route_cache == NULL) {
192         PrintError("Vnet: Route Cache Create Failurely\n");
193         return -1;
194     }
195
196     return 0;
197 }
198
199 static int look_into_cache(route_hashkey_t hashkey, int * matches) {
200     struct route_cache_entry * found = NULL;
201     int n_matches = -1;
202     int i = 0;
203     
204     found = (struct route_cache_entry *)v3_htable_search(g_route_cache, (addr_t)hashkey);
205    
206     if (found != NULL) {
207         n_matches = found->num_matched_routes;
208
209         for (i = 0; i < n_matches; i++) {
210             matches[i] = found->matches[i];
211         }
212     }
213
214     return n_matches;
215 }
216
217
218 #ifdef CONFIG_DEBUG_VNET
219
220 static void print_packet(uchar_t *pkt, int size) {
221     PrintDebug("Vnet: print_data_packet: size: %d\n", size);
222     v3_hexdump(pkt, size, NULL, 0);
223 }
224
225 static inline uint8_t hex_nybble_to_nybble(const uint8_t hexnybble) {
226     uint8_t x = toupper(hexnybble);
227
228     if (isdigit(x)) {
229         return x - '0';
230     } else {
231         return 10 + (x - 'A');
232     }
233 }
234
235 static inline uint8_t hex_byte_to_byte(const uint8_t hexbyte[2]) {
236     return ((hex_nybble_to_nybble(hexbyte[0]) << 4) + 
237             (hex_nybble_to_nybble(hexbyte[1]) & 0xf));
238 }
239
240 static inline void string_to_mac(const char *str, uint8_t mac[6]) {
241     int k;
242
243     for (k = 0; k < 6; k++) {
244         mac[k] = hex_byte_to_byte(&(str[(2 * k) + k]));
245     }
246 }
247
248 static inline void mac_to_string(char mac[6], char * buf) {
249     snprintf(buf, 20, "%02x:%02x:%02x:%02x:%02x:%02x", 
250              mac[0], mac[1], mac[2],
251              mac[3], mac[4], mac[5]);
252 }
253
254 static void dump_routes(struct routing_entry **route_tables) {
255     char dest_str[18];
256     char src_str[18];
257     struct routing_entry *route = NULL;
258     int i;
259
260     PrintDebug("\nVnet: route table dump start =====\n");
261
262     for(i = 0; i < MAX_ROUTES; i++) {
263         if (route_tables[i] != NULL){
264              route = route_tables[i];
265     
266             mac_to_string(route->src_mac, src_str);  
267             mac_to_string(route->dest_mac, dest_str);
268
269             PrintDebug("route: %d\n", i);
270             PrintDebug("SRC(%s), DEST(%s), src_mac_qual(%d), dst_mac_qual(%d)\n", src_str, dest_str, route->src_mac_qual, route->dest_mac_qual);
271             PrintDebug("Src_Link(%d), src_type(%d), dst_link(%d), dst_type(%d)\n\n", route->src_link_idx, route->src_type, route->link_idx, route->link_type);
272         }
273     }
274
275     PrintDebug("\nVnet: route table dump end =====\n");
276 }
277
278 static void dump_dom0_routes(struct routing_entry routes[], int size) {
279     char dest_str[18];
280     char src_str[18];
281     struct routing_entry *route = NULL;
282     int i;
283
284     PrintDebug("\nVnet: route table from dom0 guest =====\n");
285
286     for(i = 0; i <size; i++) {
287         route = &routes[i];
288         mac_to_string(route->src_mac, src_str);  
289         mac_to_string(route->dest_mac, dest_str);
290         PrintDebug("route: %d\n", i);
291         PrintDebug("SRC(%s), DEST(%s), src_mac_qual(%d), dst_mac_qual(%d)\n", src_str, dest_str, route->src_mac_qual, route->dest_mac_qual);
292         PrintDebug("Src_Link(%d), src_type(%d), dst_link(%d), dst_type(%d)\n\n", route->src_link_idx, route->src_type, route->link_idx, route->link_type);
293     }
294
295     PrintDebug("\nVnet: route table dom0 guest end =====\n");
296 }
297
298 static void dump_dom0_links(struct vnet_if_link links[], int size) {
299     struct vnet_if_link *link = NULL;
300     int i;
301
302     PrintDebug("\nVnet: link table from dom0 guest =====\n");
303
304     for(i = 0; i <size; i++) {
305         link = &links[i];
306         PrintDebug("link: %d\n", i);
307         PrintDebug("dest_ip(%ld), dst_port(%d), prot_type(%d)\n", link->dest_ip, link->dest_port, link->pro_type);
308         PrintDebug("vnet_header:\n");
309          v3_hexdump(&link->vnet_header, sizeof(struct udp_link_header), NULL, 0);
310     }
311
312     PrintDebug("\nVnet: link table dom0 guest end =====\n");
313 }
314
315 #endif
316
317 static int __add_link_entry(struct link_entry * link) {
318     int idx;
319     
320     for (idx = 0; idx < MAX_LINKS; idx++) {
321         if (g_links.links[idx] == NULL) {
322             g_links.links[idx] = link;
323             g_links.size++;
324             
325             return idx;
326         }
327     }
328
329     PrintError("No available Link entry\n");
330     return -1;
331 }
332
333 static int __add_route_entry(struct routing_entry * route) {
334     int idx;
335     
336     for (idx = 0; idx < MAX_ROUTES; idx++) {
337         if (g_routes.routes[idx] == NULL) {
338             g_routes.routes[idx] = route;
339             g_routes.size++;
340             
341             return idx;
342         }
343     }
344
345     PrintError("No available route entry\n");
346     return -1;
347 }
348
349
350 int vnet_add_route_entry(char src_mac[6],
351                                 char dest_mac[6],
352                                 int src_mac_qual,
353                                 int dest_mac_qual,
354                                 int link_idx,
355                                 link_type_t link_type,
356                                 int src_link_idx,
357                                 link_type_t src_link_type) {
358     struct routing_entry * new_route = (struct routing_entry *)V3_Malloc(sizeof(struct routing_entry));
359     int idx = -1;
360
361     memset(new_route, 0, sizeof(struct routing_entry));
362
363     if ((src_mac_qual != MAC_ANY)) {
364         memcpy(new_route->src_mac, src_mac, 6);
365     }
366             
367     if ((dest_mac_qual != MAC_ANY)) {
368         memcpy(new_route->dest_mac, dest_mac, 6);
369     }
370             
371     new_route->src_mac_qual = src_mac_qual;
372     new_route->dest_mac_qual = dest_mac_qual;
373     new_route->link_idx= link_idx;
374     new_route->link_type = link_type;
375     new_route->src_link_idx = src_link_idx;
376     new_route->src_type = src_link_type;
377
378     if ((idx = __add_route_entry(new_route)) == -1) {
379         PrintError("Could not add route entry\n");
380         return -1;
381     }
382     
383     clear_hash_cache();
384     
385     return idx;
386 }
387
388 #if 0
389 static void * __delete_link_entry(int index) {
390     struct link_entry * link = NULL;
391     void * ret = NULL;
392     link_type_t type;
393   
394     if ((index >= MAX_LINKS) || (g_links.links[index] == NULL)) {
395         return NULL;
396     }
397
398     link = g_links.links[index];
399     type = g_links.links[index]->type;
400
401     if (type == LINK_INTERFACE) {
402         ret = (void *)g_links.links[index]->dst_dev;
403     } else if (type == LINK_EDGE) {
404         ret = (void *)g_links.links[index]->dst_link;
405     }
406
407     g_links.links[index] = NULL;
408     g_links.size--;
409
410     V3_Free(link);
411         
412     return ret;
413 }
414
415 static int find_route_entry(char src_mac[6], 
416                             char dest_mac[6], 
417                             int src_mac_qual, 
418                             int dest_mac_qual, 
419                             int link_idx, 
420                             link_type_t link_type, 
421                             int src, 
422                             link_type_t src_type) {
423     int i;
424     char temp_src_mac[6];
425     char temp_dest_mac[6];
426   
427     if ((src_mac_qual != MAC_ANY) && (src_mac_qual != MAC_NONE)) {
428         memcpy(temp_src_mac, src_mac, 6);
429     } else {
430         memset(temp_src_mac, 0, 6);
431     }
432     
433     if ((dest_mac_qual != MAC_ANY) && (dest_mac_qual != MAC_NONE)) {
434         memcpy(temp_dest_mac, dest_mac, 6);
435     } else {
436         memset(temp_dest_mac, 0, 6);
437     }
438     
439     for (i = 0; i < MAX_ROUTES; i++) {
440         if (g_routes.routes[i] != NULL) {
441             if ((memcmp(temp_src_mac, g_routes.routes[i]->src_mac, 6) == 0) && 
442                 (memcmp(temp_dest_mac, g_routes.routes[i]->dest_mac, 6) == 0) &&
443                 (g_routes.routes[i]->src_mac_qual == src_mac_qual) &&
444                 (g_routes.routes[i]->dest_mac_qual == dest_mac_qual)  &&
445                 ( (link_type == LINK_ANY) || 
446                   ((link_type == g_routes.routes[i]->link_type) && (g_routes.routes[i]->link_idx == link_idx))) &&
447                 ( (src_type == LINK_ANY) || 
448                   ((src_type == g_routes.routes[i]->src_type) && (g_routes.routes[i]->src_link_idx == src)))) {
449                 return i;
450             }
451         } 
452      }
453     
454     return -1;
455 }
456
457 static int __delete_route_entry(int index) {
458     struct routing_entry * route;
459
460     if ((index >= MAX_ROUTES) || (g_routes.routes[index] == NULL)) {
461         PrintDebug("VNET: wrong index in delete route entry %d\n", index);
462         return -1;
463     }
464
465     route = g_routes.routes[index];
466     g_routes.routes[index] = NULL;
467     g_routes.size--;
468
469     V3_Free(route);
470
471     clear_hash_cache();
472     
473     return 0;
474 }
475
476 static int vnet_delete_route_entry_by_addr(char src_mac[6], 
477                                            char dest_mac[6], 
478                                            int src_mac_qual, 
479                                            int dest_mac_qual, 
480                                            int link_idx, 
481                                            link_type_t type, 
482                                            int src, 
483                                            link_type_t src_type) {
484     int index = find_route_entry(src_mac, dest_mac, src_mac_qual, 
485                                  dest_mac_qual, link_idx, type, src, src_type);
486     
487     if (index == -1) {
488         PrintDebug("VNET: wrong in delete route entry %d\n", index);
489         return -1;
490     }
491     
492     return __delete_route_entry(index);
493 }
494 #endif
495
496 static int match_route(uint8_t * src_mac, 
497                        uint8_t * dst_mac, 
498                        link_type_t src_type, 
499                        int src_index, 
500                        int * matches) {
501     int matched_routes[MAX_ROUTES];
502     int num_matches = 0;
503     int i;
504     struct routing_entry *route = NULL; 
505
506 #ifdef CONFIG_DEBUG_VNET
507     char dest_str[18];
508     char src_str[18];
509     
510     mac_to_string(src_mac, src_str);  
511     mac_to_string(dst_mac, dest_str);
512     
513     PrintDebug("Vnet: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dest_str);
514
515     dump_routes(g_routes.routes);
516 #endif
517
518     for(i = 0; i < MAX_ROUTES; i++) {
519         if (g_routes.routes[i] != NULL){
520              route = g_routes.routes[i];
521
522             if(src_type == LINK_ANY && src_index == -1) {
523                  if ((route->dest_mac_qual == MAC_ANY) &&
524                        (route->src_mac_qual == MAC_ANY)) {      
525                     matched_routes[num_matches] = i;
526                     num_matches++;
527                  }
528         
529                 if (memcmp((void *)&route->src_mac, (void *)src_mac, 6) == 0) {
530                      if (route->src_mac_qual !=  MAC_NOT) {
531                           if (route->dest_mac_qual == MAC_ANY) {
532                               matched_routes[num_matches] = i;
533                               num_matches++;
534                           } else if (route->dest_mac_qual != MAC_NOT &&
535                                       memcmp((void *)&route->dest_mac, (void *)dst_mac, 6) == 0) {
536                             matched_routes[num_matches] = i;
537                             num_matches++;
538                         }
539                     }
540                 }
541
542                 if (memcmp((void *)&route->dest_mac, (void *)dst_mac, 6) == 0) {
543                     if (route->dest_mac_qual != MAC_NOT) {
544                         if (route->src_mac_qual == MAC_ANY) {
545                             matched_routes[num_matches] = i;
546                             num_matches++;
547                         } else if ((route->src_mac_qual != MAC_NOT) && 
548                                        (memcmp((void *)&route->src_mac, (void *)src_mac, 6) == 0)) {
549                             matched_routes[num_matches] = i;
550                             num_matches++;
551                         }
552                      }
553                 }
554
555                 if ((route->dest_mac_qual == MAC_NOT) &&
556                        (memcmp((void *)&route->dest_mac, (void *)dst_mac, 6) != 0)) {
557                     if (route->src_mac_qual == MAC_ANY) {
558                         matched_routes[num_matches] = i;            
559                         num_matches++;    
560                     } else if ((route->src_mac_qual != MAC_NOT) && 
561                                    (memcmp((void *)&route->src_mac, (void *)src_mac, 6) == 0)) {     
562                         matched_routes[num_matches] = i;     
563                         num_matches++;
564                       }
565                 }
566
567                 if ((route->src_mac_qual == MAC_NOT) &&
568                        (memcmp((void *)&route->src_mac, (void *)src_mac, 6) != 0)) {
569                     if (route->dest_mac_qual == MAC_ANY) {
570                         matched_routes[num_matches] = i;   
571                         num_matches++;
572                     } else if ((route->dest_mac_qual != MAC_NOT) &&
573                                    (memcmp((void *)&route->dest_mac, (void *)dst_mac, 6) == 0)) {
574                         matched_routes[num_matches] = i;
575                         num_matches++;
576                     }
577                 }
578             }//end if src_type == Link_any
579         }       
580     }//end for
581
582     PrintDebug("Vnet: match_route: Matches=%d\n", num_matches);
583         
584     for (i = 0; i < num_matches; i++) {
585         matches[i] = matched_routes[i];
586     }
587     
588     return num_matches;
589 }
590
591 static int handle_one_pkt(struct ethernet_pkt *pkt) {
592     int src_link_index = -1;    //the value of src_link_index of udp always is 0
593     int i;
594     char src_mac[6];
595     char dst_mac[6];
596
597     int matches[MAX_ROUTES];
598     int num_matched_routes = 0;
599
600     struct in_pkt_header header;
601
602     char hash_key[hash_key_size];
603   
604     // get the ethernet and ip headers from the packet
605     memcpy((void *)&header, (void *)pkt->data, sizeof(header));
606     memcpy(src_mac, header.ethernetsrc, 6);
607     memcpy(dst_mac, header.ethernetdest, 6);
608
609 #ifdef CONFIG_DEBUG_VNET
610     char dest_str[18];
611     char src_str[18];
612     
613     mac_to_string(src_mac, src_str);  
614     mac_to_string(dst_mac, dest_str);
615     
616     PrintDebug("Vnet: HandleDataOverLink. SRC(%s), DEST(%s)\n", src_str, dest_str);
617 #endif
618
619     // link_edge -> pt->type???
620     make_hash_key(hash_key, src_mac, dst_mac, LINK_EDGE, src_link_index); 
621     
622     num_matched_routes = look_into_cache((route_hashkey_t)hash_key, matches);
623     
624     if (num_matched_routes == -1) {  
625     // no match in the cache
626         num_matched_routes = match_route(src_mac, dst_mac, LINK_ANY, src_link_index, matches);
627         
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 = g_routes.routes[route_index]->link_idx;
647
648         if ((link_index < 0) || (link_index > MAX_LINKS) || 
649              (g_links.links[link_index] == NULL)) {
650              continue;
651          }
652         
653         link = 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(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) {
695     struct ethernet_pkt *pkt;
696
697     pkt = (struct ethernet_pkt *)V3_Malloc(sizeof(struct ethernet_pkt));
698    
699     if(pkt == NULL){
700         PrintError("VNET: Memory allocate fails\n");
701         return -1;
702     }
703     memset(pkt, 0, sizeof(struct ethernet_pkt));
704         
705     ethernet_packet_init(pkt, data, len);  //====here we copy sending data once 
706         
707     PrintDebug("VNET: vm_send_pkt: transmitting packet: (size:%d)\n", (int)pkt->size);
708
709 #ifdef CONFIG_DEBUG_VNET
710     print_packet((char *)data, len);
711 #endif
712     
713     v3_enqueue(g_inpkt_q, (addr_t)pkt);
714
715     return 0;
716 }
717
718 //send raw ethernet packet
719 int v3_vnet_send_rawpkt(uchar_t * buf, int len, void *private_data) {
720     PrintDebug("VNET: In V3_Send_pkt: pkt length %d\n", len);
721     
722     return send_ethernet_pkt(buf, len);
723 }
724
725 //sending the packet from Dom0, should remove the link header
726 int v3_vnet_send_udppkt(uchar_t * buf, int len, void *private_data) {
727     PrintDebug("VNET: In V3_Send_pkt: pkt length %d\n", len);
728
729     uint_t hdr_len = sizeof(struct udp_link_header);
730    
731     return send_ethernet_pkt((uchar_t *)(buf+hdr_len), len - hdr_len);
732 }
733
734 static int search_device(char * device_name) {
735     int i;
736
737     for (i = 0; i < MAX_LINKS; i++) {
738         if ((g_links.links[i] != NULL) && (g_links.links[i]->type == LINK_INTERFACE)) {
739             if (strcmp(device_name, g_links.links[i]->dst_dev->name) == 0) {
740                 return i;
741             }
742         }
743     }
744
745     return -1;
746 }
747
748 int vnet_register_device(struct vm_device * vdev, 
749                          char * dev_name, 
750                          uchar_t mac[6], 
751                          int (*netif_input)(uchar_t * pkt, uint_t size, void * private_data), 
752                          void * data) {
753     struct vnet_if_device * if_dev;
754
755     int idx = search_device(dev_name);
756     if (idx != -1) {
757         PrintDebug("VNET: register device: Already has device with the name %s\n", dev_name);
758         return -1;
759     }
760     
761     if_dev = (struct vnet_if_device *)V3_Malloc(sizeof(struct vnet_if_device)); 
762     if (if_dev == NULL) {
763         PrintError("VNET: Malloc fails\n");
764         return -1;
765     }
766     
767     strcpy(if_dev->name, dev_name);
768     strncpy(if_dev->mac_addr, mac, 6);
769     if_dev->dev = vdev;
770     if_dev->input = netif_input;
771     if_dev->private_data = data;
772
773     struct link_entry * link = (struct link_entry *)V3_Malloc(sizeof(struct link_entry));
774     link->type = LINK_INTERFACE;
775     link->dst_dev = if_dev;
776
777     idx = __add_link_entry(link);
778
779     return idx;
780 }
781
782 #if 0
783 static int vnet_unregister_device(char * dev_name) {
784     int idx;
785
786     idx = search_device(dev_name);
787     
788     if (idx == -1) {
789         PrintDebug("VNET: No device with name %s found\n", dev_name);
790         return -1;
791     }
792
793     struct vnet_if_device * device = (struct vnet_if_device *)__delete_link_entry(idx);
794     if (device == NULL) {
795         PrintError("VNET: Device %s not in the link table %d, something may be wrong in link table\n", dev_name, idx);
796         return -1;
797     }
798
799     V3_Free(device);
800
801     return idx;
802 }
803
804 #endif
805
806 int v3_vnet_pkt_process() {
807     struct ethernet_pkt * pkt;
808
809     while ((pkt = (struct ethernet_pkt *)v3_dequeue(g_inpkt_q)) != NULL) {
810         PrintDebug("VNET: In vnet_check: pt length %d, pt type %d\n", (int)pkt->size, (int)pkt->type);
811
812         if (handle_one_pkt(pkt) != -1) {
813             PrintDebug("VNET: vnet_check: handle one packet!\n");  
814         } else {
815             PrintDebug("VNET: vnet_check: Fail to forward one packet, discard it!\n"); 
816         }
817         
818         V3_Free(pkt); // be careful here
819     }
820     
821     return 0;
822 }
823
824 static void init_empty_link_table() {
825     int i;
826
827     for (i = 0; i < MAX_LINKS; i++) {
828         g_links.links[i] = NULL;
829     }
830
831     g_links.size = 0;
832 }
833
834 static void init_empty_route_table() {  
835     int i;
836
837     for (i = 0; i < MAX_ROUTES; i++) {
838         g_routes.routes[i] = NULL;
839     }
840
841     g_links.size = 0;
842 }
843
844 static void init_tables() {
845     init_empty_link_table();
846     init_empty_route_table();
847     init_route_cache();
848 }
849
850 static void init_pkt_queue() {
851     PrintDebug("VNET Init package receiving queue\n");
852
853     g_inpkt_q = v3_create_queue();
854     v3_init_queue(g_inpkt_q);
855 }
856
857 static void free_link_mem(struct link_entry *link){
858     V3_Free(link->dst_dev);
859     V3_Free(link);
860 }
861
862 // TODO:
863 static int addto_routing_link_tables(struct routing_entry *route_tab, 
864                                                         uint16_t num_routes,
865                                                         struct link_entry *link_tab,
866                                                         uint16_t num_links){
867     struct routing_entry *route, *new_route;
868     struct link_entry *link, *new_link;
869     int new_idx;
870     int i;
871     int link_idxs[MAX_LINKS];
872
873     //add all of the links first, record their new indexs
874     for (i = 0; i < num_links; i++) {
875         link_idxs[i] = -1;
876         link = &link_tab[i];
877         new_link = (struct link_entry *)V3_Malloc(sizeof(struct link_entry));
878
879         if (new_link == NULL){
880             PrintError("VNET: Memory allocate error\n");
881             return -1;
882         }
883
884         new_link->type = link->type;
885         
886         //TODO: how to set the input parameters here
887         if (link->type == LINK_EDGE){
888             struct vnet_if_device *ifdev = (struct vnet_if_device *)V3_Malloc(sizeof(struct vnet_if_device));
889
890             if (ifdev == NULL){
891                 PrintError("VNET: Memory allocate fails\n");
892                 return -1;
893             }
894             
895             memcpy(ifdev->name, link->dst_dev->name, DEVICE_NAME_LEN);
896
897             // TODO:
898             //ifdev->mac_addr
899             //ifdev->input
900             //ifdev->private_data
901
902             new_link->dst_dev = ifdev;    
903         }else if (link->type == LINK_INTERFACE){
904             struct vnet_if_link *iflink = (struct vnet_if_link *)V3_Malloc(sizeof(struct vnet_if_link));
905
906             if (iflink == NULL){
907                 PrintError("VNET: Memory allocate fails\n");
908                 return -1;
909             }
910             iflink->pro_type = link->dst_link->pro_type;
911             iflink->dest_ip = link->dst_link->dest_ip;
912             iflink->dest_port = link->dst_link->dest_port;
913             memcpy(&iflink->vnet_header, &link->dst_link->vnet_header, sizeof(struct udp_link_header));
914
915             // TODO:
916             //iflink->input = 
917             //iflink->private_data = 
918             
919             new_link->dst_link = iflink;
920         }else{
921             PrintDebug("VNET: invalid link type\n");
922             V3_Free(new_link);
923             continue;
924         }
925         
926         new_idx = __add_link_entry(new_link);
927         if (new_idx < 0) {
928             PrintError("VNET: Adding link fails\n");
929             free_link_mem(new_link);
930             continue;
931         }       
932         link_idxs[i] = new_idx;
933     }
934
935     //add all of routes, replace with new link indexs
936     for (i = 0; i < num_routes; i++) {
937         route = &route_tab[i];
938        if (route->link_idx < 0 || route->link_idx >= num_links || 
939             ((route->src_link_idx != -1) && 
940               (route->src_link_idx < 0 || route->src_link_idx >= num_links))){
941             PrintError("VNET: There is error in the intial tables data from guest\n");
942             continue;
943         }
944
945         new_route = (struct routing_entry *)V3_Malloc(sizeof(struct routing_entry));
946
947         if (new_route == NULL){
948             PrintError("VNET: Memory allocate fails\n");
949             return -1;
950         }
951         memcpy(new_route, route, sizeof(struct routing_entry));
952         
953         new_route->link_idx = link_idxs[new_route->link_idx];
954                 
955         if (route->src_link_idx != -1)
956             new_route->src_link_idx = link_idxs[new_route->src_link_idx];
957
958         if((__add_route_entry(new_route)) == -1){
959             PrintDebug("VNET: Adding route fails");
960             V3_Free(new_route);
961         }
962         new_route = NULL;       
963     }
964
965     return 0;
966 }
967
968 //add the guest specified routes and links to the tables
969 static int handle_init_tables_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
970     struct vnet_if_link *link_array;
971     struct routing_entry *route_array;
972     addr_t routes_addr, routes_addr_gva;
973     addr_t links_addr, links_addr_gva;
974     uint16_t route_size, link_size;
975
976     routes_addr_gva = (addr_t)info->vm_regs.rbx;
977     route_size = (uint16_t)info->vm_regs.rcx;
978     links_addr_gva  = (addr_t)info->vm_regs.rdx;
979     link_size = (uint16_t)info->vm_regs.rsi;
980
981     PrintDebug("Vnet: In handle_init_tables_hcall\n");
982     PrintDebug("Vnet: route_table_start: %x, route size: %d\n", (int)routes_addr_gva, route_size);
983     PrintDebug("Vnet: link_table_start: %x, link size: %d\n", (int)links_addr_gva, link_size);
984         
985     if (guest_va_to_host_va(info, routes_addr_gva, &routes_addr) == -1) {
986         PrintError("VNET: Could not translate guest address\n");
987         return -1;
988     }
989     route_array = (struct routing_entry *)routes_addr;
990
991 #ifdef CONFIG_DEBUG_VNET
992     dump_dom0_routes(route_array, route_size);
993 #endif
994
995     if (guest_va_to_host_va(info, links_addr_gva, &links_addr) == -1) {
996         PrintError("VNET: Could not translate guest address\n");
997         return -1;
998     }   
999     link_array = (struct vnet_if_link *)links_addr;
1000
1001 #ifdef CONFIG_DEBUG_VNET
1002     dump_dom0_links(link_array, link_size);
1003 #endif
1004
1005
1006 // TODO:
1007     if (0)addto_routing_link_tables(route_array, route_size, NULL, 0);
1008
1009     return 0;
1010 }
1011
1012 void v3_vnet_init(struct guest_info * vm) {
1013     init_tables();
1014     init_pkt_queue();
1015         
1016     v3_register_hypercall(vm, VNET_INITAB_HCALL, handle_init_tables_hcall, NULL);
1017
1018     PrintDebug("VNET Initialized\n");
1019 }
1020
1021