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.


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