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.


7f9248b4a8a9a5bb6800911930925847f6b1965e
[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/vm_guest_mem.h>
24 #include <palacios/vmm_lock.h>
25 #include <palacios/vmm_queue.h>
26 #include <palacios/vmm_sprintf.h>
27
28 #ifndef CONFIG_DEBUG_VNET
29 #undef PrintDebug
30 #define PrintDebug(fmt, args...)
31 #endif
32
33
34
35 struct eth_hdr {
36     uint8_t dst_mac[6];
37     uint8_t src_mac[6];
38     uint16_t type; // indicates layer 3 protocol type
39 } __attribute__((packed));
40
41
42
43
44
45 struct vnet_dev {
46
47     uint8_t mac_addr[6];
48     struct v3_vm_info * vm;
49     
50     int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data);
51     void * private_data;
52     
53     int dev_id;
54     struct list_head node;
55 } __attribute__((packed));
56
57
58 struct vnet_brg_dev {
59     struct v3_vm_info * vm;
60     
61     int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data);
62     void * private_data;
63 } __attribute__((packed));
64
65
66
67
68
69 struct vnet_route_info {
70     struct v3_vnet_route route_def;
71
72     struct vnet_dev * dst_dev;
73     struct vnet_dev * src_dev;
74
75     struct list_head node;
76     struct list_head match_node; // used for route matching
77 };
78
79
80
81
82 struct route_list {
83     uint8_t hash_buf[VNET_HASH_SIZE];
84
85     uint32_t num_routes;
86     struct vnet_route_info * routes[0];
87 } __attribute__((packed));
88
89
90
91 static struct {
92     struct list_head routes;
93     struct list_head devs;
94     
95     int num_routes;
96     int num_devs;
97
98     struct vnet_brg_dev *bridge;
99
100     v3_lock_t lock;
101
102     struct gen_queue * inpkt_q;
103     struct hashtable * route_cache;
104
105 } vnet_state;
106
107
108
109
110 #ifdef CONFIG_DEBUG_VNET
111 static inline void mac_to_string(char mac[6], char * buf) {
112     snprintf(buf, 50, "%x:%x:%x:%x:%x:%x", 
113              mac[0], mac[1], mac[2],
114              mac[3], mac[4], mac[5]);
115 }
116
117 static void print_route(struct vnet_route_info *route){
118     char str[50];
119
120     mac_to_string(route->route_def.src_mac, str);
121     PrintDebug("Src Mac (%s),  src_qual (%d)\n", 
122                         str, route->route_def.src_mac_qual);
123     mac_to_string(route->route_def.dst_mac, str);
124     PrintDebug("Dst Mac (%s),  dst_qual (%d)\n", 
125                         str, route->route_def.dst_mac_qual);
126     PrintDebug("Src dev id (%d), src type (%d)", 
127                         route->route_def.src_id, 
128                         route->route_def.src_type);
129     PrintDebug("Dst dev id (%d), dst type (%d)\n", 
130                         route->route_def.dst_id, 
131                         route->route_def.dst_type);
132     if (route->route_def.dst_type == LINK_INTERFACE) {
133         PrintDebug("dst_dev (%p), dst_dev_id (%d), dst_dev_input (%p), dst_dev_data (%p)\n",
134                                         route->dst_dev,
135                                         route->dst_dev->dev_id,
136                                         route->dst_dev->input,
137                                         route->dst_dev->private_data);
138     }
139 }
140
141 static void dump_routes(){
142         struct vnet_route_info *route;
143
144         int i = 0;
145         PrintDebug("\n========Dump routes starts ============\n");
146         list_for_each_entry(route, &(vnet_state.routes), node) {
147                 PrintDebug("\nroute %d:\n", ++i);
148                 
149                 print_route(route);
150         }
151         PrintDebug("\n========Dump routes end ============\n");
152 }
153
154 #endif
155
156
157 /* 
158  * A VNET packet is a packed struct with the hashed fields grouped together.
159  * This means we can generate the hash from an offset into the pkt struct
160  */
161 static inline uint_t hash_fn(addr_t hdr_ptr) {    
162     uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
163
164     return v3_hash_buffer(hdr_buf, VNET_HASH_SIZE);
165 }
166
167 static inline int hash_eq(addr_t key1, addr_t key2) {   
168     return (memcmp((uint8_t *)key1, (uint8_t *)key2, VNET_HASH_SIZE) == 0);
169 }
170
171
172 static int add_route_to_cache(struct v3_vnet_pkt * pkt, struct route_list * routes) {
173     memcpy(routes->hash_buf, pkt->hash_buf, VNET_HASH_SIZE);    
174
175     if (v3_htable_insert(vnet_state.route_cache, (addr_t)routes->hash_buf, (addr_t)routes) == 0) {
176         PrintError("Vnet: Failed to insert new route entry to the cache\n");
177         return -1;
178     }
179     
180     return 0;
181 }
182
183 static int clear_hash_cache() {
184
185     v3_free_htable(vnet_state.route_cache, 1, 1);
186     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
187
188     return 0;
189 }
190
191 static int look_into_cache(struct v3_vnet_pkt * pkt, struct route_list ** routes) {
192     
193     *routes = (struct route_list *)v3_htable_search(vnet_state.route_cache, (addr_t)(pkt->hash_buf));
194    
195     return 0;
196 }
197
198
199 static struct vnet_dev * find_dev_by_id(int idx) {
200     struct vnet_dev * dev = NULL; 
201     
202     list_for_each_entry(dev, &(vnet_state.devs), node) {
203         int dev_id = dev->dev_id;
204
205         if (dev_id == idx)
206             return dev;
207     }
208
209     return NULL;
210 }
211
212 static struct vnet_dev * find_dev_by_mac(char mac[6]) {
213     struct vnet_dev * dev = NULL; 
214     
215     list_for_each_entry(dev, &(vnet_state.devs), node) {
216         if (!memcmp(dev->mac_addr, mac, 6))
217             return dev;
218     }
219
220     return NULL;
221 }
222
223 int get_device_id_by_mac(char mac[6]){
224
225     struct vnet_dev *dev = find_dev_by_mac(mac);
226
227     if (dev == NULL)
228         return -1;
229
230     return dev->dev_id;
231 }
232
233
234 int v3_vnet_add_route(struct v3_vnet_route route) {
235     struct vnet_route_info * new_route = NULL;
236     unsigned long flags; 
237
238     new_route = (struct vnet_route_info *)V3_Malloc(sizeof(struct vnet_route_info));
239     memset(new_route, 0, sizeof(struct vnet_route_info));
240
241     PrintDebug("Vnet: vnet_add_route_entry: dst_id: %d, dst_type: %d\n",
242                         route.dst_id, route.dst_type);  
243     
244     memcpy(new_route->route_def.src_mac, route.src_mac, 6);
245     memcpy(new_route->route_def.dst_mac, route.dst_mac, 6);
246     new_route->route_def.src_mac_qual = route.src_mac_qual;
247     new_route->route_def.dst_mac_qual = route.dst_mac_qual;
248     new_route->route_def.dst_id = route.dst_id;
249     new_route->route_def.dst_type = route.dst_type;
250     new_route->route_def.src_id = route.src_id;
251     new_route->route_def.src_type = route.src_type;
252
253     if (new_route->route_def.dst_type == LINK_INTERFACE) {
254         new_route->dst_dev = find_dev_by_id(new_route->route_def.dst_id);
255         PrintDebug("Vnet: Add route, get device: dev_id %d, input : %p, private_data %p\n",
256                         new_route->dst_dev->dev_id, new_route->dst_dev->input, new_route->dst_dev->private_data);
257     }
258
259     if (new_route->route_def.src_type == LINK_INTERFACE) {
260         new_route->src_dev = find_dev_by_id(new_route->route_def.src_id);
261     }
262
263     flags = v3_lock_irqsave(vnet_state.lock);
264     list_add(&(new_route->node), &(vnet_state.routes));
265     v3_unlock_irqrestore(vnet_state.lock, flags);
266    
267     clear_hash_cache();
268
269 #ifdef CONFIG_DEBUG_VNET
270     dump_routes();
271 #endif
272
273     return 0;
274 }
275
276
277
278 // At the end allocate a route_list
279 // This list will be inserted into the cache so we don't need to free it
280 static struct route_list * match_route(struct v3_vnet_pkt * pkt) {
281     struct vnet_route_info * route = NULL; 
282     struct route_list * matches = NULL;
283     int num_matches = 0;
284     int max_rank = 0;
285     struct list_head match_list;
286     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
287     uint8_t src_type = pkt->src_type;
288     uint32_t src_link = pkt->src_id;
289
290 #ifdef CONFIG_DEBUG_VNET
291     {
292         char dst_str[50];
293         char src_str[50];
294
295         mac_to_string(hdr->src_mac, src_str);  
296         mac_to_string(hdr->dst_mac, dst_str);
297         PrintDebug("Vnet: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
298     }
299 #endif
300
301     INIT_LIST_HEAD(&match_list);
302     
303 #define UPDATE_MATCHES(rank) do {                               \
304         if (max_rank < (rank)) {                                \
305             max_rank = (rank);                                  \
306             INIT_LIST_HEAD(&match_list);                        \
307                                                                 \
308             list_add(&(route->match_node), &match_list);        \
309             num_matches = 1;                                    \
310         } else if (max_rank == (rank)) {                        \
311             list_add(&(route->match_node), &match_list);        \
312             num_matches++;                                      \
313         }                                                       \
314     } while (0)
315     
316
317     list_for_each_entry(route, &(vnet_state.routes), node) {
318         struct v3_vnet_route * route_def = &(route->route_def);
319
320         // CHECK SOURCE TYPE HERE
321         if ( (route_def->src_type != LINK_ANY) && 
322              ( (route_def->src_type != src_type) || 
323                ( (route_def->src_id != src_link) &&
324                  (route_def->src_id != (uint32_t)-1)))) {
325             continue;
326         }
327
328
329         if ((route_def->dst_mac_qual == MAC_ANY) &&
330             (route_def->src_mac_qual == MAC_ANY)) {      
331             UPDATE_MATCHES(3);
332         }
333         
334         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
335             if (route_def->src_mac_qual != MAC_NOT) {
336                 if (route_def->dst_mac_qual == MAC_ANY) {
337                     UPDATE_MATCHES(6);
338                 } else if (route_def->dst_mac_qual != MAC_NOT &&
339                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
340                     UPDATE_MATCHES(8);
341                 }
342             }
343         }
344             
345         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
346             if (route_def->dst_mac_qual != MAC_NOT) {
347                 if (route_def->src_mac_qual == MAC_ANY) {
348                     UPDATE_MATCHES(6);
349                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
350                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
351                     UPDATE_MATCHES(8);
352                 }
353             }
354         }
355             
356         if ((route_def->dst_mac_qual == MAC_NOT) &&
357             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
358             if (route_def->src_mac_qual == MAC_ANY) {
359                 UPDATE_MATCHES(5);
360             } else if ((route_def->src_mac_qual != MAC_NOT) && 
361                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
362                 UPDATE_MATCHES(7);
363             }
364         }
365         
366         if ((route_def->src_mac_qual == MAC_NOT) &&
367             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
368             if (route_def->dst_mac_qual == MAC_ANY) {
369                 UPDATE_MATCHES(5);
370             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
371                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
372                 UPDATE_MATCHES(7);
373             }
374         }
375         
376         // Default route
377         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &&
378              (route_def->dst_mac_qual == MAC_NONE)) {
379             UPDATE_MATCHES(4);
380         }
381     }
382
383     PrintDebug("Vnet: match_route: Matches=%d\n", num_matches);
384
385     if (num_matches == 0) {
386         return NULL;
387     }
388
389     matches = V3_Malloc(sizeof(struct route_list) + 
390                         (sizeof(struct vnet_route_info *) * num_matches));
391
392     matches->num_routes = num_matches;
393
394     {
395         int i = 0;
396         list_for_each_entry(route, &match_list, match_node) {
397             matches->routes[i++] = route;
398         }
399     }
400
401     return matches;
402 }
403
404 static int handle_one_pkt(struct v3_vnet_pkt * pkt, void *private_data) {
405     struct route_list * matched_routes = NULL;
406     unsigned long flags;
407     int i;
408
409
410 #ifdef CONFIG_DEBUG_VNET
411    {
412         struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
413         char dest_str[30];
414         char src_str[30];
415
416         mac_to_string(hdr->src_mac, src_str);  
417         mac_to_string(hdr->dst_mac, dest_str);
418         PrintDebug("Vnet: HandleDataOverLink. SRC(%s), DEST(%s)\n", src_str, dest_str);
419    }
420 #endif
421
422 #ifdef CONFIG_VNET_PROFILE
423     struct guest_info *core = (struct guest_info *)private_data;
424     uint64_t start, end;
425     rdtscll(start);
426 #endif
427
428     flags = v3_lock_irqsave(vnet_state.lock);
429
430     look_into_cache(pkt, &matched_routes);
431         
432     if (matched_routes == NULL) {  
433         PrintDebug("Vnet: can not find route in cache, looking into routing table\n");
434         
435         matched_routes = match_route(pkt);
436                 
437         if (matched_routes) {
438             add_route_to_cache(pkt, matched_routes);
439         } else {
440             PrintDebug("Could not find route for packet...\n");
441             v3_unlock_irqrestore(vnet_state.lock, flags);
442             return -1;
443         }
444     }
445
446     v3_unlock_irqrestore(vnet_state.lock, flags);
447
448 #ifdef CONFIG_VNET_PROFILE
449     {
450         rdtscll(end);
451         core->vnet_times.time_route_lookup = end - start;
452     }
453 #endif
454
455     PrintDebug("Vnet: HandleOnePacket: route matches %d\n", matched_routes->num_routes);
456     for (i = 0; i < matched_routes->num_routes; i++) {
457          struct vnet_route_info * route = matched_routes->routes[i];
458         
459         if (route->route_def.dst_type == LINK_EDGE) {
460             pkt->dst_type = LINK_EDGE;
461             pkt->dst_id = route->route_def.dst_id;
462             if (vnet_state.bridge == NULL) {
463                 PrintDebug("VNET: No bridge to sent data to links\n");
464                 continue;
465             }
466             if (vnet_state.bridge->input(vnet_state.bridge->vm, pkt, vnet_state.bridge->private_data) == -1) {
467                 PrintDebug("VNET: Packet not sent properly\n");
468                 continue;
469               } 
470         } else if (route->route_def.dst_type == LINK_INTERFACE) {
471             if (route->dst_dev->input(route->dst_dev->vm, pkt, route->dst_dev->private_data) == -1) {
472                 PrintDebug("VNET: Packet not sent properly\n");
473                 continue;
474              }
475         } else {
476             PrintDebug("Vnet: Wrong Edge type\n");
477             continue;
478         }
479
480         PrintDebug("Vnet: HandleOnePacket: Forward packet according to Route\n");
481     }
482
483 #ifdef CONFIG_VNET_PROFILE
484     {
485         rdtscll(start);
486         core->vnet_times.time_copy_to_guest = start - end;
487     }
488 #endif
489     
490     return 0;
491 }
492
493 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void *private_data) {
494     PrintDebug("In Vnet Send: pkt size: %d\n", pkt->size);
495                 
496     if (handle_one_pkt(pkt, private_data) != -1) {
497         PrintDebug("VNET: send one packet! pt length %d\n", pkt->size);  
498     } else {
499         PrintDebug("VNET: Fail to forward one packet, discard it!\n"); 
500     }
501
502     return 0;
503 }
504
505 int v3_vnet_add_dev(struct v3_vm_info *vm,uint8_t mac[6], 
506                     int (*netif_input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data), 
507                     void * priv_data){
508     struct vnet_dev * new_dev = NULL;
509     unsigned long flags;
510     int dev_id;
511
512     flags = v3_lock_irqsave(vnet_state.lock);
513         
514     new_dev = find_dev_by_mac(mac);
515
516     if (new_dev) {
517         PrintDebug("VNET: register device: Already has device with the same mac\n");
518         dev_id = -1;
519         goto exit;
520     }
521     
522     new_dev = (struct vnet_dev *)V3_Malloc(sizeof(struct vnet_dev)); 
523
524     if (new_dev == NULL) {
525         PrintError("VNET: Malloc fails\n");
526         dev_id = -1;
527         goto exit;
528     }
529    
530     memcpy(new_dev->mac_addr, mac, 6);
531     new_dev->input = netif_input;
532     new_dev->private_data = priv_data;
533     new_dev->vm = vm;
534         
535     list_add(&(new_dev->node), &(vnet_state.devs));
536     vnet_state.num_devs ++;
537     new_dev->dev_id = vnet_state.num_devs;
538     dev_id = new_dev->dev_id;
539
540     PrintDebug("Vnet: Add Device: dev_id %d, input : %p, private_data %p\n",
541                         new_dev->dev_id, new_dev->input, new_dev->private_data);
542
543 exit:
544         
545     v3_unlock_irqrestore(vnet_state.lock, flags);
546  
547     return dev_id;
548 }
549
550
551 int v3_vnet_add_bridge(struct v3_vm_info * vm,
552                                 int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data), 
553                                 void * priv_data){
554     unsigned long flags;
555         
556     flags = v3_lock_irqsave(vnet_state.lock);
557
558     if(vnet_state.bridge != NULL){
559         PrintDebug("Vnet: Replace current bridge with a new one\n");
560     } else {
561         vnet_state.bridge = (struct vnet_brg_dev *)V3_Malloc(sizeof(struct vnet_brg_dev));
562         if (vnet_state.bridge == NULL) {
563             PrintError("Malloc Fails\n");
564             return -1;
565         }
566     }
567
568     vnet_state.bridge->vm = vm;
569     vnet_state.bridge->input = input;
570     vnet_state.bridge->private_data = priv_data;
571
572     v3_unlock_irqrestore(vnet_state.lock, flags);
573
574     return 0;
575 }
576
577 int V3_init_vnet() {
578         
579     INIT_LIST_HEAD(&(vnet_state.routes));
580     INIT_LIST_HEAD(&(vnet_state.devs));
581
582     vnet_state.num_devs = 0;
583     vnet_state.num_routes = 0;
584
585     PrintDebug("VNET: Links and Routes tables initiated\n");
586
587     if (v3_lock_init(&(vnet_state.lock)) == -1){
588         PrintError("VNET: Failure to init lock for routes table\n");
589     }
590
591     PrintDebug("VNET: Locks initiated\n");
592
593     vnet_state.inpkt_q = v3_create_queue();
594     v3_init_queue(vnet_state.inpkt_q);
595     PrintDebug("VNET: Receiving queue initiated\n");
596
597     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
598
599     if (vnet_state.route_cache == NULL) {
600         PrintError("Vnet: Route Cache Init Fails\n");
601         return -1;
602     }
603
604     PrintDebug("VNET: initiated\n");
605
606     return 0;
607 }