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.


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