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.


VNET code clean and rearrangement
[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
268 /* At the end allocate a route_list
269  * This list will be inserted into the cache so we don't need to free it
270  */
271 static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
272     struct vnet_route_info * route = NULL; 
273     struct route_list * matches = NULL;
274     int num_matches = 0;
275     int max_rank = 0;
276     struct list_head match_list;
277     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
278     uint8_t src_type = pkt->src_type;
279     uint32_t src_link = pkt->src_id;
280
281 #ifdef CONFIG_DEBUG_VNET
282     {
283         char dst_str[100];
284         char src_str[100];
285
286         mac_to_string(hdr->src_mac, src_str);  
287         mac_to_string(hdr->dst_mac, dst_str);
288         PrintDebug("Vnet: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
289     }
290 #endif
291
292     INIT_LIST_HEAD(&match_list);
293     
294 #define UPDATE_MATCHES(rank) do {                               \
295         if (max_rank < (rank)) {                                \
296             max_rank = (rank);                                  \
297             INIT_LIST_HEAD(&match_list);                        \
298                                                                 \
299             list_add(&(route->match_node), &match_list);        \
300             num_matches = 1;                                    \
301         } else if (max_rank == (rank)) {                        \
302             list_add(&(route->match_node), &match_list);        \
303             num_matches++;                                      \
304         }                                                       \
305     } while (0)
306     
307
308     list_for_each_entry(route, &(vnet_state.routes), node) {
309         struct v3_vnet_route * route_def = &(route->route_def);
310
311         // CHECK SOURCE TYPE HERE
312         if ( (route_def->src_type != LINK_ANY) && 
313              ( (route_def->src_type != src_type) || 
314                ( (route_def->src_id != src_link) &&
315                  (route_def->src_id != (uint32_t)-1)))) {
316             continue;
317         }
318
319
320         if ((route_def->dst_mac_qual == MAC_ANY) &&
321             (route_def->src_mac_qual == MAC_ANY)) {      
322             UPDATE_MATCHES(3);
323         }
324         
325         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
326             if (route_def->src_mac_qual != MAC_NOT) {
327                 if (route_def->dst_mac_qual == MAC_ANY) {
328                     UPDATE_MATCHES(6);
329                 } else if (route_def->dst_mac_qual != MAC_NOT &&
330                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
331                     UPDATE_MATCHES(8);
332                 }
333             }
334         }
335             
336         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
337             if (route_def->dst_mac_qual != MAC_NOT) {
338                 if (route_def->src_mac_qual == MAC_ANY) {
339                     UPDATE_MATCHES(6);
340                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
341                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
342                     UPDATE_MATCHES(8);
343                 }
344             }
345         }
346             
347         if ((route_def->dst_mac_qual == MAC_NOT) &&
348             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
349             if (route_def->src_mac_qual == MAC_ANY) {
350                 UPDATE_MATCHES(5);
351             } else if ((route_def->src_mac_qual != MAC_NOT) && 
352                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
353                 UPDATE_MATCHES(7);
354             }
355         }
356         
357         if ((route_def->src_mac_qual == MAC_NOT) &&
358             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
359             if (route_def->dst_mac_qual == MAC_ANY) {
360                 UPDATE_MATCHES(5);
361             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
362                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
363                 UPDATE_MATCHES(7);
364             }
365         }
366         
367         // Default route
368         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &&
369              (route_def->dst_mac_qual == MAC_NONE)) {
370             UPDATE_MATCHES(4);
371         }
372     }
373
374     PrintDebug("Vnet: match_route: Matches=%d\n", num_matches);
375
376     if (num_matches == 0) {
377         return NULL;
378     }
379
380     matches = (struct route_list *)V3_Malloc(sizeof(struct route_list) + 
381                                 (sizeof(struct vnet_route_info *) * num_matches));
382
383     matches->num_routes = num_matches;
384
385     {
386         int i = 0;
387         list_for_each_entry(route, &match_list, match_node) {
388             matches->routes[i++] = route;
389         }
390     }
391
392     return matches;
393 }
394
395
396 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
397     struct route_list * matched_routes = NULL;
398     unsigned long flags;
399     int i;
400
401 #ifdef CONFIG_DEBUG_VNET
402    {
403         struct eth_hdr * hdr = (struct eth_hdr *)(pkt->header);
404         char dest_str[100];
405         char src_str[100];
406
407         mac_to_string(hdr->src_mac, src_str);  
408         mac_to_string(hdr->dst_mac, dest_str);
409         int cpu = V3_Get_CPU();
410         PrintDebug("Vnet: on cpu %d, HandleDataOverLink. SRC(%s), DEST(%s), pkt size: %d\n", cpu, src_str, dest_str, pkt->size);
411    }
412 #endif
413
414     flags = v3_lock_irqsave(vnet_state.lock);
415
416     look_into_cache(pkt, &matched_routes);
417         
418     if (matched_routes == NULL) {  
419         PrintError("Vnet: send pkt Looking into routing table\n");
420         
421         matched_routes = match_route(pkt);
422         
423         if (matched_routes) {
424             add_route_to_cache(pkt, matched_routes);
425         } else {
426             PrintDebug("Could not find route for packet... discards packet\n");
427             v3_unlock_irqrestore(vnet_state.lock, flags);
428             return 0; /* do we return -1 here?*/
429         }
430     }
431
432     v3_unlock_irqrestore(vnet_state.lock, flags);
433
434     PrintDebug("Vnet: send pkt route matches %d\n", matched_routes->num_routes);
435
436     for (i = 0; i < matched_routes->num_routes; i++) {
437          struct vnet_route_info * route = matched_routes->routes[i];
438         
439         if (route->route_def.dst_type == LINK_EDGE) {
440              struct vnet_brg_dev *bridge = vnet_state.bridge;
441             pkt->dst_type = LINK_EDGE;
442             pkt->dst_id = route->route_def.dst_id;
443
444              if (bridge == NULL || (bridge->active == 0)) {
445                 PrintError("VNET: No active bridge to sent data to links\n");
446                 continue;
447              }
448
449              if(bridge->brg_ops.input(bridge->vm, pkt, bridge->private_data) == -1){
450                 PrintDebug("VNET: Packet not sent properly to bridge\n");
451                 continue;
452              }         
453         } else if (route->route_def.dst_type == LINK_INTERFACE) {
454             if (route->dst_dev && route->dst_dev->active){ 
455                   if(route->dst_dev->dev_ops.input(route->dst_dev->vm, pkt, route->dst_dev->private_data) == -1) {
456                         PrintDebug("VNET: Packet not sent properly\n");
457                         continue;
458                   }
459              }
460         } else {
461             PrintError("VNET: Wrong dst type\n");
462         }
463
464         PrintDebug("VNET: Forward one packet according to Route %d\n", i);
465     }
466     
467     return 0;
468 }
469
470 int v3_vnet_add_dev(struct v3_vm_info *vm, uint8_t mac[6], 
471                     struct v3_vnet_dev_ops *ops,
472                     void * priv_data){
473     struct vnet_dev * new_dev = NULL;
474     unsigned long flags;
475
476     new_dev = (struct vnet_dev *)V3_Malloc(sizeof(struct vnet_dev)); 
477
478     if (new_dev == NULL) {
479         PrintError("VNET: Malloc fails\n");
480         return -1;
481     }
482    
483     memcpy(new_dev->mac_addr, mac, 6);
484     new_dev->dev_ops.input = ops->input;
485     new_dev->dev_ops.poll = ops->poll;
486     new_dev->private_data = priv_data;
487     new_dev->vm = vm;
488     new_dev->dev_id = 0;        
489
490     flags = v3_lock_irqsave(vnet_state.lock);
491
492     if (!find_dev_by_mac(mac)) {
493         list_add(&(new_dev->node), &(vnet_state.devs));
494         new_dev->dev_id = ++vnet_state.num_devs;
495     }
496
497     v3_unlock_irqrestore(vnet_state.lock, flags);
498
499     /* if the device was found previosly the id should still be 0 */
500     if (new_dev->dev_id == 0) {
501         PrintError("Device Alrady exists\n");
502         return -1;
503     }
504
505     PrintDebug("Vnet: Add Device: dev_id %d\n", new_dev->dev_id);
506
507     return new_dev->dev_id;
508 }
509
510
511 void  v3_vnet_poll(struct v3_vm_info * vm){
512     struct vnet_dev * dev = NULL; 
513     struct vnet_brg_dev *bridge = vnet_state.bridge;
514
515     list_for_each_entry(dev, &(vnet_state.devs), node) {
516         if(dev->mode == VMM_DRIVERN && 
517             dev->active && 
518             dev->vm == vm){
519             
520             dev->dev_ops.poll(vm, dev->private_data);
521         }
522     }
523
524     if (bridge != NULL && 
525           bridge->active && 
526           bridge->mode == VMM_DRIVERN) {
527         
528         bridge->brg_ops.poll(bridge->vm, bridge->private_data);
529     }
530         
531 }
532
533 int v3_vnet_add_bridge(struct v3_vm_info * vm,
534                        struct v3_vnet_bridge_ops * ops,
535                        uint8_t type,
536                        void * priv_data) {
537     unsigned long flags;
538     int bridge_free = 0;
539     struct vnet_brg_dev * tmp_bridge = NULL;    
540     
541     flags = v3_lock_irqsave(vnet_state.lock);
542
543     if (vnet_state.bridge == NULL) {
544         bridge_free = 1;
545         vnet_state.bridge = (void *)1;
546     }
547
548     v3_unlock_irqrestore(vnet_state.lock, flags);
549
550     if (bridge_free == 0) {
551         PrintError("Bridge already set\n");
552         return -1;
553     }
554
555     tmp_bridge = (struct vnet_brg_dev *)V3_Malloc(sizeof(struct vnet_brg_dev));
556
557     if (tmp_bridge == NULL) {
558         PrintError("Malloc Fails\n");
559         vnet_state.bridge = NULL;
560         return -1;
561     }
562     
563     tmp_bridge->vm = vm;
564     tmp_bridge->brg_ops.input = ops->input;
565     tmp_bridge->brg_ops.poll = ops->poll;
566     tmp_bridge->private_data = priv_data;
567     tmp_bridge->active = 1;
568     tmp_bridge->mode = GUEST_DRIVERN;
569     tmp_bridge->type = type;
570         
571     /* make this atomic to avoid possible race conditions */
572     flags = v3_lock_irqsave(vnet_state.lock);
573     vnet_state.bridge = tmp_bridge;
574     v3_unlock_irqrestore(vnet_state.lock, flags);
575
576     return 0;
577 }
578
579
580 int v3_init_vnet() {
581     memset(&vnet_state, 0, sizeof(vnet_state));
582         
583     INIT_LIST_HEAD(&(vnet_state.routes));
584     INIT_LIST_HEAD(&(vnet_state.devs));
585
586     vnet_state.num_devs = 0;
587     vnet_state.num_routes = 0;
588
589     PrintDebug("VNET: Links and Routes tables initiated\n");
590
591     if (v3_lock_init(&(vnet_state.lock)) == -1){
592         PrintError("VNET: Failure to init lock for routes table\n");
593     }
594     PrintDebug("VNET: Locks initiated\n");
595
596     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
597
598     if (vnet_state.route_cache == NULL) {
599         PrintError("Vnet: Route Cache Init Fails\n");
600         return -1;
601     }
602
603     PrintDebug("VNET: initiated\n");
604
605     return 0;
606 }