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.


vnet fixes for compilation
[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
265     list_add(&(new_route->node), &(vnet_state.routes));
266     clear_hash_cache();
267
268     v3_unlock_irqrestore(vnet_state.lock, flags);
269    
270
271 #ifdef CONFIG_DEBUG_VNET
272     dump_routes();
273 #endif
274
275     return 0;
276 }
277
278
279
280 // At the end allocate a route_list
281 // This list will be inserted into the cache so we don't need to free it
282 static struct route_list * match_route(struct v3_vnet_pkt * pkt) {
283     struct vnet_route_info * route = NULL; 
284     struct route_list * matches = NULL;
285     int num_matches = 0;
286     int max_rank = 0;
287     struct list_head match_list;
288     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
289     uint8_t src_type = pkt->src_type;
290     uint32_t src_link = pkt->src_id;
291
292 #ifdef CONFIG_DEBUG_VNET
293     {
294         char dst_str[50];
295         char src_str[50];
296
297         mac_to_string(hdr->src_mac, src_str);  
298         mac_to_string(hdr->dst_mac, dst_str);
299         PrintDebug("Vnet: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
300     }
301 #endif
302
303     INIT_LIST_HEAD(&match_list);
304     
305 #define UPDATE_MATCHES(rank) do {                               \
306         if (max_rank < (rank)) {                                \
307             max_rank = (rank);                                  \
308             INIT_LIST_HEAD(&match_list);                        \
309                                                                 \
310             list_add(&(route->match_node), &match_list);        \
311             num_matches = 1;                                    \
312         } else if (max_rank == (rank)) {                        \
313             list_add(&(route->match_node), &match_list);        \
314             num_matches++;                                      \
315         }                                                       \
316     } while (0)
317     
318
319     list_for_each_entry(route, &(vnet_state.routes), node) {
320         struct v3_vnet_route * route_def = &(route->route_def);
321
322         // CHECK SOURCE TYPE HERE
323         if ( (route_def->src_type != LINK_ANY) && 
324              ( (route_def->src_type != src_type) || 
325                ( (route_def->src_id != src_link) &&
326                  (route_def->src_id != (uint32_t)-1)))) {
327             continue;
328         }
329
330
331         if ((route_def->dst_mac_qual == MAC_ANY) &&
332             (route_def->src_mac_qual == MAC_ANY)) {      
333             UPDATE_MATCHES(3);
334         }
335         
336         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
337             if (route_def->src_mac_qual != MAC_NOT) {
338                 if (route_def->dst_mac_qual == MAC_ANY) {
339                     UPDATE_MATCHES(6);
340                 } else if (route_def->dst_mac_qual != MAC_NOT &&
341                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
342                     UPDATE_MATCHES(8);
343                 }
344             }
345         }
346             
347         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
348             if (route_def->dst_mac_qual != MAC_NOT) {
349                 if (route_def->src_mac_qual == MAC_ANY) {
350                     UPDATE_MATCHES(6);
351                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
352                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
353                     UPDATE_MATCHES(8);
354                 }
355             }
356         }
357             
358         if ((route_def->dst_mac_qual == MAC_NOT) &&
359             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
360             if (route_def->src_mac_qual == MAC_ANY) {
361                 UPDATE_MATCHES(5);
362             } else if ((route_def->src_mac_qual != MAC_NOT) && 
363                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
364                 UPDATE_MATCHES(7);
365             }
366         }
367         
368         if ((route_def->src_mac_qual == MAC_NOT) &&
369             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
370             if (route_def->dst_mac_qual == MAC_ANY) {
371                 UPDATE_MATCHES(5);
372             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
373                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
374                 UPDATE_MATCHES(7);
375             }
376         }
377         
378         // Default route
379         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &&
380              (route_def->dst_mac_qual == MAC_NONE)) {
381             UPDATE_MATCHES(4);
382         }
383     }
384
385     PrintDebug("Vnet: match_route: Matches=%d\n", num_matches);
386
387     if (num_matches == 0) {
388         return NULL;
389     }
390
391     matches = V3_Malloc(sizeof(struct route_list) + 
392                         (sizeof(struct vnet_route_info *) * num_matches));
393
394     matches->num_routes = num_matches;
395
396     {
397         int i = 0;
398         list_for_each_entry(route, &match_list, match_node) {
399             matches->routes[i++] = route;
400         }
401     }
402
403     return matches;
404 }
405
406
407 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
408     struct route_list * matched_routes = NULL;
409     unsigned long flags;
410     int i;
411
412 #ifdef CONFIG_DEBUG_VNET
413    {
414         struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
415         char dest_str[30];
416         char src_str[30];
417
418         mac_to_string(hdr->src_mac, src_str);  
419         mac_to_string(hdr->dst_mac, dest_str);
420         PrintDebug("Vnet: HandleDataOverLink. SRC(%s), DEST(%s)\n", src_str, dest_str);
421    }
422 #endif
423
424 #ifdef CONFIG_VNET_PROFILE
425     struct guest_info *core = (struct guest_info *)private_data;
426     uint64_t start, end;
427     rdtscll(start);
428 #endif
429
430     flags = v3_lock_irqsave(vnet_state.lock);
431
432     look_into_cache(pkt, &matched_routes);
433         
434     if (matched_routes == NULL) {  
435         PrintDebug("Vnet: can not find route in cache, looking into routing table\n");
436         
437         matched_routes = match_route(pkt);
438                 
439         if (matched_routes) {
440             add_route_to_cache(pkt, matched_routes);
441         } else {
442             PrintDebug("Could not find route for packet...\n");
443             v3_unlock_irqrestore(vnet_state.lock, flags);
444             return -1;
445         }
446     }
447
448     v3_unlock_irqrestore(vnet_state.lock, flags);
449
450 #ifdef CONFIG_VNET_PROFILE
451     {
452         rdtscll(end);
453         core->vnet_times.time_route_lookup = end - start;
454     }
455 #endif
456
457     PrintDebug("Vnet: HandleOnePacket: route matches %d\n", matched_routes->num_routes);
458
459     for (i = 0; i < matched_routes->num_routes; i++) {
460          struct vnet_route_info * route = matched_routes->routes[i];
461         
462         if (route->route_def.dst_type == LINK_EDGE) {
463             pkt->dst_type = LINK_EDGE;
464             pkt->dst_id = route->route_def.dst_id;
465
466             if (vnet_state.bridge == NULL) {
467                 PrintDebug("VNET: No bridge to sent data to links\n");
468                 continue;
469             }
470
471             if (vnet_state.bridge->input(vnet_state.bridge->vm, pkt, vnet_state.bridge->private_data) == -1) {
472                 PrintDebug("VNET: Packet not sent properly\n");
473                 continue;
474             } 
475
476         } else if (route->route_def.dst_type == LINK_INTERFACE) {
477             if (route->dst_dev->input(route->dst_dev->vm, pkt, route->dst_dev->private_data) == -1) {
478                 PrintDebug("VNET: Packet not sent properly\n");
479                 continue;
480              }
481         } else {
482             PrintDebug("Vnet: Wrong Edge type\n");
483             continue;
484         }
485
486         PrintDebug("Vnet: HandleOnePacket: Forward packet according to Route\n");
487     }
488
489 #ifdef CONFIG_VNET_PROFILE
490     {
491         rdtscll(start);
492         core->vnet_times.time_copy_to_guest = start - end;
493     }
494 #endif
495     
496     return 0;
497 }
498
499 int v3_vnet_add_dev(struct v3_vm_info *vm, uint8_t mac[6], 
500                     int (*netif_input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data), 
501                     void * priv_data){
502     struct vnet_dev * new_dev = NULL;
503     unsigned long flags;
504
505     new_dev = (struct vnet_dev *)V3_Malloc(sizeof(struct vnet_dev)); 
506
507     if (new_dev == NULL) {
508         PrintError("VNET: Malloc fails\n");
509         return -1;
510     }
511    
512     memcpy(new_dev->mac_addr, mac, 6);
513     new_dev->input = netif_input;
514     new_dev->private_data = priv_data;
515     new_dev->vm = vm;
516     new_dev->dev_id = 0;        
517
518     flags = v3_lock_irqsave(vnet_state.lock);
519
520     if (!find_dev_by_mac(mac)) {
521         list_add(&(new_dev->node), &(vnet_state.devs));
522         new_dev->dev_id = ++vnet_state.num_devs;
523     }
524
525     v3_unlock_irqrestore(vnet_state.lock, flags);
526
527     // if the device was found previosly the id should still be 0
528     if (new_dev->dev_id == 0) {
529         PrintError("Device Alrady exists\n");
530         return -1;
531     }
532
533     PrintDebug("Vnet: Add Device: dev_id %d, input : %p, private_data %p\n",
534                         new_dev->dev_id, new_dev->input, new_dev->private_data);
535
536     return new_dev->dev_id;
537 }
538
539
540 int v3_vnet_add_bridge(struct v3_vm_info * vm,
541                        int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data), 
542                        void * priv_data) {
543     unsigned long flags;
544     int bridge_free = 0;
545     struct vnet_brg_dev * tmp_bridge = NULL;
546     
547     
548     flags = v3_lock_irqsave(vnet_state.lock);
549
550     if (vnet_state.bridge == NULL) {
551         bridge_free = 1;
552         vnet_state.bridge = (void *)1;
553     }
554
555     v3_unlock_irqrestore(vnet_state.lock, flags);
556
557     if (bridge_free == 0) {
558         PrintError("Bridge already set\n");
559         return -1;
560     }
561
562     tmp_bridge = (struct vnet_brg_dev *)V3_Malloc(sizeof(struct vnet_brg_dev));
563
564     if (tmp_bridge == NULL) {
565         PrintError("Malloc Fails\n");
566         return -1;
567     }
568     
569     tmp_bridge->vm = vm;
570     tmp_bridge->input = input;
571     tmp_bridge->private_data = priv_data;
572
573     // make this atomic to avoid possible race conditions
574     flags = v3_lock_irqsave(vnet_state.lock);
575     vnet_state.bridge = tmp_bridge;
576     v3_unlock_irqrestore(vnet_state.lock, flags);
577
578     return 0;
579 }
580
581 int V3_init_vnet() {
582         
583     INIT_LIST_HEAD(&(vnet_state.routes));
584     INIT_LIST_HEAD(&(vnet_state.devs));
585
586     vnet_state.num_devs = 0;
587     vnet_state.num_routes = 0;
588
589     PrintDebug("VNET: Links and Routes tables initiated\n");
590
591     if (v3_lock_init(&(vnet_state.lock)) == -1){
592         PrintError("VNET: Failure to init lock for routes table\n");
593     }
594
595     PrintDebug("VNET: Locks initiated\n");
596
597     vnet_state.inpkt_q = v3_create_queue();
598     v3_init_queue(vnet_state.inpkt_q);
599     PrintDebug("VNET: Receiving queue initiated\n");
600
601     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
602
603     if (vnet_state.route_cache == NULL) {
604         PrintError("Vnet: Route Cache Init Fails\n");
605         return -1;
606     }
607
608     PrintDebug("VNET: initiated\n");
609
610     return 0;
611 }