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.


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