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.


6b86436a7bf1181e4a76c494be4818d7f1e214c2
[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     vnet_poll_type_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     vnet_poll_type_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     struct vnet_stat stats;
97
98     struct hashtable * route_cache;
99 } vnet_state;
100
101
102
103 #ifdef CONFIG_DEBUG_VNET
104 static inline void mac_to_string(uint8_t * mac, char * buf) {
105     snprintf(buf, 100, "%2x:%2x:%2x:%2x:%2x:%2x", 
106              mac[0], mac[1], mac[2],
107              mac[3], mac[4], mac[5]);
108 }
109
110 static void print_route(struct v3_vnet_route * route){
111     char str[50];
112
113     mac_to_string(route->src_mac, str);
114     PrintDebug("Src Mac (%s),  src_qual (%d)\n", 
115                str, route->src_mac_qual);
116     mac_to_string(route->dst_mac, str);
117     PrintDebug("Dst Mac (%s),  dst_qual (%d)\n", 
118                str, route->dst_mac_qual);
119     PrintDebug("Src dev id (%d), src type (%d)", 
120                route->src_id, 
121                route->src_type);
122     PrintDebug("Dst dev id (%d), dst type (%d)\n", 
123                route->dst_id, 
124                route->dst_type);
125 }
126
127 static void dump_routes(){
128     struct vnet_route_info *route;
129
130     int i = 0;
131     PrintDebug("\n========Dump routes starts ============\n");
132     list_for_each_entry(route, &(vnet_state.routes), node) {
133         PrintDebug("\nroute %d:\n", i++);
134                 
135         print_route(&(route->route_def));
136         if (route->route_def.dst_type == LINK_INTERFACE) {
137             PrintDebug("dst_dev (%p), dst_dev_id (%d), dst_dev_ops(%p), dst_dev_data (%p)\n",
138                 route->dst_dev,
139                 route->dst_dev->dev_id,
140                 (void *)&(route->dst_dev->dev_ops),
141                 route->dst_dev->private_data);
142         }
143     }
144
145     PrintDebug("\n========Dump routes end ============\n");
146 }
147
148 #endif
149
150
151 /* 
152  * A VNET packet is a packed struct with the hashed fields grouped together.
153  * This means we can generate the hash from an offset into the pkt struct
154  */
155 static inline uint_t hash_fn(addr_t hdr_ptr) {    
156     uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
157
158     return v3_hash_buffer(hdr_buf, VNET_HASH_SIZE);
159 }
160
161 static inline int hash_eq(addr_t key1, addr_t key2) {   
162     return (memcmp((uint8_t *)key1, (uint8_t *)key2, VNET_HASH_SIZE) == 0);
163 }
164
165 static int add_route_to_cache(const struct v3_vnet_pkt * pkt, struct route_list * routes) {
166     memcpy(routes->hash_buf, pkt->hash_buf, VNET_HASH_SIZE);    
167
168     if (v3_htable_insert(vnet_state.route_cache, (addr_t)routes->hash_buf, (addr_t)routes) == 0) {
169         PrintError("VNET/P Core: Failed to insert new route entry to the cache\n");
170         return -1;
171     }
172     
173     return 0;
174 }
175
176 static int clear_hash_cache() {
177     v3_free_htable(vnet_state.route_cache, 1, 1);
178     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
179
180     return 0;
181 }
182
183 static int look_into_cache(const struct v3_vnet_pkt * pkt, struct route_list ** routes) {
184     *routes = (struct route_list *)v3_htable_search(vnet_state.route_cache, (addr_t)(pkt->hash_buf));
185    
186     return 0;
187 }
188
189
190 static struct vnet_dev * dev_by_id(int idx) {
191     struct vnet_dev * dev = NULL; 
192
193     list_for_each_entry(dev, &(vnet_state.devs), node) {
194         int dev_id = dev->dev_id;
195
196         if (dev_id == idx)
197             return dev;
198     }
199
200     return NULL;
201 }
202
203 static struct vnet_dev * dev_by_mac(uint8_t * mac) {
204     struct vnet_dev * dev = NULL; 
205     
206     list_for_each_entry(dev, &(vnet_state.devs), node) {
207         if (!compare_ethaddr(dev->mac_addr, mac)){
208             return dev;
209         }
210     }
211
212     return NULL;
213 }
214
215
216 int v3_vnet_find_dev(uint8_t  * mac) {
217     struct vnet_dev * dev = NULL;
218
219     dev = dev_by_mac(mac);
220
221     if(dev != NULL) {
222         return dev->dev_id;
223     }
224
225     return -1;
226 }
227
228
229 int v3_vnet_add_route(struct v3_vnet_route route) {
230     struct vnet_route_info * new_route = NULL;
231     unsigned long flags; 
232
233     new_route = (struct vnet_route_info *)V3_Malloc(sizeof(struct vnet_route_info));
234     memset(new_route, 0, sizeof(struct vnet_route_info));
235
236 #ifdef CONFIG_DEBUG_VNET
237     PrintDebug("VNET/P Core: add_route_entry:\n");
238     print_route(&route);
239 #endif
240     
241     memcpy(new_route->route_def.src_mac, route.src_mac, ETH_ALEN);
242     memcpy(new_route->route_def.dst_mac, route.dst_mac, ETH_ALEN);
243     new_route->route_def.src_mac_qual = route.src_mac_qual;
244     new_route->route_def.dst_mac_qual = route.dst_mac_qual;
245     new_route->route_def.dst_type = route.dst_type;
246     new_route->route_def.src_type = route.src_type;
247     new_route->route_def.src_id = route.src_id;
248     new_route->route_def.dst_id = route.dst_id;
249
250     if (new_route->route_def.dst_type == LINK_INTERFACE) {
251         new_route->dst_dev = dev_by_id(new_route->route_def.dst_id);
252     }
253
254     if (new_route->route_def.src_type == LINK_INTERFACE) {
255         new_route->src_dev = dev_by_id(new_route->route_def.src_id);
256     }
257
258
259     flags = v3_lock_irqsave(vnet_state.lock);
260
261     list_add(&(new_route->node), &(vnet_state.routes));
262     clear_hash_cache();
263
264     v3_unlock_irqrestore(vnet_state.lock, flags);
265    
266
267 #ifdef CONFIG_DEBUG_VNET
268     dump_routes();
269 #endif
270
271     return 0;
272 }
273
274
275 /* delete all route entries with specfied src or dst device id */ 
276 static void inline del_routes_by_dev(int dev_id){
277     struct vnet_route_info * route = NULL;
278     unsigned long flags; 
279
280     flags = v3_lock_irqsave(vnet_state.lock);
281
282     list_for_each_entry(route, &(vnet_state.routes), node) {
283         if((route->route_def.dst_type == LINK_INTERFACE &&
284              route->route_def.dst_id == dev_id) ||
285              (route->route_def.src_type == LINK_INTERFACE &&
286               route->route_def.src_id == dev_id)){
287               
288             list_del(&(route->node));
289             list_del(&(route->match_node));
290             V3_Free(route);    
291         }
292     }
293
294     v3_unlock_irqrestore(vnet_state.lock, flags);
295 }
296
297 /* At the end allocate a route_list
298  * This list will be inserted into the cache so we don't need to free it
299  */
300 static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
301     struct vnet_route_info * route = NULL; 
302     struct route_list * matches = NULL;
303     int num_matches = 0;
304     int max_rank = 0;
305     struct list_head match_list;
306     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
307  //   uint8_t src_type = pkt->src_type;
308  //   uint32_t src_link = pkt->src_id;
309
310 #ifdef CONFIG_DEBUG_VNET
311     {
312         char dst_str[100];
313         char src_str[100];
314
315         mac_to_string(hdr->src_mac, src_str);  
316         mac_to_string(hdr->dst_mac, dst_str);
317         PrintDebug("VNET/P Core: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
318     }
319 #endif
320
321     INIT_LIST_HEAD(&match_list);
322     
323 #define UPDATE_MATCHES(rank) do {                               \
324         if (max_rank < (rank)) {                                \
325             max_rank = (rank);                                  \
326             INIT_LIST_HEAD(&match_list);                        \
327                                                                 \
328             list_add(&(route->match_node), &match_list);        \
329             num_matches = 1;                                    \
330         } else if (max_rank == (rank)) {                        \
331             list_add(&(route->match_node), &match_list);        \
332             num_matches++;                                      \
333         }                                                       \
334     } while (0)
335     
336
337     list_for_each_entry(route, &(vnet_state.routes), node) {
338         struct v3_vnet_route * route_def = &(route->route_def);
339
340 /*
341         // CHECK SOURCE TYPE HERE
342         if ( (route_def->src_type != LINK_ANY) && 
343              ( (route_def->src_type != src_type) || 
344                ( (route_def->src_id != src_link) &&
345                  (route_def->src_id != -1)))) {
346             continue;
347         }
348 */
349
350         if ((route_def->dst_mac_qual == MAC_ANY) &&
351             (route_def->src_mac_qual == MAC_ANY)) {      
352             UPDATE_MATCHES(3);
353         }
354         
355         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
356             if (route_def->src_mac_qual != MAC_NOT) {
357                 if (route_def->dst_mac_qual == MAC_ANY) {
358                     UPDATE_MATCHES(6);
359                 } else if (route_def->dst_mac_qual != MAC_NOT &&
360                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
361                     UPDATE_MATCHES(8);
362                 }
363             }
364         }
365             
366         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
367             if (route_def->dst_mac_qual != MAC_NOT) {
368                 if (route_def->src_mac_qual == MAC_ANY) {
369                     UPDATE_MATCHES(6);
370                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
371                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
372                     UPDATE_MATCHES(8);
373                 }
374             }
375         }
376             
377         if ((route_def->dst_mac_qual == MAC_NOT) &&
378             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
379             if (route_def->src_mac_qual == MAC_ANY) {
380                 UPDATE_MATCHES(5);
381             } else if ((route_def->src_mac_qual != MAC_NOT) && 
382                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
383                 UPDATE_MATCHES(7);
384             }
385         }
386         
387         if ((route_def->src_mac_qual == MAC_NOT) &&
388             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
389             if (route_def->dst_mac_qual == MAC_ANY) {
390                 UPDATE_MATCHES(5);
391             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
392                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
393                 UPDATE_MATCHES(7);
394             }
395         }
396         
397         // Default route
398         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &&
399              (route_def->dst_mac_qual == MAC_NONE)) {
400             UPDATE_MATCHES(4);
401         }
402     }
403
404     PrintDebug("VNET/P Core: match_route: Matches=%d\n", num_matches);
405
406     if (num_matches == 0) {
407         return NULL;
408     }
409
410     matches = (struct route_list *)V3_Malloc(sizeof(struct route_list) + 
411                                 (sizeof(struct vnet_route_info *) * num_matches));
412
413     matches->num_routes = num_matches;
414
415     {
416         int i = 0;
417         list_for_each_entry(route, &match_list, match_node) {
418             matches->routes[i++] = route;
419         }
420     }
421
422     return matches;
423 }
424
425
426 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
427     struct route_list * matched_routes = NULL;
428     unsigned long flags;
429     int i;
430
431 #ifdef CONFIG_DEBUG_VNET
432    {
433         int cpu = V3_Get_CPU();
434        PrintDebug("VNET/P Core: cpu %d: pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n",
435                   cpu, pkt->size, pkt->src_id, 
436                   pkt->src_type, pkt->dst_id, pkt->dst_type);
437        //v3_hexdump(pkt->data, pkt->size, NULL, 0);
438    }
439 #endif
440
441     flags = v3_lock_irqsave(vnet_state.lock);
442
443     vnet_state.stats.rx_bytes += pkt->size;
444     vnet_state.stats.rx_pkts++;
445
446     look_into_cache(pkt, &matched_routes);
447     if (matched_routes == NULL) {  
448         PrintDebug("VNET/P Core: send pkt Looking into routing table\n");
449         
450         matched_routes = match_route(pkt);
451         
452         if (matched_routes) {
453             add_route_to_cache(pkt, matched_routes);
454         } else {
455             PrintDebug("VNET/P Core: Could not find route for packet... discards packet\n");
456             v3_unlock_irqrestore(vnet_state.lock, flags);
457             return 0; /* do we return -1 here?*/
458         }
459     }
460
461     v3_unlock_irqrestore(vnet_state.lock, flags);
462
463     PrintDebug("VNET/P Core: send pkt route matches %d\n", matched_routes->num_routes);
464
465     for (i = 0; i < matched_routes->num_routes; i++) {
466         struct vnet_route_info * route = matched_routes->routes[i];
467         
468         if (route->route_def.dst_type == LINK_EDGE) {
469             struct vnet_brg_dev *bridge = vnet_state.bridge;
470             pkt->dst_type = LINK_EDGE;
471             pkt->dst_id = route->route_def.dst_id;
472
473             if (bridge == NULL || (bridge->active == 0)) {
474                 PrintDebug("VNET/P Core: No active bridge to sent data to\n");
475                  continue;
476             }
477
478             if(bridge->brg_ops.input(bridge->vm, pkt, bridge->private_data) < 0){
479                 PrintDebug("VNET/P Core: Packet not sent properly to bridge\n");
480                 continue;
481             }         
482             vnet_state.stats.tx_bytes += pkt->size;
483             vnet_state.stats.tx_pkts ++;
484         } else if (route->route_def.dst_type == LINK_INTERFACE) {
485             if (route->dst_dev == NULL || route->dst_dev->active == 0){
486                 PrintDebug("VNET/P Core: No active device to sent data to\n");
487                 continue;
488             }
489
490             if(route->dst_dev->dev_ops.input(route->dst_dev->vm, pkt, route->dst_dev->private_data) < 0) {
491                 PrintDebug("VNET/P Core: Packet not sent properly\n");
492                 continue;
493             }
494             vnet_state.stats.tx_bytes += pkt->size;
495             vnet_state.stats.tx_pkts ++;
496         } else {
497             PrintError("VNET/P Core: Wrong dst type\n");
498         }
499     }
500     
501     return 0;
502 }
503
504 int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, 
505                     struct v3_vnet_dev_ops *ops,
506                     void * priv_data){
507     struct vnet_dev * new_dev = NULL;
508     unsigned long flags;
509
510     new_dev = (struct vnet_dev *)V3_Malloc(sizeof(struct vnet_dev)); 
511
512     if (new_dev == NULL) {
513         PrintError("Malloc fails\n");
514         return -1;
515     }
516    
517     memcpy(new_dev->mac_addr, mac, 6);
518     new_dev->dev_ops.input = ops->input;
519     new_dev->dev_ops.poll = ops->poll;
520     new_dev->private_data = priv_data;
521     new_dev->vm = vm;
522     new_dev->dev_id = 0;
523     new_dev->active = 1;
524     new_dev->mode = GUEST_DRIVERN;
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->mode = GUEST_DRIVERN;
634     tmp_bridge->type = type;
635         
636     /* make this atomic to avoid possible race conditions */
637     flags = v3_lock_irqsave(vnet_state.lock);
638     vnet_state.bridge = tmp_bridge;
639     v3_unlock_irqrestore(vnet_state.lock, flags);
640
641     return 0;
642 }
643
644
645 int v3_init_vnet() {
646     memset(&vnet_state, 0, sizeof(vnet_state));
647         
648     INIT_LIST_HEAD(&(vnet_state.routes));
649     INIT_LIST_HEAD(&(vnet_state.devs));
650
651     vnet_state.num_devs = 0;
652     vnet_state.num_routes = 0;
653
654     if (v3_lock_init(&(vnet_state.lock)) == -1){
655         PrintError("VNET/P Core: Fails to initiate lock\n");
656     }
657
658     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
659
660     if (vnet_state.route_cache == NULL) {
661         PrintError("VNET/P Core: Fails to initiate route cache\n");
662         return -1;
663     }
664
665     PrintDebug("VNET/P Core is initiated\n");
666
667     return 0;
668 }
669
670
671 void v3_deinit_vnet(){
672
673     v3_lock_deinit(&(vnet_state.lock));
674
675     free_devices();
676     free_routes();
677
678     v3_free_htable(vnet_state.route_cache, 1, 1);
679     V3_Free(vnet_state.bridge);
680 }
681
682