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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
15 * Author: Lei Xia <lxia@northwestern.edu>
16 * Yuan Tang <ytang@northwestern.edu>
18 * This is free software. You are permitted to use,
19 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
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>
27 #ifndef CONFIG_DEBUG_VNET
29 #define PrintDebug(fmt, args...)
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
38 }__attribute__((packed));
42 #define HASH_KEY_LEN 16
43 #define MIN_CACHE_SIZE 100
44 #define HASH_KEY_SIZE 16
47 struct link_entry * links[MAX_LINKS];
50 }__attribute__((packed));
52 struct routing_table {
53 struct routing_entry * routes[MAX_ROUTES];
56 }__attribute__((packed));
58 typedef char * route_hashkey_t;
60 struct route_cache_entry {
61 int num_matched_routes;
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;
73 static struct vnet_state_t g_vnet_state;//global state for vnet
75 static uint16_t ip_xsum(struct ip_header *ip_hdr, int hdr_len){
78 uint16_t *p = (uint16_t*) ip_hdr;
82 sum = (sum & 0xFFFF) + (sum >> 16);
87 sum += (uint16_t) *(uchar_t *)p;
90 sum = (sum & 0xFFFF) + (sum >> 16);
92 return (uint16_t)~sum;
95 static void ethernet_packet_init(struct ethernet_pkt *pt,
100 memset(&pt->ext_hdr, 0, sizeof(struct udp_link_header));
101 memcpy(pt->data, data, size);
104 static inline uint_t hash_from_key_fn(addr_t hashkey) {
105 return v3_hash_buffer((uint8_t *)hashkey, HASH_KEY_LEN);
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);
112 static int init_route_cache(struct vnet_state_t *vnet_state) {
113 vnet_state->g_route_cache = v3_create_htable(MIN_CACHE_SIZE,
117 if (vnet_state->g_route_cache == NULL) {
118 PrintError("Vnet: Route Cache Init Fails\n");
125 static void make_hash_key(route_hashkey_t hashkey,
132 for (j = 0; j < 6; j++) {
133 hashkey[j] = src_addr[j];
134 hashkey[j + 6] = dest_addr[j] + 1;
137 hashkey[12] = src_type;
139 *(int *)(hashkey + 12) = src_index;
142 static int add_route_to_cache(route_hashkey_t hashkey,
145 struct route_cache_entry * new_entry = NULL;
146 struct vnet_state_t *vnet_state = &g_vnet_state;
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");
155 new_entry->num_matched_routes = num_matched_r;
156 new_entry->matches = (int *)V3_Malloc(num_matched_r * sizeof(int));
158 if (new_entry->matches == NULL) {
159 PrintError("Vnet: Malloc fails\n");
163 for (i = 0; i < num_matched_r; i++) {
164 new_entry->matches[i] = matches[i];
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);
176 static int clear_hash_cache() {
177 struct vnet_state_t *vnet_state = &g_vnet_state;
179 v3_free_htable(vnet_state->g_route_cache, 1, 1);
180 vnet_state->g_route_cache = v3_create_htable(MIN_CACHE_SIZE,
184 if (vnet_state->g_route_cache == NULL) {
185 PrintError("Vnet: Route Cache Create Failurely\n");
192 static int look_into_cache(route_hashkey_t hashkey, int * matches) {
193 struct route_cache_entry * found = NULL;
196 struct vnet_state_t *vnet_state = &g_vnet_state;
198 found = (struct route_cache_entry *)v3_htable_search(vnet_state->g_route_cache,
202 n_matches = found->num_matched_routes;
204 for (i = 0; i < n_matches; i++) {
205 matches[i] = found->matches[i];
213 #ifdef CONFIG_DEBUG_VNET
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);
220 static inline uint8_t hex_nybble_to_nybble(const uint8_t hexnybble) {
221 uint8_t x = toupper(hexnybble);
226 return 10 + (x - 'A');
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));
235 static inline void string_to_mac(const char *str, uint8_t mac[6]) {
238 for (k = 0; k < 6; k++) {
239 mac[k] = hex_byte_to_byte(&(str[(2 * k) + k]));
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]);
250 static void print_route(struct routing_entry *route){
254 mac_to_string(route->src_mac, src_str);
255 mac_to_string(route->dest_mac, dest_str);
257 PrintDebug("SRC(%s), DEST(%s), src_mac_qual(%d), dst_mac_qual(%d)\n",
261 route->dest_mac_qual);
262 PrintDebug("Src_Link(%d), src_type(%d), dst_link(%d), dst_type(%d)\n\n",
270 static void dump_routes(struct routing_entry **route_tables) {
273 PrintDebug("\nVnet: route table dump start =====\n");
275 for(i = 0; i < MAX_ROUTES; i++) {
276 if (route_tables[i] != NULL){
277 print_route(route_tables[i]);
281 PrintDebug("\nVnet: route table dump end =====\n");
284 static void dump_dom0_routes(struct routing_entry routes[], int size) {
287 PrintDebug("\nVnet: route table from dom0 guest =====\n");
289 for(i = 0; i <size; i++) {
290 print_route(&routes[i]);
293 PrintDebug("\nVnet: route table dom0 guest end =====\n");
296 static void dump_dom0_links(struct vnet_if_link links[], int size) {
297 struct vnet_if_link *link = NULL;
300 PrintDebug("\nVnet: link table from dom0 guest =====\n");
302 for(i = 0; i <size; i++) {
304 PrintDebug("link: %d\n", i);
305 PrintDebug("dest_ip(%ld), dst_port(%d), prot_type(%d)\n",
309 PrintDebug("vnet_header:\n");
310 v3_hexdump(&link->vnet_header, sizeof(struct udp_link_header), NULL, 0);
313 PrintDebug("\nVnet: link table dom0 guest end =====\n");
318 static int __add_link_entry(struct link_entry * link) {
320 struct vnet_state_t *vnet_state = &g_vnet_state;
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++;
330 v3_unlock(vnet_state->g_links.lock);
332 if (idx == MAX_LINKS) {
333 PrintDebug("VNET: No available Link entry for new link\n");
340 static int __add_route_entry(struct routing_entry * route) {
342 struct vnet_state_t *vnet_state = &g_vnet_state;
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++;
352 v3_unlock(vnet_state->g_routes.lock);
354 if(idx == MAX_LINKS){
355 PrintDebug("VNET: No available route entry for new route\n");
359 #ifdef CONFIG_DEBUG_VNET
360 dump_routes(vnet_state->g_routes.routes);
366 int vnet_add_route_entry(char src_mac[6],
371 link_type_t link_type,
373 link_type_t src_link_type) {
374 struct routing_entry * new_route = (struct routing_entry *)V3_Malloc(sizeof(struct routing_entry));
377 PrintDebug("Vnet: vnet_add_route_entry\n");
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);
384 if ((dest_mac_qual != MAC_ANY)) {
385 memcpy(new_route->dest_mac, dest_mac, 6);
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;
395 if ((idx = __add_route_entry(new_route)) == -1) {
396 PrintError("Could not add route entry\n");
405 static int match_route(uint8_t * src_mac,
407 link_type_t src_type,
410 struct routing_entry *route = NULL;
411 struct vnet_state_t *vnet_state = &g_vnet_state;
412 int matched_routes[MAX_ROUTES];
416 #ifdef CONFIG_DEBUG_VNET
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);
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];
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;
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;
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;
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;
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;
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;
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;
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;
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;
485 }//end if src_type == Link_any
489 PrintDebug("Vnet: match_route: Matches=%d\n", num_matches);
491 for (i = 0; i < num_matches; i++) {
492 matches[i] = matched_routes[i];
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
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;
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);
514 #ifdef CONFIG_DEBUG_VNET
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);
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);
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);
533 PrintDebug("Vnet: HandleDataOverLink: Matches=%d\n", num_matched_routes);
535 if (num_matched_routes == 0) {
539 for (i = 0; i < num_matched_routes; i++) {//send packet to all destinations
540 int route_index = -1;
543 struct link_entry * link = NULL;
545 route_index = matches[i];
546 link_index = vnet_state->g_routes.routes[route_index]->link_idx;
548 if ((link_index < 0) || (link_index > MAX_LINKS) ||
549 (vnet_state->g_links.links[link_index] == NULL)) {
553 link = vnet_state->g_links.links[link_index];
555 if (link->type == LINK_EDGE) {
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));
566 int hdr_size = sizeof(struct udp_link_header);
567 memcpy(&pkt->ext_hdr, hdr, 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);
575 PrintDebug("VNET: Link protocol type not support\n");
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);
584 PrintDebug("Vnet: Wrong Edge type of link: %d\n", link_index);
588 PrintDebug("Vnet: HandleDataOverLink: Forward packet according to Route entry %d to link %d\n", route_index, link_index);
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;
598 pkt = (struct ethernet_pkt *)V3_Malloc(sizeof(struct ethernet_pkt));
600 PrintError("VNET: Memory allocate fails\n");
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);
608 #ifdef CONFIG_DEBUG_VNET
609 PrintDebug("VNET: send_pkt: transmitting packet: (size:%d)\n", (int)pkt->size);
610 print_packet((char *)data, len);
616 int v3_vnet_send_rawpkt(uchar_t * buf,
618 void *private_data) {
619 PrintDebug("VNET: In v3_vnet_send_rawpkt: pkt length %d\n", len);
621 return send_ethernet_pkt(buf, len, private_data);
624 //sending the packet from Dom0, should remove the link header
625 int v3_vnet_send_udppkt(uchar_t * buf,
627 void *private_data) {
628 uint_t hdr_len = sizeof(struct udp_link_header);
630 PrintDebug("VNET: In v3_vnet_send_udppkt: pkt length %d\n", len);
632 return send_ethernet_pkt((uchar_t *)(buf+hdr_len), len - hdr_len, private_data);
635 static int search_device(char * device_name) {
636 struct vnet_state_t *vnet_state = &g_vnet_state;
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) {
650 int vnet_register_device(struct vm_device * vdev,
653 int (*netif_input)(uchar_t * pkt, uint_t size, void * private_data),
655 struct vnet_if_device * if_dev;
657 int idx = search_device(dev_name);
659 PrintDebug("VNET: register device: Already has device with the name %s\n", dev_name);
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");
669 strcpy(if_dev->name, dev_name);
670 strncpy(if_dev->mac_addr, mac, 6);
672 if_dev->input = netif_input;
673 if_dev->private_data = data;
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;
679 idx = __add_link_entry(link);
684 int v3_vnet_pkt_process() {
685 struct ethernet_pkt * pkt;
686 struct vnet_state_t *vnet_state = &g_vnet_state;
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);
692 PrintDebug("VNET: vnet_check: Fail to forward one packet, discard it!\n");
695 V3_Free(pkt); // be careful here
701 static void vnet_state_init(struct vnet_state_t *vnet_state) {
704 /*initial links table */
705 for (i = 0; i < MAX_LINKS; i++) {
706 vnet_state->g_links.links[i] = NULL;
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");
712 PrintDebug("VNET: Links table initiated\n");
714 /*initial routes table */
715 for (i = 0; i < MAX_ROUTES; i++) {
716 vnet_state->g_routes.routes[i] = NULL;
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");
722 PrintDebug("VNET: Routes table initiated\n");
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");
729 /*initial routing cache */
730 init_route_cache(vnet_state);
733 static void free_link_mem(struct link_entry *link){
734 V3_Free(link->dst_dev);
740 static int addto_routing_link_tables(struct routing_entry *route_tab,
742 struct link_entry *link_tab,
744 struct routing_entry *route, *new_route;
745 struct link_entry *link, *new_link;
748 int link_idxs[MAX_LINKS];
750 //add all of the links first, record their new indexs
751 for (i = 0; i < num_links; i++) {
754 new_link = (struct link_entry *)V3_Malloc(sizeof(struct link_entry));
756 if (new_link == NULL){
757 PrintError("VNET: Memory allocate error\n");
761 new_link->type = link->type;
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));
768 PrintError("VNET: Memory allocate fails\n");
772 memcpy(ifdev->name, link->dst_dev->name, DEVICE_NAME_LEN);
777 //ifdev->private_data
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));
784 PrintError("VNET: Memory allocate fails\n");
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));
794 //iflink->private_data =
796 new_link->dst_link = iflink;
798 PrintDebug("VNET: invalid link type\n");
803 new_idx = __add_link_entry(new_link);
805 PrintError("VNET: Adding link fails\n");
806 free_link_mem(new_link);
809 link_idxs[i] = new_idx;
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");
822 new_route = (struct routing_entry *)V3_Malloc(sizeof(struct routing_entry));
823 if (new_route == NULL){
824 PrintError("VNET: Memory allocate fails\n");
827 memcpy(new_route, route, sizeof(struct routing_entry));
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];
833 if((__add_route_entry(new_route)) == -1){
834 PrintDebug("VNET: Adding route fails");
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;
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;
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);
860 if (guest_va_to_host_va(info, routes_addr_gva, &routes_addr) == -1) {
861 PrintError("VNET: Could not translate guest address\n");
864 route_array = (struct routing_entry *)routes_addr;
866 #ifdef CONFIG_DEBUG_VNET
867 dump_dom0_routes(route_array, route_size);
870 if (guest_va_to_host_va(info, links_addr_gva, &links_addr) == -1) {
871 PrintError("VNET: Could not translate guest address\n");
874 link_array = (struct vnet_if_link *)links_addr;
876 #ifdef CONFIG_DEBUG_VNET
877 dump_dom0_links(link_array, link_size);
882 if (0)addto_routing_link_tables(route_array, route_size, NULL, 0);
887 void v3_init_vnet() {
888 vnet_state_init(&g_vnet_state);
890 PrintDebug("VNET Initialized\n");
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,
897 handle_init_tables_hcall,