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.


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