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.


added cpuid masking
[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
50     uint64_t bytes_tx, bytes_rx;
51     uint32_t pkts_tx, pkt_rx;
52     
53     struct list_head node;
54 } __attribute__((packed));
55
56
57 struct vnet_brg_dev {
58     struct v3_vm_info * vm;
59     struct v3_vnet_bridge_ops brg_ops;
60
61     uint8_t type;
62
63     int active;
64     void * private_data;
65 } __attribute__((packed));
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 struct route_list {
81     uint8_t hash_buf[VNET_HASH_SIZE];
82
83     uint32_t num_routes;
84     struct vnet_route_info * routes[0];
85 } __attribute__((packed));
86
87
88 static struct {
89     struct list_head routes;
90     struct list_head devs;
91     
92     int num_routes;
93     int num_devs;
94
95     struct vnet_brg_dev * bridge;
96
97     v3_lock_t lock;
98     struct vnet_stat stats;
99
100     struct hashtable * route_cache;
101 } vnet_state;
102
103
104
105 #ifdef CONFIG_DEBUG_VNET
106 static inline void mac_to_string(uint8_t * mac, char * buf) {
107     snprintf(buf, 100, "%2x:%2x:%2x:%2x:%2x:%2x", 
108              mac[0], mac[1], mac[2],
109              mac[3], mac[4], mac[5]);
110 }
111
112 static void print_route(struct v3_vnet_route * route){
113     char str[50];
114
115     mac_to_string(route->src_mac, str);
116     PrintDebug("Src Mac (%s),  src_qual (%d)\n", 
117                str, route->src_mac_qual);
118     mac_to_string(route->dst_mac, str);
119     PrintDebug("Dst Mac (%s),  dst_qual (%d)\n", 
120                str, route->dst_mac_qual);
121     PrintDebug("Src dev id (%d), src type (%d)", 
122                route->src_id, 
123                route->src_type);
124     PrintDebug("Dst dev id (%d), dst type (%d)\n", 
125                route->dst_id, 
126                route->dst_type);
127 }
128
129 static void dump_routes(){
130     struct vnet_route_info *route;
131
132     int i = 0;
133     PrintDebug("\n========Dump routes starts ============\n");
134     list_for_each_entry(route, &(vnet_state.routes), node) {
135         PrintDebug("\nroute %d:\n", i++);
136                 
137         print_route(&(route->route_def));
138         if (route->route_def.dst_type == LINK_INTERFACE) {
139             PrintDebug("dst_dev (%p), dst_dev_id (%d), dst_dev_ops(%p), dst_dev_data (%p)\n",
140                 route->dst_dev,
141                 route->dst_dev->dev_id,
142                 (void *)&(route->dst_dev->dev_ops),
143                 route->dst_dev->private_data);
144         }
145     }
146
147     PrintDebug("\n========Dump routes end ============\n");
148 }
149
150 #endif
151
152
153 /* 
154  * A VNET packet is a packed struct with the hashed fields grouped together.
155  * This means we can generate the hash from an offset into the pkt struct
156  */
157 static inline uint_t hash_fn(addr_t hdr_ptr) {    
158     uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
159
160     return v3_hash_buffer(hdr_buf, VNET_HASH_SIZE);
161 }
162
163 static inline int hash_eq(addr_t key1, addr_t key2) {   
164     return (memcmp((uint8_t *)key1, (uint8_t *)key2, VNET_HASH_SIZE) == 0);
165 }
166
167 static int add_route_to_cache(const struct v3_vnet_pkt * pkt, struct route_list * routes) {
168     memcpy(routes->hash_buf, pkt->hash_buf, VNET_HASH_SIZE);    
169
170     if (v3_htable_insert(vnet_state.route_cache, (addr_t)routes->hash_buf, (addr_t)routes) == 0) {
171         PrintError("VNET/P Core: Failed to insert new route entry to the cache\n");
172         return -1;
173     }
174     
175     return 0;
176 }
177
178 static int clear_hash_cache() {
179     v3_free_htable(vnet_state.route_cache, 1, 1);
180     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
181
182     return 0;
183 }
184
185 static int look_into_cache(const struct v3_vnet_pkt * pkt, struct route_list ** routes) {
186     *routes = (struct route_list *)v3_htable_search(vnet_state.route_cache, (addr_t)(pkt->hash_buf));
187    
188     return 0;
189 }
190
191
192 static struct vnet_dev * dev_by_id(int idx) {
193     struct vnet_dev * dev = NULL; 
194
195     list_for_each_entry(dev, &(vnet_state.devs), node) {
196         int dev_id = dev->dev_id;
197
198         if (dev_id == idx)
199             return dev;
200     }
201
202     return NULL;
203 }
204
205 static struct vnet_dev * dev_by_mac(uint8_t * mac) {
206     struct vnet_dev * dev = NULL; 
207     
208     list_for_each_entry(dev, &(vnet_state.devs), node) {
209         if (!compare_ethaddr(dev->mac_addr, mac)){
210             return dev;
211         }
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     dev = dev_by_mac(mac);
222
223     if(dev != NULL) {
224         return dev->dev_id;
225     }
226
227     return -1;
228 }
229
230
231 int v3_vnet_add_route(struct v3_vnet_route route) {
232     struct vnet_route_info * new_route = NULL;
233     unsigned long flags; 
234
235     new_route = (struct vnet_route_info *)V3_Malloc(sizeof(struct vnet_route_info));
236     memset(new_route, 0, sizeof(struct vnet_route_info));
237
238 #ifdef CONFIG_DEBUG_VNET
239     PrintDebug("VNET/P Core: add_route_entry:\n");
240     print_route(&route);
241 #endif
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    }
440 #endif
441
442     flags = v3_lock_irqsave(vnet_state.lock);
443
444     vnet_state.stats.rx_bytes += pkt->size;
445     vnet_state.stats.rx_pkts++;
446
447     look_into_cache(pkt, &matched_routes);
448     if (matched_routes == NULL) {  
449         PrintDebug("VNET/P Core: send pkt Looking into routing table\n");
450         
451         matched_routes = match_route(pkt);
452         
453         if (matched_routes) {
454             add_route_to_cache(pkt, matched_routes);
455         } else {
456             PrintDebug("VNET/P Core: Could not find route for packet... discards packet\n");
457             v3_unlock_irqrestore(vnet_state.lock, flags);
458             return 0; /* do we return -1 here?*/
459         }
460     }
461
462     v3_unlock_irqrestore(vnet_state.lock, flags);
463
464     PrintDebug("VNET/P Core: send pkt route matches %d\n", matched_routes->num_routes);
465
466     for (i = 0; i < matched_routes->num_routes; i++) {
467         struct vnet_route_info * route = matched_routes->routes[i];
468         
469         if (route->route_def.dst_type == LINK_EDGE) {
470             struct vnet_brg_dev *bridge = vnet_state.bridge;
471             pkt->dst_type = LINK_EDGE;
472             pkt->dst_id = route->route_def.dst_id;
473
474             if (bridge == NULL || (bridge->active == 0)) {
475                 PrintDebug("VNET/P Core: No active bridge to sent data to\n");
476                  continue;
477             }
478
479             if(bridge->brg_ops.input(bridge->vm, pkt, bridge->private_data) < 0){
480                 PrintDebug("VNET/P Core: Packet not sent properly to bridge\n");
481                 continue;
482             }         
483             vnet_state.stats.tx_bytes += pkt->size;
484             vnet_state.stats.tx_pkts ++;
485         } else if (route->route_def.dst_type == LINK_INTERFACE) {
486             if (route->dst_dev == NULL || route->dst_dev->active == 0){
487                 PrintDebug("VNET/P Core: No active device to sent data to\n");
488                 continue;
489             }
490
491             if(route->dst_dev->dev_ops.input(route->dst_dev->vm, pkt, route->dst_dev->private_data) < 0) {
492                 PrintDebug("VNET/P Core: Packet not sent properly\n");
493                 continue;
494             }
495             vnet_state.stats.tx_bytes += pkt->size;
496             vnet_state.stats.tx_pkts ++;
497         } else {
498             PrintError("VNET/P Core: Wrong dst type\n");
499         }
500     }
501     
502     return 0;
503 }
504
505 int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, 
506                     struct v3_vnet_dev_ops *ops,
507                     void * priv_data){
508     struct vnet_dev * new_dev = NULL;
509     unsigned long flags;
510
511     new_dev = (struct vnet_dev *)V3_Malloc(sizeof(struct vnet_dev)); 
512
513     if (new_dev == NULL) {
514         PrintError("Malloc fails\n");
515         return -1;
516     }
517    
518     memcpy(new_dev->mac_addr, mac, 6);
519     new_dev->dev_ops.input = ops->input;
520     new_dev->dev_ops.poll = ops->poll;
521     new_dev->private_data = priv_data;
522     new_dev->vm = vm;
523     new_dev->dev_id = 0;
524     new_dev->active = 1;
525
526     flags = v3_lock_irqsave(vnet_state.lock);
527
528     if (dev_by_mac(mac) == NULL) {
529         list_add(&(new_dev->node), &(vnet_state.devs));
530         new_dev->dev_id = ++vnet_state.num_devs;
531     }
532
533     v3_unlock_irqrestore(vnet_state.lock, flags);
534
535     /* if the device was found previosly the id should still be 0 */
536     if (new_dev->dev_id == 0) {
537         PrintError("VNET/P Core: Device Already exists\n");
538         return -1;
539     }
540
541     PrintDebug("VNET/P Core: Add Device: dev_id %d\n", new_dev->dev_id);
542
543     return new_dev->dev_id;
544 }
545
546
547
548 int v3_vnet_del_dev(int dev_id){
549     struct vnet_dev * dev = NULL;
550     unsigned long flags;
551
552     flags = v3_lock_irqsave(vnet_state.lock);
553         
554     dev = dev_by_id(dev_id);
555     if (dev != NULL){
556         list_del(&(dev->node));
557         del_routes_by_dev(dev_id);
558     }
559         
560     v3_unlock_irqrestore(vnet_state.lock, flags);
561
562     V3_Free(dev);
563
564     PrintDebug("VNET/P Core: Remove Device: dev_id %d\n", dev_id);
565
566     return 0;
567 }
568
569 int v3_vnet_stat(struct vnet_stat * stats){
570         
571     stats->rx_bytes = vnet_state.stats.rx_bytes;
572     stats->rx_pkts = vnet_state.stats.rx_pkts;
573     stats->tx_bytes = vnet_state.stats.tx_bytes;
574     stats->tx_pkts = vnet_state.stats.tx_pkts;
575
576     return 0;
577 }
578
579 static void free_devices(){
580     struct vnet_dev * dev = NULL; 
581
582     list_for_each_entry(dev, &(vnet_state.devs), node) {
583         list_del(&(dev->node));
584         V3_Free(dev);
585     }
586 }
587
588 static void free_routes(){
589     struct vnet_route_info * route = NULL; 
590
591     list_for_each_entry(route, &(vnet_state.routes), node) {
592         list_del(&(route->node));
593         list_del(&(route->match_node));
594         V3_Free(route);
595     }
596 }
597
598 int v3_vnet_add_bridge(struct v3_vm_info * vm,
599                        struct v3_vnet_bridge_ops * ops,
600                        uint8_t type,
601                        void * priv_data) {
602     unsigned long flags;
603     int bridge_free = 0;
604     struct vnet_brg_dev * tmp_bridge = NULL;    
605     
606     flags = v3_lock_irqsave(vnet_state.lock);
607
608     if (vnet_state.bridge == NULL) {
609         bridge_free = 1;
610         vnet_state.bridge = (void *)1;
611     }
612
613     v3_unlock_irqrestore(vnet_state.lock, flags);
614
615     if (bridge_free == 0) {
616         PrintError("VNET/P Core: Bridge already set\n");
617         return -1;
618     }
619
620     tmp_bridge = (struct vnet_brg_dev *)V3_Malloc(sizeof(struct vnet_brg_dev));
621
622     if (tmp_bridge == NULL) {
623         PrintError("Malloc Fails\n");
624         vnet_state.bridge = NULL;
625         return -1;
626     }
627     
628     tmp_bridge->vm = vm;
629     tmp_bridge->brg_ops.input = ops->input;
630     tmp_bridge->brg_ops.poll = ops->poll;
631     tmp_bridge->private_data = priv_data;
632     tmp_bridge->active = 1;
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 void v3_vnet_do_poll(struct v3_vm_info * vm){
645     struct vnet_dev * dev = NULL;
646
647     /* TODO: run this on separate threads
648       * round-robin schedule, with maximal budget for each poll
649       */
650     list_for_each_entry(dev, &(vnet_state.devs), node) {
651             if(dev->dev_ops.poll != NULL){
652                 dev->dev_ops.poll(vm, -1, dev->private_data);
653             }
654     }
655 }
656
657
658 int v3_init_vnet() {
659     memset(&vnet_state, 0, sizeof(vnet_state));
660         
661     INIT_LIST_HEAD(&(vnet_state.routes));
662     INIT_LIST_HEAD(&(vnet_state.devs));
663
664     vnet_state.num_devs = 0;
665     vnet_state.num_routes = 0;
666
667     if (v3_lock_init(&(vnet_state.lock)) == -1){
668         PrintError("VNET/P Core: Fails to initiate lock\n");
669     }
670
671     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
672
673     if (vnet_state.route_cache == NULL) {
674         PrintError("VNET/P Core: Fails to initiate route cache\n");
675         return -1;
676     }
677
678     PrintDebug("VNET/P Core is initiated\n");
679
680     return 0;
681 }
682
683
684 void v3_deinit_vnet(){
685
686     v3_lock_deinit(&(vnet_state.lock));
687
688     free_devices();
689     free_routes();
690
691     v3_free_htable(vnet_state.route_cache, 1, 1);
692     V3_Free(vnet_state.bridge);
693 }
694
695