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