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.


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