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.


dca5b7bb6668b7b61bddd4973abb4bbe1ad96687
[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     /* USE the hash table iterators. 
146      * See v3_swap_flush(struct v3_vm_info * vm) in vmm_shdw_pg_swapbypass.c
147      */
148
149     // MAKE SURE YOU DELETE the route_list entries
150     struct hashtable_iter * ht_iter = v3_create_htable_iter(vnet_state.route_cache);
151
152     if (!ht_iter) {
153         PrintError("NULL iterator in vnet cache!\n");
154     }
155
156     while (ht_iter->entry) {
157         struct route_list * route_list_ptr = (struct route_list *)v3_htable_get_iter_value(ht_iter);
158         V3_Free(route_list_ptr);
159         v3_htable_iter_advance(ht_iter);
160     }
161
162     V3_Free(ht_iter);
163
164     //v3_free_htable(vnet_state.route_cache, 0, 1);
165
166     return 0;
167 }
168
169 static int look_into_cache(struct v3_vnet_pkt * pkt, struct route_list ** routes) {
170     
171     *routes = (struct route_list *)v3_htable_search(vnet_state.route_cache, (addr_t)pkt);
172    
173     return 0;
174 }
175
176
177
178 int v3_vnet_add_route(struct v3_vnet_route route) {
179     struct vnet_route_info * new_route = NULL;
180     unsigned long flags; 
181
182     new_route = (struct vnet_route_info *)V3_Malloc(sizeof(struct vnet_route_info));
183     memset(new_route, 0, sizeof(struct vnet_route_info));
184
185     PrintDebug("Vnet: vnet_add_route_entry\n"); 
186     
187     new_route->route_def = route;
188
189     /* TODO: Find devices */
190     if (new_route->route_def.dst_type == LINK_INTERFACE) {
191         //new_route->dst_dev = FIND_DEV();
192     }
193
194     if (new_route->route_def.src_type == LINK_INTERFACE) {
195         // new_route->src_dev = FIND_DEV()
196     }
197
198     flags = v3_lock_irqsave(vnet_state.lock);
199     list_add(&(new_route->node), &(vnet_state.routes));
200     v3_unlock_irqrestore(vnet_state.lock, flags);
201    
202     clear_hash_cache();
203
204     return 0;
205 }
206
207
208
209 // At the end allocate a route_list
210 // This list will be inserted into the cache so we don't need to free it
211 static struct route_list * match_route(struct v3_vnet_pkt * pkt) {
212     struct vnet_route_info * route = NULL; 
213     struct route_list * matches = NULL;
214     int num_matches = 0;
215     int max_rank = 0;
216     struct list_head match_list;
217     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
218     uint8_t src_type = pkt->src_type;
219     uint32_t src_link = pkt->src_id;
220
221 #ifdef CONFIG_DEBUG_VNET
222     {
223         char dst_str[18];
224         char src_str[18];
225
226         mac_to_string(hdr->src_mac, src_str);  
227         mac_to_string(hdr->dst_mac, dst_str);
228         PrintDebug("Vnet: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
229     }
230 #endif
231
232     INIT_LIST_HEAD(&match_list);
233     
234 #define UPDATE_MATCHES(rank) do {                               \
235         if (max_rank < (rank)) {                                \
236             max_rank = (rank);                                  \
237             INIT_LIST_HEAD(&match_list);                        \
238                                                                 \
239             list_add(&(route->match_node), &match_list);        \
240             num_matches = 1;                                    \
241         } else if (max_rank == (rank)) {                        \
242             list_add(&(route->match_node), &match_list);        \
243             num_matches++;                                      \
244         }                                                       \
245     } while (0)
246     
247
248     list_for_each_entry(route, &(vnet_state.routes), node) {
249         struct v3_vnet_route * route_def = &(route->route_def);
250
251         // CHECK SOURCE TYPE HERE
252         if ( (route_def->src_type != LINK_ANY) && 
253              ( (route_def->src_type != src_type) || 
254                ( (route_def->src_id != src_link) &&
255                  (route_def->src_id != (uint32_t)-1)))) {
256             continue;
257         }
258
259
260         if ((route_def->dst_mac_qual == MAC_ANY) &&
261             (route_def->src_mac_qual == MAC_ANY)) {      
262             UPDATE_MATCHES(3);
263         }
264         
265         if (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) {
266             if (route_def->src_mac_qual != MAC_NOT) {
267                 if (route_def->dst_mac_qual == MAC_ANY) {
268                     UPDATE_MATCHES(6);
269                 } else if (route_def->dst_mac_qual != MAC_NOT &&
270                            memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
271                     UPDATE_MATCHES(8);
272                 }
273             }
274         }
275             
276         if (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0) {
277             if (route_def->dst_mac_qual != MAC_NOT) {
278                 if (route_def->src_mac_qual == MAC_ANY) {
279                     UPDATE_MATCHES(6);
280                 } else if ((route_def->src_mac_qual != MAC_NOT) && 
281                            (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {
282                     UPDATE_MATCHES(8);
283                 }
284             }
285         }
286             
287         if ((route_def->dst_mac_qual == MAC_NOT) &&
288             (memcmp(route_def->dst_mac, hdr->dst_mac, 6) != 0)) {
289             if (route_def->src_mac_qual == MAC_ANY) {
290                 UPDATE_MATCHES(5);
291             } else if ((route_def->src_mac_qual != MAC_NOT) && 
292                        (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0)) {     
293                 UPDATE_MATCHES(7);
294             }
295         }
296         
297         if ((route_def->src_mac_qual == MAC_NOT) &&
298             (memcmp(route_def->src_mac, hdr->src_mac, 6) != 0)) {
299             if (route_def->dst_mac_qual == MAC_ANY) {
300                 UPDATE_MATCHES(5);
301             } else if ((route_def->dst_mac_qual != MAC_NOT) &&
302                        (memcmp(route_def->dst_mac, hdr->dst_mac, 6) == 0)) {
303                 UPDATE_MATCHES(7);
304             }
305         }
306         
307         // Default route
308         if ( (memcmp(route_def->src_mac, hdr->src_mac, 6) == 0) &
309              (route_def->dst_mac_qual == MAC_NONE)) {
310             UPDATE_MATCHES(4);
311         }
312     }
313
314     PrintDebug("Vnet: match_route: Matches=%d\n", num_matches);
315
316     if (num_matches == 0) {
317         return NULL;
318     }
319
320     matches = V3_Malloc(sizeof(struct route_list) + 
321                         (sizeof(struct vnet_route_info *) * num_matches));
322
323     matches->num_routes = num_matches;
324
325     {
326         int i = 0;
327         list_for_each_entry(route, &match_list, node) {
328             matches->routes[i++] = route;
329         }
330     }
331
332     return matches;
333 }
334
335 static int handle_one_pkt(struct v3_vnet_pkt * pkt) {
336     struct route_list * matched_routes = NULL;
337     int i;
338
339
340 #ifdef CONFIG_DEBUG_VNET
341    {
342         struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
343         char dest_str[18];
344         char src_str[18];
345
346         mac_to_string(hdr->src_mac, src_str);  
347         mac_to_string(hdr->dst_mac, dest_str);
348         PrintDebug("Vnet: HandleDataOverLink. SRC(%s), DEST(%s)\n", src_str, dest_str);
349    }
350 #endif
351
352     look_into_cache(pkt, &matched_routes);
353     
354     if (matched_routes == NULL) {  
355         matched_routes = match_route(pkt);      
356
357       if (matched_routes) {
358             add_route_to_cache(pkt, matched_routes);      
359         } else {
360             PrintError("Could not find route for packet...\n");
361             return -1;
362         }
363     }
364     
365     
366     for (i = 0; i < matched_routes->num_routes; i++) {
367         struct vnet_route_info * route = matched_routes->routes[i];
368
369         if (route->route_def.dst_type == LINK_EDGE) {
370
371         } else if (route->route_def.dst_type == LINK_INTERFACE) {
372             if (route->dst_dev->input(route->dst_dev->vm, pkt, route->dst_dev->private_data) == -1) {
373                 PrintDebug("VNET: Packet not sent properly\n");
374                 continue;
375              }
376         } else {
377             PrintDebug("Vnet: Wrong Edge type\n");
378             continue;
379         }
380
381         PrintDebug("Vnet: HandleDataOverLink: Forward packet according to Route\n");
382     }
383     
384     return 0;
385 }
386
387 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt) {
388     // find the destination and call the send packet function, passing pkt *
389
390     if (handle_one_pkt(pkt) != -1) {
391         PrintDebug("VNET: send one packet! pt length %d\n", pkt->size);  
392     } else {
393         PrintDebug("VNET: Fail to forward one packet, discard it!\n"); 
394     }
395
396 #ifdef CONFIG_DEBUG_VNET
397     print_packet(pkt);
398 #endif
399
400     return 0;
401 }
402
403 struct vnet_dev * find_dev_by_id(int idx) {
404     struct vnet_dev * dev = NULL; 
405     
406     list_for_each_entry(dev, &(vnet_state.devs), node) {
407         int dev_id = dev->dev_id;
408
409         if (dev_id == idx)
410             return dev;
411     }
412
413     return NULL;
414 }
415
416 static struct vnet_dev * find_dev_by_mac(char * name) {
417     struct vnet_dev * dev = NULL; 
418     
419     list_for_each_entry(dev, &(vnet_state.devs), node) {
420         if (!memcmp(dev->mac_addr, name, 6))
421             return dev;
422     }
423
424     return NULL;
425 }
426
427 int v3_vnet_add_dev(struct v3_vm_info *vm,uint8_t mac[6], 
428                     int (*netif_input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data), 
429                     void * priv_data){
430     struct vnet_dev * new_dev = NULL;
431
432     new_dev = find_dev_by_mac(mac);
433
434     if (new_dev) {
435         PrintDebug("VNET: register device: Already has device with the same mac\n");
436         return -1;
437     }
438     
439     new_dev = (struct vnet_dev *)V3_Malloc(sizeof(struct vnet_dev)); 
440
441     if (new_dev == NULL) {
442         PrintError("VNET: Malloc fails\n");
443         return -1;
444     }
445     
446     memcpy(new_dev->mac_addr, mac, 6);
447     new_dev->input = netif_input;
448     new_dev->private_data = priv_data;
449     new_dev->vm = vm;
450
451     // ADD TO dev list
452     // increment dev count
453     
454     list_add(&(new_dev->node), &(vnet_state.devs));
455     vnet_state.num_devs ++;
456     new_dev->dev_id = vnet_state.num_devs;
457
458     return 0;
459 }
460
461 int v3_vnet_pkt_process() {
462     struct v3_vnet_pkt * pkt = NULL;
463
464     while ((pkt = (struct v3_vnet_pkt *)v3_dequeue(vnet_state.inpkt_q)) != NULL) {
465         if (handle_one_pkt(pkt) != -1) {
466             PrintDebug("VNET: vnet_check: handle one packet! pt length %d\n", (int)pkt->size);  
467         } else {
468             PrintDebug("VNET: vnet_check: Fail to forward one packet, discard it!\n"); 
469         }
470         
471         V3_Free(pkt); // be careful here
472     }
473     
474     return 0;
475 }
476
477
478 int V3_init_vnet() {
479
480     PrintDebug("VNET: Links table initiated\n");
481
482     INIT_LIST_HEAD(&(vnet_state.routes));
483     INIT_LIST_HEAD(&(vnet_state.devs));
484
485     vnet_state.num_devs = 0;
486     vnet_state.num_routes = 0;
487
488     if (v3_lock_init(&(vnet_state.lock)) == -1){
489         PrintError("VNET: Failure to init lock for routes table\n");
490     }
491
492     PrintDebug("VNET: Routes table initiated\n");
493
494     /*initial pkt receiving queue */
495     vnet_state.inpkt_q = v3_create_queue();
496     v3_init_queue(vnet_state.inpkt_q);
497     PrintDebug("VNET: Receiving queue initiated\n");
498
499     vnet_state.route_cache = v3_create_htable(0, &hash_fn, &hash_eq);
500
501     if (vnet_state.route_cache == NULL) {
502         PrintError("Vnet: Route Cache Init Fails\n");
503         return -1;
504     }
505
506     return 0;
507 }