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.


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