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.


137c4d80892b33434f499f54a27d7910d2e72663
[palacios.git] / palacios / src / palacios / vmm_vnet.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) 2009, 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
34
35 struct eth_hdr {
36     uint8_t dst_mac[6];
37     uint8_t src_mac[6];
38     uint16_t type; // indicates layer 3 protocol type
39 } __attribute__((packed));
40
41
42
43
44
45 struct vnet_dev {
46
47     uint8_t mac_addr[6];
48     struct v3_vm_info * vm;
49     
50     int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt,  void * private_data);
51     void * private_data;
52     
53     int dev_id;
54     struct list_head node;
55 } __attribute__((packed));
56
57
58
59
60
61 struct vnet_route_info {
62     struct v3_vnet_route route_def;
63
64     struct vnet_dev * dst_dev;
65     struct vnet_dev * src_dev;
66
67     struct list_head node;
68     struct list_head match_node; // used for route matching
69 };
70
71
72
73
74 struct route_list {
75     uint8_t hash_buf[VNET_HASH_SIZE];
76
77     uint32_t num_routes;
78     struct vnet_route_info * routes[0];
79 } __attribute__((packed));
80
81
82
83 static struct {
84     struct list_head routes;
85     struct list_head devs;
86
87     int num_routes;
88     int num_devs;
89
90     v3_lock_t lock;
91
92     struct gen_queue * inpkt_q;
93     struct hashtable * route_cache;
94
95 } vnet_state;
96
97
98
99
100 #ifdef CONFIG_DEBUG_VNET
101
102 static void print_packet(struct v3_vnet_pkt * pkt) {
103     PrintDebug("Vnet: data_packet: size: %d\n", pkt->size);
104     v3_hexdump(pkt->data, pkt->size, NULL, 0);
105 }
106
107
108 static inline void mac_to_string(char mac[6], char * buf) {
109     snprintf(buf, 20, "%02x:%02x:%02x:%02x:%02x:%02x", 
110              mac[0], mac[1], mac[2],
111              mac[3], mac[4], mac[5]);
112 }
113
114 #endif
115
116
117 /* 
118  * A VNET packet is a packed struct with the hashed fields grouped together.
119  * This means we can generate the hash from an offset into the pkt struct
120  */
121 static inline uint_t hash_fn(addr_t hdr_ptr) {    
122     uint8_t * hdr_buf = (uint8_t *)&(hdr_ptr);
123     
124     return v3_hash_buffer(hdr_buf, VNET_HASH_SIZE);
125 }
126
127 static inline int hash_eq(addr_t key1, addr_t key2) {
128     return (memcmp((uint8_t *)key1, (uint8_t *)key2, VNET_HASH_SIZE) == 0);
129 }
130
131
132 static int add_route_to_cache(struct v3_vnet_pkt * pkt, struct route_list * routes) {
133     memcpy(routes->hash_buf, pkt->hash_buf, VNET_HASH_SIZE);    
134
135     if (v3_htable_insert(vnet_state.route_cache, (addr_t)routes->hash_buf, (addr_t)routes) == 0) {
136         PrintError("Vnet: Failed to insert new route entry to the cache\n");
137         return -1;
138     }
139     
140     return 0;
141 }
142
143 static int clear_hash_cache() {
144
145     v3_free_htable(vnet_state.route_cache, 1, 1);
146     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
147
148     return 0;
149 }
150
151 static int look_into_cache(struct v3_vnet_pkt * pkt, struct route_list ** routes) {
152     
153     *routes = (struct route_list *)v3_htable_search(vnet_state.route_cache, (addr_t)pkt);
154    
155     return 0;
156 }
157
158
159 struct vnet_dev * find_dev_by_id(int idx) {
160     struct vnet_dev * dev = NULL; 
161     
162     list_for_each_entry(dev, &(vnet_state.devs), node) {
163         int dev_id = dev->dev_id;
164
165         if (dev_id == idx)
166             return dev;
167     }
168
169     return NULL;
170 }
171
172 static struct vnet_dev * find_dev_by_mac(char * name) {
173     struct vnet_dev * dev = NULL; 
174     
175     list_for_each_entry(dev, &(vnet_state.devs), node) {
176         if (!memcmp(dev->mac_addr, name, 6))
177             return dev;
178     }
179
180     return NULL;
181 }
182
183
184 int v3_vnet_add_route(struct v3_vnet_route route) {
185     struct vnet_route_info * new_route = NULL;
186     unsigned long flags; 
187
188     new_route = (struct vnet_route_info *)V3_Malloc(sizeof(struct vnet_route_info));
189     memset(new_route, 0, sizeof(struct vnet_route_info));
190
191     PrintDebug("Vnet: vnet_add_route_entry\n"); 
192     
193     new_route->route_def = route;
194
195     /* TODO: Find devices */
196     if (new_route->route_def.dst_type == LINK_INTERFACE) {
197         new_route->dst_dev = find_dev_by_id(new_route->route_def.dst_id);
198     }
199
200     if (new_route->route_def.src_type == LINK_INTERFACE) {
201         new_route->src_dev = find_dev_by_id(new_route->route_def.src_id);
202     }
203
204     flags = v3_lock_irqsave(vnet_state.lock);
205     list_add(&(new_route->node), &(vnet_state.routes));
206     v3_unlock_irqrestore(vnet_state.lock, flags);
207    
208     clear_hash_cache();
209
210     return 0;
211 }
212
213
214
215 // At the end allocate a route_list
216 // This list will be inserted into the cache so we don't need to free it
217 static struct route_list * match_route(struct v3_vnet_pkt * pkt) {
218     struct vnet_route_info * route = NULL; 
219     struct route_list * matches = NULL;
220     int num_matches = 0;
221     int max_rank = 0;
222     struct list_head match_list;
223     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
224     uint8_t src_type = pkt->src_type;
225     uint32_t src_link = pkt->src_id;
226
227 #ifdef CONFIG_DEBUG_VNET
228     {
229         char dst_str[18];
230         char src_str[18];
231
232         mac_to_string(hdr->src_mac, src_str);  
233         mac_to_string(hdr->dst_mac, dst_str);
234         PrintDebug("Vnet: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
235     }
236 #endif
237
238     INIT_LIST_HEAD(&match_list);
239     
240 #define UPDATE_MATCHES(rank) do {                               \
241         if (max_rank < (rank)) {                                \
242             max_rank = (rank);                                  \
243             INIT_LIST_HEAD(&match_list);                        \
244                                                                 \
245             list_add(&(route->match_node), &match_list);        \
246             num_matches = 1;                                    \
247         } else if (max_rank == (rank)) {                        \
248             list_add(&(route->match_node), &match_list);        \
249             num_matches++;                                      \
250         }                                                       \
251     } while (0)
252     
253
254     list_for_each_entry(route, &(vnet_state.routes), node) {
255         struct v3_vnet_route * route_def = &(route->route_def);
256
257         // CHECK SOURCE TYPE HERE
258         if ( (route_def->src_type != LINK_ANY) && 
259              ( (route_def->src_type != src_type) || 
260                ( (route_def->src_id != src_link) &&
261                  (route_def->src_id != (uint32_t)-1)))) {
262             continue;
263         }
264
265
266         if ((route_def->dst_mac_qual == MAC_ANY) &&
267             (route_def->src_mac_qual == MAC_ANY)) {      
268             UPDATE_MATCHES(3);
269         }
270         
271         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
272             if (route_def->src_mac_qual != MAC_NOT) {
273                 if (route_def->dst_mac_qual == MAC_ANY) {
274                     UPDATE_MATCHES(6);
275                 } else if (route_def->dst_mac_qual != MAC_NOT &&
276                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
277                     UPDATE_MATCHES(8);
278                 }
279             }
280         }
281             
282         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
283             if (route_def->dst_mac_qual != MAC_NOT) {
284                 if (route_def->src_mac_qual == MAC_ANY) {
285                     UPDATE_MATCHES(6);
286                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
287                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
288                     UPDATE_MATCHES(8);
289                 }
290             }
291         }
292             
293         if ((route_def->dst_mac_qual == MAC_NOT) &&
294             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
295             if (route_def->src_mac_qual == MAC_ANY) {
296                 UPDATE_MATCHES(5);
297             } else if ((route_def->src_mac_qual != MAC_NOT) && 
298                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
299                 UPDATE_MATCHES(7);
300             }
301         }
302         
303         if ((route_def->src_mac_qual == MAC_NOT) &&
304             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
305             if (route_def->dst_mac_qual == MAC_ANY) {
306                 UPDATE_MATCHES(5);
307             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
308                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
309                 UPDATE_MATCHES(7);
310             }
311         }
312         
313         // Default route
314         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &
315              (route_def->dst_mac_qual == MAC_NONE)) {
316             UPDATE_MATCHES(4);
317         }
318     }
319
320     PrintDebug("Vnet: match_route: Matches=%d\n", num_matches);
321
322     if (num_matches == 0) {
323         return NULL;
324     }
325
326     matches = V3_Malloc(sizeof(struct route_list) + 
327                         (sizeof(struct vnet_route_info *) * num_matches));
328
329     matches->num_routes = num_matches;
330
331     {
332         int i = 0;
333         list_for_each_entry(route, &match_list, node) {
334             matches->routes[i++] = route;
335         }
336     }
337
338     return matches;
339 }
340
341 static int handle_one_pkt(struct v3_vnet_pkt * pkt) {
342     struct route_list * matched_routes = NULL;
343     unsigned long flags;
344     int i;
345
346
347 #ifdef CONFIG_DEBUG_VNET
348    {
349         struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
350         char dest_str[18];
351         char src_str[18];
352
353         mac_to_string(hdr->src_mac, src_str);  
354         mac_to_string(hdr->dst_mac, dest_str);
355         PrintDebug("Vnet: HandleDataOverLink. SRC(%s), DEST(%s)\n", src_str, dest_str);
356    }
357 #endif
358
359     flags = v3_lock_irqsave(vnet_state.lock);
360
361     look_into_cache(pkt, &matched_routes);
362         
363     if (matched_routes == NULL) {  
364         matched_routes = match_route(pkt);
365                 
366       if (matched_routes) {
367             add_route_to_cache(pkt, matched_routes);
368         } else {
369             PrintError("Could not find route for packet...\n");
370             return -1;
371         }
372     }
373
374     v3_unlock_irqrestore(vnet_state.lock, flags);
375     
376     
377     for (i = 0; i < matched_routes->num_routes; i++) {
378         struct vnet_route_info * route = matched_routes->routes[i];
379
380         if (route->route_def.dst_type == LINK_EDGE) {
381
382         } else if (route->route_def.dst_type == LINK_INTERFACE) {
383             if (route->dst_dev->input(route->dst_dev->vm, pkt, route->dst_dev->private_data) == -1) {
384                 PrintDebug("VNET: Packet not sent properly\n");
385                 continue;
386              }
387         } else {
388             PrintDebug("Vnet: Wrong Edge type\n");
389             continue;
390         }
391
392         PrintDebug("Vnet: HandleDataOverLink: Forward packet according to Route\n");
393     }
394     
395     return 0;
396 }
397
398 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt) {
399     // find the destination and call the send packet function, passing pkt *
400
401     if (handle_one_pkt(pkt) != -1) {
402         PrintDebug("VNET: send one packet! pt length %d\n", pkt->size);  
403     } else {
404         PrintDebug("VNET: Fail to forward one packet, discard it!\n"); 
405     }
406
407 #ifdef CONFIG_DEBUG_VNET
408     print_packet(pkt);
409 #endif
410
411     return 0;
412 }
413
414 int v3_vnet_add_dev(struct v3_vm_info *vm,uint8_t mac[6], 
415                     int (*netif_input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data), 
416                     void * priv_data){
417     struct vnet_dev * new_dev = NULL;
418
419     new_dev = find_dev_by_mac(mac);
420
421     if (new_dev) {
422         PrintDebug("VNET: register device: Already has device with the same mac\n");
423         return -1;
424     }
425     
426     new_dev = (struct vnet_dev *)V3_Malloc(sizeof(struct vnet_dev)); 
427
428     if (new_dev == NULL) {
429         PrintError("VNET: Malloc fails\n");
430         return -1;
431     }
432     
433     memcpy(new_dev->mac_addr, mac, 6);
434     new_dev->input = netif_input;
435     new_dev->private_data = priv_data;
436     new_dev->vm = vm;
437
438     // ADD TO dev list
439     // increment dev count
440     
441     list_add(&(new_dev->node), &(vnet_state.devs));
442     vnet_state.num_devs ++;
443     new_dev->dev_id = vnet_state.num_devs;
444
445     return 0;
446 }
447
448 int v3_vnet_pkt_process() {
449     struct v3_vnet_pkt * pkt = NULL;
450
451     while ((pkt = (struct v3_vnet_pkt *)v3_dequeue(vnet_state.inpkt_q)) != NULL) {
452         if (handle_one_pkt(pkt) != -1) {
453             PrintDebug("VNET: vnet_check: handle one packet! pt length %d\n", (int)pkt->size);  
454         } else {
455             PrintDebug("VNET: vnet_check: Fail to forward one packet, discard it!\n"); 
456         }
457         
458         V3_Free(pkt); // be careful here
459     }
460     
461     return 0;
462 }
463
464
465 int V3_init_vnet() {
466
467     PrintDebug("VNET: Links table initiated\n");
468
469     INIT_LIST_HEAD(&(vnet_state.routes));
470     INIT_LIST_HEAD(&(vnet_state.devs));
471
472     vnet_state.num_devs = 0;
473     vnet_state.num_routes = 0;
474
475     if (v3_lock_init(&(vnet_state.lock)) == -1){
476         PrintError("VNET: Failure to init lock for routes table\n");
477     }
478
479     PrintDebug("VNET: Routes table initiated\n");
480
481     /*initial pkt receiving queue */
482     vnet_state.inpkt_q = v3_create_queue();
483     v3_init_queue(vnet_state.inpkt_q);
484     PrintDebug("VNET: Receiving queue initiated\n");
485
486     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
487
488     if (vnet_state.route_cache == NULL) {
489         PrintError("Vnet: Route Cache Init Fails\n");
490         return -1;
491     }
492
493     return 0;
494 }