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.


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