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 VNET Linux backend code into Linux module directory
[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
211     return NULL;
212 }
213
214
215 int v3_vnet_find_dev(uint8_t  * mac) {
216     struct vnet_dev * dev = NULL;
217
218     dev = dev_by_mac(mac);
219
220     if(dev != NULL) {
221         return dev->dev_id;
222     }
223
224     return -1;
225 }
226
227
228 int v3_vnet_add_route(struct v3_vnet_route route) {
229     struct vnet_route_info * new_route = NULL;
230     unsigned long flags; 
231
232     new_route = (struct vnet_route_info *)V3_Malloc(sizeof(struct vnet_route_info));
233     memset(new_route, 0, sizeof(struct vnet_route_info));
234
235 #ifdef CONFIG_DEBUG_VNET
236     PrintDebug("VNET/P Core: add_route_entry:\n");
237     print_route(&route);
238 #endif
239     
240     memcpy(new_route->route_def.src_mac, route.src_mac, ETH_ALEN);
241     memcpy(new_route->route_def.dst_mac, route.dst_mac, ETH_ALEN);
242     new_route->route_def.src_mac_qual = route.src_mac_qual;
243     new_route->route_def.dst_mac_qual = route.dst_mac_qual;
244     new_route->route_def.dst_type = route.dst_type;
245     new_route->route_def.src_type = route.src_type;
246     new_route->route_def.src_id = route.src_id;
247     new_route->route_def.dst_id = route.dst_id;
248
249     if (new_route->route_def.dst_type == LINK_INTERFACE) {
250         new_route->dst_dev = dev_by_id(new_route->route_def.dst_id);
251     }
252
253     if (new_route->route_def.src_type == LINK_INTERFACE) {
254         new_route->src_dev = dev_by_id(new_route->route_def.src_id);
255     }
256
257
258     flags = v3_lock_irqsave(vnet_state.lock);
259
260     list_add(&(new_route->node), &(vnet_state.routes));
261     clear_hash_cache();
262
263     v3_unlock_irqrestore(vnet_state.lock, flags);
264    
265
266 #ifdef CONFIG_DEBUG_VNET
267     dump_routes();
268 #endif
269
270     return 0;
271 }
272
273
274 /* delete all route entries with specfied src or dst device id */ 
275 static void inline del_routes_by_dev(int dev_id){
276     struct vnet_route_info * route = NULL;
277     unsigned long flags; 
278
279     flags = v3_lock_irqsave(vnet_state.lock);
280
281     list_for_each_entry(route, &(vnet_state.routes), node) {
282         if((route->route_def.dst_type == LINK_INTERFACE &&
283              route->route_def.dst_id == dev_id) ||
284              (route->route_def.src_type == LINK_INTERFACE &&
285               route->route_def.src_id == dev_id)){
286               
287             list_del(&(route->node));
288             list_del(&(route->match_node));
289             V3_Free(route);    
290         }
291     }
292
293     v3_unlock_irqrestore(vnet_state.lock, flags);
294 }
295
296 /* At the end allocate a route_list
297  * This list will be inserted into the cache so we don't need to free it
298  */
299 static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
300     struct vnet_route_info * route = NULL; 
301     struct route_list * matches = NULL;
302     int num_matches = 0;
303     int max_rank = 0;
304     struct list_head match_list;
305     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
306  //   uint8_t src_type = pkt->src_type;
307  //   uint32_t src_link = pkt->src_id;
308
309 #ifdef CONFIG_DEBUG_VNET
310     {
311         char dst_str[100];
312         char src_str[100];
313
314         mac_to_string(hdr->src_mac, src_str);  
315         mac_to_string(hdr->dst_mac, dst_str);
316         PrintDebug("VNET/P Core: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
317     }
318 #endif
319
320     INIT_LIST_HEAD(&match_list);
321     
322 #define UPDATE_MATCHES(rank) do {                               \
323         if (max_rank < (rank)) {                                \
324             max_rank = (rank);                                  \
325             INIT_LIST_HEAD(&match_list);                        \
326                                                                 \
327             list_add(&(route->match_node), &match_list);        \
328             num_matches = 1;                                    \
329         } else if (max_rank == (rank)) {                        \
330             list_add(&(route->match_node), &match_list);        \
331             num_matches++;                                      \
332         }                                                       \
333     } while (0)
334     
335
336     list_for_each_entry(route, &(vnet_state.routes), node) {
337         struct v3_vnet_route * route_def = &(route->route_def);
338
339 /*
340         // CHECK SOURCE TYPE HERE
341         if ( (route_def->src_type != LINK_ANY) && 
342              ( (route_def->src_type != src_type) || 
343                ( (route_def->src_id != src_link) &&
344                  (route_def->src_id != -1)))) {
345             continue;
346         }
347 */
348
349         if ((route_def->dst_mac_qual == MAC_ANY) &&
350             (route_def->src_mac_qual == MAC_ANY)) {      
351             UPDATE_MATCHES(3);
352         }
353         
354         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
355             if (route_def->src_mac_qual != MAC_NOT) {
356                 if (route_def->dst_mac_qual == MAC_ANY) {
357                     UPDATE_MATCHES(6);
358                 } else if (route_def->dst_mac_qual != MAC_NOT &&
359                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
360                     UPDATE_MATCHES(8);
361                 }
362             }
363         }
364             
365         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
366             if (route_def->dst_mac_qual != MAC_NOT) {
367                 if (route_def->src_mac_qual == MAC_ANY) {
368                     UPDATE_MATCHES(6);
369                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
370                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
371                     UPDATE_MATCHES(8);
372                 }
373             }
374         }
375             
376         if ((route_def->dst_mac_qual == MAC_NOT) &&
377             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
378             if (route_def->src_mac_qual == MAC_ANY) {
379                 UPDATE_MATCHES(5);
380             } else if ((route_def->src_mac_qual != MAC_NOT) && 
381                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
382                 UPDATE_MATCHES(7);
383             }
384         }
385         
386         if ((route_def->src_mac_qual == MAC_NOT) &&
387             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
388             if (route_def->dst_mac_qual == MAC_ANY) {
389                 UPDATE_MATCHES(5);
390             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
391                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
392                 UPDATE_MATCHES(7);
393             }
394         }
395         
396         // Default route
397         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &&
398              (route_def->dst_mac_qual == MAC_NONE)) {
399             UPDATE_MATCHES(4);
400         }
401     }
402
403     PrintDebug("VNET/P Core: match_route: Matches=%d\n", num_matches);
404
405     if (num_matches == 0) {
406         return NULL;
407     }
408
409     matches = (struct route_list *)V3_Malloc(sizeof(struct route_list) + 
410                                 (sizeof(struct vnet_route_info *) * num_matches));
411
412     matches->num_routes = num_matches;
413
414     {
415         int i = 0;
416         list_for_each_entry(route, &match_list, match_node) {
417             matches->routes[i++] = route;
418         }
419     }
420
421     return matches;
422 }
423
424
425 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
426     struct route_list * matched_routes = NULL;
427     unsigned long flags;
428     int i;
429
430 #ifdef CONFIG_DEBUG_VNET
431    {
432         int cpu = V3_Get_CPU();
433        PrintDebug("VNET/P Core: cpu %d: pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n",
434                   cpu, pkt->size, pkt->src_id, 
435                   pkt->src_type, pkt->dst_id, pkt->dst_type);
436        //v3_hexdump(pkt->data, pkt->size, NULL, 0);
437    }
438 #endif
439
440     flags = v3_lock_irqsave(vnet_state.lock);
441
442     look_into_cache(pkt, &matched_routes);
443     if (matched_routes == NULL) {  
444         PrintDebug("VNET/P Core: send pkt Looking into routing table\n");
445         
446         matched_routes = match_route(pkt);
447         
448         if (matched_routes) {
449             add_route_to_cache(pkt, matched_routes);
450         } else {
451             PrintDebug("VNET/P Core: Could not find route for packet... discards packet\n");
452             v3_unlock_irqrestore(vnet_state.lock, flags);
453             return 0; /* do we return -1 here?*/
454         }
455     }
456
457     v3_unlock_irqrestore(vnet_state.lock, flags);
458
459     PrintDebug("VNET/P Core: send pkt route matches %d\n", matched_routes->num_routes);
460
461     for (i = 0; i < matched_routes->num_routes; i++) {
462         struct vnet_route_info * route = matched_routes->routes[i];
463         
464         if (route->route_def.dst_type == LINK_EDGE) {
465             struct vnet_brg_dev *bridge = vnet_state.bridge;
466             pkt->dst_type = LINK_EDGE;
467             pkt->dst_id = route->route_def.dst_id;
468
469             if (bridge == NULL || (bridge->active == 0)) {
470                 PrintDebug("VNET/P Core: No active bridge to sent data to\n");
471                  continue;
472             }
473
474             if(bridge->brg_ops.input(bridge->vm, pkt, bridge->private_data) < 0){
475                 PrintDebug("VNET/P Core: Packet not sent properly to bridge\n");
476                 continue;
477             }         
478         } else if (route->route_def.dst_type == LINK_INTERFACE) {
479             if (route->dst_dev == NULL || route->dst_dev->active == 0){
480                 PrintDebug("VNET/P Core: No active device to sent data to\n");
481                 continue;
482             }
483
484             if(route->dst_dev->dev_ops.input(route->dst_dev->vm, pkt, route->dst_dev->private_data) < 0) {
485                 PrintDebug("VNET/P Core: Packet not sent properly\n");
486                 continue;
487             }
488         } else {
489             PrintError("VNET/P Core: Wrong dst type\n");
490         }
491     }
492     
493     return 0;
494 }
495
496 int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, 
497                     struct v3_vnet_dev_ops *ops,
498                     void * priv_data){
499     struct vnet_dev * new_dev = NULL;
500     unsigned long flags;
501
502     new_dev = (struct vnet_dev *)V3_Malloc(sizeof(struct vnet_dev)); 
503
504     if (new_dev == NULL) {
505         PrintError("Malloc fails\n");
506         return -1;
507     }
508    
509     memcpy(new_dev->mac_addr, mac, 6);
510     new_dev->dev_ops.input = ops->input;
511     new_dev->dev_ops.poll = ops->poll;
512     new_dev->private_data = priv_data;
513     new_dev->vm = vm;
514     new_dev->dev_id = 0;
515     new_dev->active = 1;
516     new_dev->mode = GUEST_DRIVERN;
517
518     flags = v3_lock_irqsave(vnet_state.lock);
519
520     if (dev_by_mac(mac) == NULL) {
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("VNET/P Core: Device Already exists\n");
530         return -1;
531     }
532
533     PrintDebug("VNET/P Core: Add Device: dev_id %d\n", new_dev->dev_id);
534
535     return new_dev->dev_id;
536 }
537
538
539
540 int v3_vnet_del_dev(int dev_id){
541     struct vnet_dev * dev = NULL;
542     unsigned long flags;
543
544     flags = v3_lock_irqsave(vnet_state.lock);
545         
546     dev = dev_by_id(dev_id);
547     if (dev != NULL){
548         list_del(&(dev->node));
549         del_routes_by_dev(dev_id);
550     }
551         
552     v3_unlock_irqrestore(vnet_state.lock, flags);
553
554     V3_Free(dev);
555
556     PrintDebug("VNET/P Core: Remove Device: dev_id %d\n", dev_id);
557
558     return 0;
559 }
560
561
562 static void free_devices(){
563     struct vnet_dev * dev = NULL; 
564
565     list_for_each_entry(dev, &(vnet_state.devs), node) {
566         list_del(&(dev->node));
567         V3_Free(dev);
568     }
569 }
570
571 static void free_routes(){
572     struct vnet_route_info * route = NULL; 
573
574     list_for_each_entry(route, &(vnet_state.routes), node) {
575         list_del(&(route->node));
576         list_del(&(route->match_node));
577         V3_Free(route);
578     }
579 }
580
581 int v3_vnet_add_bridge(struct v3_vm_info * vm,
582                        struct v3_vnet_bridge_ops * ops,
583                        uint8_t type,
584                        void * priv_data) {
585     unsigned long flags;
586     int bridge_free = 0;
587     struct vnet_brg_dev * tmp_bridge = NULL;    
588     
589     flags = v3_lock_irqsave(vnet_state.lock);
590
591     if (vnet_state.bridge == NULL) {
592         bridge_free = 1;
593         vnet_state.bridge = (void *)1;
594     }
595
596     v3_unlock_irqrestore(vnet_state.lock, flags);
597
598     if (bridge_free == 0) {
599         PrintError("VNET/P Core: Bridge already set\n");
600         return -1;
601     }
602
603     tmp_bridge = (struct vnet_brg_dev *)V3_Malloc(sizeof(struct vnet_brg_dev));
604
605     if (tmp_bridge == NULL) {
606         PrintError("Malloc Fails\n");
607         vnet_state.bridge = NULL;
608         return -1;
609     }
610     
611     tmp_bridge->vm = vm;
612     tmp_bridge->brg_ops.input = ops->input;
613     tmp_bridge->brg_ops.poll = ops->poll;
614     tmp_bridge->private_data = priv_data;
615     tmp_bridge->active = 1;
616     tmp_bridge->mode = GUEST_DRIVERN;
617     tmp_bridge->type = type;
618         
619     /* make this atomic to avoid possible race conditions */
620     flags = v3_lock_irqsave(vnet_state.lock);
621     vnet_state.bridge = tmp_bridge;
622     v3_unlock_irqrestore(vnet_state.lock, flags);
623
624     return 0;
625 }
626
627
628 int v3_init_vnet() {
629     memset(&vnet_state, 0, sizeof(vnet_state));
630         
631     INIT_LIST_HEAD(&(vnet_state.routes));
632     INIT_LIST_HEAD(&(vnet_state.devs));
633
634     vnet_state.num_devs = 0;
635     vnet_state.num_routes = 0;
636
637     if (v3_lock_init(&(vnet_state.lock)) == -1){
638         PrintError("VNET/P Core: Fails to initiate lock\n");
639     }
640
641     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
642
643     if (vnet_state.route_cache == NULL) {
644         PrintError("VNET/P Core: Fails to initiate route cache\n");
645         return -1;
646     }
647
648     PrintDebug("VNET/P Core is initiated\n");
649
650     return 0;
651 }
652
653
654 void v3_deinit_vnet(){
655
656     v3_lock_deinit(&(vnet_state.lock));
657
658     free_devices();
659     free_routes();
660
661     v3_free_htable(vnet_state.route_cache, 1, 1);
662     V3_Free(vnet_state.bridge);
663 }
664
665