ia64/xen-unstable

view tools/vnet/vnet-module/vnet.c @ 17838:e5c9c8e6e726

tools: replace sprintf with snprintf where applicable

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 12 15:41:15 2008 +0100 (2008-06-12)
parents aedc55daf92b
children
line source
1 /*
2 * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free software Foundation, Inc.,
16 * 59 Temple Place, suite 330, Boston, MA 02111-1307 USA
17 *
18 */
20 #ifdef __KERNEL__
21 #include <linux/config.h>
22 #include <linux/module.h>
23 #include <linux/types.h>
24 #include <linux/kernel.h>
25 #include <linux/version.h>
26 #include <linux/errno.h>
28 #include <linux/string.h>
29 #include <linux/spinlock.h>
31 #include <linux/net.h>
32 #include <linux/in.h>
33 #include <linux/inet.h>
34 #include <linux/netdevice.h>
36 #include <linux/etherdevice.h>
37 #include <net/ip.h>
38 #include <net/protocol.h>
39 #include <net/route.h>
40 #include <linux/skbuff.h>
41 #include <net/checksum.h>
44 #else
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
49 #include "sys_kernel.h"
50 #include "spinlock.h"
51 #include "skbuff.h"
53 #include <linux/ip.h> // For struct iphdr.
55 extern int netif_rx(struct sk_buff *skb);
57 #endif
59 #include <tunnel.h>
60 #include <sa.h>
61 #include <varp.h>
62 #include <if_varp.h>
63 #include <esp.h>
64 #include <etherip.h>
65 #include <random.h>
67 #include <skb_context.h>
69 #include <skb_util.h>
70 #include <vnet_dev.h>
71 #include <vnet.h>
72 #include <vnet_forward.h>
73 #include <vif.h>
74 #include <vnet_ioctl.h>
75 #include <sa.h>
76 #ifdef __KERNEL__
77 #include <sa_algorithm.h>
78 #endif
80 #include "allocate.h"
81 #include "iostream.h"
82 #include "hash_table.h"
83 #include "sys_net.h"
84 #include "sys_string.h"
86 #define MODULE_NAME "VNET"
87 #define DEBUG 1
88 #undef DEBUG
89 #include "debug.h"
91 /** Default vnet security level.
92 */
93 int vnet_security_default = SA_AUTH ; //| SA_CONF;
95 /** The physical vnet. */
96 Vnet *vnet_physical = NULL;
98 /** Table of vnets indexed by id. */
99 HashTable *vnet_table = NULL;
101 rwlock_t vnet_lock = RW_LOCK_UNLOCKED;
103 #define vnet_table_read_lock(flags) read_lock_irqsave(&vnet_lock, flags)
104 #define vnet_table_read_unlock(flags) read_unlock_irqrestore(&vnet_lock, flags)
105 #define vnet_table_write_lock(flags) write_lock_irqsave(&vnet_lock, flags)
106 #define vnet_table_write_unlock(flags) write_unlock_irqrestore(&vnet_lock, flags)
108 /** Decrement reference count, freeing if zero.
109 *
110 * @param info vnet (OK if null)
111 */
112 void Vnet_decref(Vnet *info){
113 if(!info) return;
114 if(atomic_dec_and_test(&info->refcount)){
115 deallocate(info);
116 }
117 }
119 /** Increment reference count.
120 *
121 * @param info vnet (OK if null)
122 */
123 void Vnet_incref(Vnet *info){
124 if(!info) return;
125 atomic_inc(&info->refcount);
126 }
128 void Vnet_print(Vnet *info, IOStream *io)
129 {
130 char vnetbuf[VNET_ID_BUF];
131 char *security;
133 if(info->security & SA_CONF){
134 security = "conf";
135 } else if(info->security & SA_AUTH){
136 security = "auth";
137 } else {
138 security = "none";
139 }
141 IOStream_print(io, "(vnet");
142 IOStream_print(io, " (id %s)", VnetId_ntoa(&info->vnet, vnetbuf));
143 IOStream_print(io, " (vnetif %s)", info->device);
144 IOStream_print(io, " (security %s)", security);
145 IOStream_print(io, " (header %d)", info->header_n);
146 IOStream_print(io, ")");
147 }
149 void vnet_print(IOStream *io)
150 {
151 HashTable_for_decl(entry);
152 Vnet *info;
153 unsigned long flags;
155 vnet_table_read_lock(flags);
156 HashTable_for_each(entry, vnet_table){
157 info = entry->value;
158 Vnet_print(info, io);
159 IOStream_print(io, "\n");
160 }
161 vnet_table_read_unlock(flags);
162 }
164 /** Allocate a vnet, setting reference count to 1.
165 *
166 * @param info return parameter for vnet
167 * @return 0 on success, error code otherwise
168 */
169 int Vnet_alloc(Vnet **info){
170 int err = 0;
171 *info = ALLOCATE(Vnet);
172 if(*info){
173 atomic_set(&(*info)->refcount, 1);
174 } else {
175 err = -ENOMEM;
176 }
177 return err;
178 }
180 /** Create the virtual interface for a vnet.
181 *
182 * @param info vnet
183 * @return 0 on success, error code otherwise
184 */
185 int Vnet_create(Vnet *info){
186 int err = 0;
188 err = vnet_dev_add(info);
189 if(err) goto exit;
190 err = Vnet_add(info);
191 exit:
192 return err;
193 }
195 /** Add a vnet to the table under its vnet id.
196 *
197 * @param info vnet to add
198 * @return 0 on success, error code otherwise
199 */
200 int Vnet_add(Vnet *info){
201 int err = 0;
202 HTEntry *entry = NULL;
203 unsigned long flags;
205 if(Vnet_lookup(&info->vnet, NULL) == 0){
206 //todo: Delete existing vnet info?
207 err = -EEXIST;
208 goto exit;
209 }
210 Vnet_incref(info);
211 vnet_table_write_lock(flags);
212 entry = HashTable_add(vnet_table, &info->vnet, info);
213 vnet_table_write_unlock(flags);
214 if(!entry){
215 err = -ENOMEM;
216 vnet_dev_remove(info);
217 Vnet_decref(info);
218 }
219 exit:
220 return err;
221 }
223 /** Remove a vnet from the table.
224 * Also removes all vifs and varp entries for the vnet.
225 *
226 * @param vnet id of vnet to remove
227 * @return number of vnets removed
228 */
229 int Vnet_del(VnetId *vnet){
230 int count;
231 unsigned long flags;
232 Vnet *info;
234 vnet_table_write_lock(flags);
235 info = HashTable_get(vnet_table, vnet);
236 count = HashTable_remove(vnet_table, vnet);
237 vnet_table_write_unlock(flags);
239 varp_remove_vnet(vnet);
240 vif_remove_vnet(vnet);
242 if(info){
243 // Can't do this in the hashtable entry free function because it runs
244 // while we hold the vnet table lock, and the vnet tidy up calls
245 // vnet_dev_remove(), which calls unregister_netdev(), which schedules.
246 vnet_dev_remove(info);
247 Vnet_decref(info);
248 }
249 return count;
250 }
252 /** Lookup a vnet by id.
253 * References the vnet on success - the caller must decref.
254 *
255 * @param vnet vnet id
256 * @param pinfo return parameter for vnet (or NULL)
257 * @return 0 on sucess, -ENOENT if no vnet found
258 */
259 int Vnet_lookup(VnetId *vnet, Vnet **pinfo){
260 int err = 0;
261 unsigned long flags;
262 Vnet *info;
264 vnet_table_read_lock(flags);
265 info = HashTable_get(vnet_table, vnet);
266 if(info){
267 if(pinfo){
268 Vnet_incref(info);
269 }
270 } else {
271 err = -ENOENT;
272 }
273 vnet_table_read_unlock(flags);
275 if(pinfo){
276 *pinfo = (err ? NULL : info);
277 }
278 return err;
279 }
281 static int vnet_key_equal_fn(void *k1, void *k2){
282 return memcmp(k1, k2, sizeof(VnetId)) == 0;
283 }
285 static Hashcode vnet_key_hash_fn(void *k){
286 return hash_hvoid(0, k, sizeof(VnetId));
287 }
289 /** Free an entry in the vnet table.
290 *
291 * @param table containing table
292 * @param entry to free
293 */
294 static void vnet_entry_free_fn(HashTable *table, HTEntry *entry){
295 if(!entry) return;
296 HTEntry_free(entry);
297 }
299 void vnet_table_free(void){
300 HashTable *vnt;
301 HashTable_for_decl(entry);
303 vnt = vnet_table;
304 if(!vnt) return;
305 vnet_table = NULL;
306 HashTable_for_each(entry, vnt){
307 Vnet *info = entry->value;
308 vnet_dev_remove(info);
309 Vnet_decref(info);
310 }
311 HashTable_free(vnt);
312 }
314 int vnet_table_init(void){
315 int err = 0;
316 vnet_table = HashTable_new(0);
317 if(!vnet_table){
318 err = -ENOMEM;
319 goto exit;
320 }
321 vnet_table->key_size = sizeof(VnetId);
322 vnet_table->key_equal_fn = vnet_key_equal_fn;
323 vnet_table->key_hash_fn = vnet_key_hash_fn;
324 vnet_table->entry_free_fn = vnet_entry_free_fn;
326 err = Vnet_alloc(&vnet_physical);
327 if(err) goto exit;
328 vnet_physical->vnet = toVnetId(VNET_PHYS);
329 vnet_physical->security = 0;
330 err = Vnet_add(vnet_physical);
332 exit:
333 if(err){
334 vnet_table_free();
335 }
336 return err;
337 }
339 /** Setup some vnet entries (for testing).
340 * Vnet 1 is physical, vnets 2 to 10 are insecure, vnets above
341 * 10 are secure.
342 *
343 * @return 0 on success, negative error code otherwise
344 */
345 static int vnet_setup(void){
346 int err = 0;
347 int i, n = 3;
348 int security = vnet_security_default;
349 uint32_t vnetid;
350 Vnet *vnet;
352 for(i=0; i<n; i++){
353 err = Vnet_alloc(&vnet);
354 if(err) break;
355 vnetid = VNET_VIF + i;
356 vnet->vnet = toVnetId(vnetid);
357 snprintf(vnet->device, sizeof(vnet->device), "vnif%04x", vnetid);
358 vnet->security = (vnetid > 10 ? security : 0);
359 err = Vnet_create(vnet);
360 Vnet_decref(vnet);
361 if(err) break;
362 }
363 return err;
364 }
366 /** Initialize the vnet table and the physical vnet.
367 *
368 * @return 0 on success, error code otherwise
369 */
370 int vnet_init(void){
371 int err = 0;
373 err = vnet_forward_init();
374 if(err) goto exit;
375 err = vnet_table_init();
376 if(err) goto exit;
377 err = vnet_setup();
378 if(err) goto exit;
379 err = vif_init();
380 if(err) goto exit;
381 err = varp_init();
382 exit:
383 return err;
384 }
386 void vnet_exit(void){
387 varp_exit();
388 vif_exit();
389 vnet_table_free();
390 vnet_forward_exit();
391 }
393 #ifdef __KERNEL__
394 inline int _skb_xmit(struct sk_buff *skb, uint32_t saddr){
395 int err = 0;
396 struct rtable *rt = NULL;
398 dprintf("> src=%u.%u.%u.%u dst=%u.%u.%u.%u\n",
399 NIPQUAD(skb->nh.iph->saddr),
400 NIPQUAD(skb->nh.iph->daddr));
401 skb->protocol = htons(ETH_P_IP);
402 if(saddr){
403 skb->nh.iph->saddr = 0;
404 }
405 err = skb_route(skb, &rt);
406 if(err){
407 wprintf("> skb_route=%d\n", err);
408 wprintf("> dev=%s idx=%d src=%u.%u.%u.%u dst=%u.%u.%u.%u tos=%d\n",
409 (skb->dev ? skb->dev->name : "???"),
410 (skb->dev ? skb->dev->ifindex : -1),
411 NIPQUAD(skb->nh.iph->saddr),
412 NIPQUAD(skb->nh.iph->daddr),
413 skb->nh.iph->tos);
415 goto exit;
416 }
417 dst_release(skb->dst);
418 skb->dst = &rt->u.dst;
419 if(!skb->dev){
420 skb->dev = rt->u.dst.dev;
421 }
423 ip_select_ident(skb->nh.iph, &rt->u.dst, NULL);
425 if(saddr){
426 skb->nh.iph->saddr = saddr;
427 } else {
428 if(!skb->nh.iph->saddr){
429 skb->nh.iph->saddr = rt->rt_src;
430 }
431 }
433 ip_send_check(skb->nh.iph);
435 #if 1
436 // Output to skb destination. Will use ip_output(), which fragments.
437 // Slightly slower than neigh_compat_output() (marginal - 1%).
438 err = dst_output(skb);
439 #else
440 // Sends direct to device via dev_queue_xmit(). No fragmentation?
441 err = neigh_compat_output(skb);
442 #endif
444 #if 0
445 if(needs_frags){
446 err = ip_fragment(skb, ip_finish_output);
447 } else {
448 err = ip_finish_output(skb);
449 }
450 #endif
452 exit:
453 dprintf("< err=%d\n", err);
454 return err;
455 }
457 #else
459 extern int _skb_xmit(struct sk_buff *skb, uint32_t saddr);
461 #endif
463 int skb_xmit(struct sk_buff *skb){
464 if(MULTICAST(skb->nh.iph->daddr)){
465 vnet_forward_send(skb);
466 }
467 return _skb_xmit(skb, 0);
468 }
470 /** Called when a vif sends a packet to the network.
471 * Encapsulates the packet for its vnet and forwards it.
472 *
473 * @param skb packet
474 * @return 0 on success, error code otherwise
475 *
476 */
477 int vnet_skb_send(struct sk_buff *skb, VnetId *vnet){
478 VnetId vnet_phys = toVnetId(VNET_PHYS);
479 int err = 0;
481 //dprintf(">\n");
482 skb->dev = NULL;
483 if(!vnet || VnetId_eq(vnet, &vnet_phys)){
484 // No vnet or physical vnet, send direct to the network.
485 skb_xmit(skb);
486 } else {
487 // Update the vif table with the source MAC.
488 vif_update(vnet, (Vmac*)eth_hdr(skb)->h_source);
489 err = varp_output(skb, vnet);
490 }
491 //dprintf("< err=%d\n", err);
492 return err;
493 }
495 /** Receive an skb for a vnet.
496 * We make the skb come out of the vif for the vnet, and
497 * let ethernet bridging forward it to related interfaces.
498 *
499 * The packet must have skb->mac.raw set and skb->data must point
500 * after the device (ethernet) header.
501 *
502 * Return code 1 means we now own the packet - the caller must not free it.
503 * Return code < 0 means an error - caller still owns the packet.
504 *
505 * @param skb packet
506 * @param vnet packet vnet
507 */
508 int vnet_skb_recv(struct sk_buff *skb, Vnet *vnet){
509 int err = 1;
511 if(!vnet->dev){
512 // No device for the vnet.
513 err = -ENOTCONN;
514 goto exit;
515 }
516 skb->dev = vnet->dev;
517 vnet->stats.rx_packets++;
518 vnet->stats.rx_bytes += skb->len;
519 netif_rx(skb);
520 exit:
521 return err;
522 }
525 /** Check that a context has the correct properties w.r.t. a vnet.
526 * The context must be secure if the vnet requires security.
527 *
528 * @param vnet vnet id
529 * @param context context
530 * @return 0 on success, error code otherwise
531 *
532 * @todo Need to check that the sa provides the correct security level.
533 */
534 int vnet_check_context(VnetId *vnet, SkbContext *context, Vnet **val){
535 int err = 0;
536 Vnet *info = NULL;
537 SAState *sa = NULL;
539 err = Vnet_lookup(vnet, &info);
540 if(err){
541 goto exit;
542 }
543 if(!info->security) goto exit;
544 err = -EINVAL;
545 if(!context){
546 wprintf("> No security context\n");
547 goto exit;
548 }
549 if(context->protocol != IPPROTO_ESP){
550 wprintf("> Invalid protocol: wanted %d, got %d\n",
551 IPPROTO_ESP, context->protocol);
552 goto exit;
553 }
554 sa = context->data;
555 //todo: Check security properties of the SA are correct w.r.t. the vnet.
556 //Something like sa->security == info->security;
557 err = 0;
558 exit:
559 *val = info;
560 return err;
561 }
564 /** Create a tunnel for a vnet to a given address.
565 *
566 * @param vnet vnet id
567 * @param addr destination address
568 * @param tunnel return parameter
569 * @return 0 on success, error code otherwise
570 */
571 static int vnet_tunnel_create(VnetId *vnet, VarpAddr *addr, Tunnel **tunnel){
572 int err = 0;
573 Vnet *info = NULL;
574 Tunnel *base = NULL;
575 Tunnel *sa_tunnel = NULL;
576 Tunnel *eth_tunnel = NULL;
578 err = Vnet_lookup(vnet, &info);
579 if(err) goto exit;
580 if(info->security){
581 err = sa_tunnel_create(info, addr, base, &sa_tunnel);
582 if(err) goto exit;
583 base = sa_tunnel;
584 }
585 err = etherip_tunnel_create(vnet, addr, base, &eth_tunnel);
586 exit:
587 Tunnel_decref(sa_tunnel);
588 Vnet_decref(info);
589 *tunnel = (err ? NULL : eth_tunnel);
590 return err;
591 }
593 /** Lookup a tunnel for a vnet to a given address.
594 * Uses an existing tunnel if there is one.
595 *
596 * @param vnet vnet id
597 * @param addr care-of address
598 * @param tunnel return parameter
599 * @return 0 on success, error code otherwise
600 */
601 int vnet_tunnel_lookup(VnetId *vnet, VarpAddr *addr, Tunnel **tunnel){
602 int err = 0;
603 err = Tunnel_lookup(vnet, addr, tunnel);
604 if(err){
605 err = Tunnel_open(vnet, addr, vnet_tunnel_create, tunnel);
606 }
607 return err;
608 }
610 /** Send a packet on the appropriate tunnel.
611 *
612 * @param vnet vnet
613 * @param addr tunnel endpoint
614 * @param skb packet
615 * @return 0 on success, error code otherwise
616 */
617 int vnet_tunnel_send(VnetId *vnet, VarpAddr *addr, struct sk_buff *skb){
618 int err = 0;
619 Tunnel *tunnel = NULL;
621 err = vnet_tunnel_lookup(vnet, addr, &tunnel);
622 if(err) {
623 char vnetbuf[VNET_ID_BUF];
624 char addrbuf[VARP_ADDR_BUF];
625 wprintf("No tunnel: skb=%p vnet=%s addr=%s\n",
626 skb,
627 VnetId_ntoa(vnet, vnetbuf),
628 VarpAddr_ntoa(addr, addrbuf));
629 goto exit;
630 }
631 err = Tunnel_send(tunnel, skb);
632 Tunnel_decref(tunnel);
633 exit:
634 return err;
635 }
637 #ifdef __KERNEL__
639 /** Module parameter for vnet encapsulation. */
640 static char *vnet_encaps = NULL;
642 static void __exit vnet_module_exit(void){
643 ProcFS_exit();
644 sa_table_exit();
645 vnet_exit();
646 esp_module_exit();
647 etherip_module_exit();
648 tunnel_module_exit();
649 random_module_exit();
650 }
652 /** Initialize the vnet module.
653 * Failure is fatal.
654 *
655 * @return 0 on success, error code otherwise
656 */
657 static int __init vnet_module_init(void){
658 int err = 0;
660 if(vnet_encaps && !strcmp(vnet_encaps, "udp")){
661 etherip_in_udp = 1;
662 }
663 dprintf(">\n");
664 err = random_module_init();
665 if(err) wprintf("> random_module_init err=%d\n", err);
666 if(err) goto exit;
667 err = tunnel_module_init();
668 if(err) wprintf("> tunnel_module_init err=%d\n", err);
669 if(err) goto exit;
670 err = etherip_module_init();
671 if(err) wprintf("> etherip_module_init err=%d\n", err);
672 if(err) goto exit;
673 err = esp_module_init();
674 if(err) wprintf("> esp_module_init err=%d\n", err);
675 if(err) goto exit;
676 err = vnet_init();
677 if(err) wprintf("> vnet_init err=%d\n", err);
678 if(err) goto exit;
679 sa_algorithm_probe_all();
680 err = sa_table_init();
681 if(err) wprintf("> sa_table_init err=%d\n", err);
682 if(err) goto exit;
683 ProcFS_init();
684 exit:
685 if(err < 0){
686 vnet_module_exit();
687 wprintf("< err=%d\n", err);
688 }
689 return err;
690 }
692 module_init(vnet_module_init);
693 module_exit(vnet_module_exit);
694 MODULE_LICENSE("GPL");
696 module_param(vnet_encaps, charp, 0644);
697 MODULE_PARM_DESC(vnet_encaps, "Vnet encapsulation: etherip or udp.");
699 #endif