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