ia64/xen-unstable

view tools/vnet/vnet-module/vnet.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 3233e7ecfa9f
children 06d84bf87159
line source
1 /*
2 * Copyright (C) 2004 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 #include <linux/config.h>
21 #include <linux/module.h>
22 #include <linux/types.h>
23 #include <linux/kernel.h>
24 #include <linux/version.h>
25 #include <linux/errno.h>
27 #include <linux/string.h>
29 #include <linux/net.h>
30 #include <linux/in.h>
31 #include <linux/inet.h>
32 #include <linux/netdevice.h>
34 #include <linux/etherdevice.h>
35 #include <net/ip.h>
36 #include <net/protocol.h>
37 #include <net/route.h>
38 #include <linux/skbuff.h>
39 #include <net/checksum.h>
41 #include <tunnel.h>
42 #include <sa.h>
43 #include <varp.h>
44 #include <if_varp.h>
45 #include <esp.h>
46 #include <etherip.h>
47 #include <random.h>
48 #include <tunnel.h>
50 #include <skb_util.h>
51 #include <vnet_dev.h>
52 #include <vnet.h>
53 #include <vif.h>
54 #include <vnet_ioctl.h>
55 #include <sa_algorithm.h>
57 #include "allocate.h"
58 #include "hash_table.h"
59 #include "sys_net.h"
60 #include "sys_string.h"
62 #define MODULE_NAME "VNET"
63 #define DEBUG 1
64 #undef DEBUG
65 #include "debug.h"
67 /** Default vnet security level.
68 */
69 int vnet_security_default = SA_AUTH ; //| SA_CONF;
71 /** Key for entries in the vnet address table. */
72 typedef struct VnetAddrKey {
73 /** Vnet id. */
74 VnetId vnet;
75 /** MAC address. */
76 unsigned char mac[ETH_ALEN];
77 } VnetAddrKey;
79 /** The physical vnet. */
80 Vnet *vnet_physical = NULL;
82 /** Table of vnets indexed by id. */
83 static HashTable *vnet_table = NULL;
85 /** Decrement reference count, freeing if zero.
86 *
87 * @param info vnet (OK if null)
88 */
89 void Vnet_decref(Vnet *info){
90 if(!info) return;
91 if(atomic_dec_and_test(&info->refcount)){
92 vnet_dev_remove(info);
93 deallocate(info);
94 }
95 }
97 /** Increment reference count.
98 *
99 * @param info vnet (OK if null)
100 */
101 void Vnet_incref(Vnet *info){
102 if(!info) return;
103 atomic_inc(&info->refcount);
104 }
106 void Vnet_print(Vnet *info)
107 {
108 char vnetbuf[VNET_ID_BUF];
110 printk(KERN_INFO "VNET(vnet=%s device=%s security=%c%c)\n",
111 VnetId_ntoa(&info->vnet, vnetbuf),
112 info->device,
113 ((info->security & SA_AUTH) ? 'a' : '-'),
114 ((info->security & SA_CONF) ? 'c' : '-'));
115 }
117 void vnet_print(void)
118 {
119 HashTable_for_decl(entry);
120 Vnet *info;
122 HashTable_for_each(entry, vnet_table){
123 info = entry->value;
124 Vnet_print(info);
125 }
126 }
128 /** Allocate a vnet, setting reference count to 1.
129 *
130 * @param info return parameter for vnet
131 * @return 0 on success, error code otherwise
132 */
133 int Vnet_alloc(Vnet **info){
134 int err = 0;
135 *info = ALLOCATE(Vnet);
136 if(*info){
137 atomic_set(&(*info)->refcount, 1);
138 } else {
139 err = -ENOMEM;
140 }
141 return err;
142 }
144 /** Add a vnet to the table under its vnet id.
145 *
146 * @param info vnet to add
147 * @return 0 on success, error code otherwise
148 */
149 int Vnet_add(Vnet *info){
150 int err = 0;
151 HTEntry *entry = NULL;
152 // Vnet_del(info->vnet); //todo: Delete existing vnet info?
153 Vnet_incref(info);
154 entry = HashTable_add(vnet_table, &info->vnet, info);
155 if(!entry){
156 err = -ENOMEM;
157 Vnet_decref(info);
158 }
159 return err;
160 }
162 /** Remove a vnet from the table.
163 *
164 * @param vnet id of vnet to remove
165 * @return number of vnets removed
166 */
167 int Vnet_del(VnetId *vnet){
168 return HashTable_remove(vnet_table, vnet);
169 }
171 /** Lookup a vnet by id.
172 * References the vnet on success - the caller must decref.
173 *
174 * @param vnet vnet id
175 * @param info return parameter for vnet
176 * @return 0 on sucess, -ENOENT if no vnet found
177 */
178 int Vnet_lookup(VnetId *vnet, Vnet **info){
179 int err = 0;
180 *info = HashTable_get(vnet_table, vnet);
181 if(*info){
182 Vnet_incref(*info);
183 } else {
184 err = -ENOENT;
185 }
186 return err;
187 }
189 /** Free an entry in the vnet table.
190 *
191 * @param table containing table
192 * @param entry to free
193 */
194 static void vnet_entry_free_fn(HashTable *table, HTEntry *entry){
195 Vnet *info;
196 if(!entry) return;
197 info = entry->value;
198 if(info){
199 vnet_dev_remove(info);
200 Vnet_decref(info);
201 }
202 HTEntry_free(entry);
203 }
205 /** Setup some vnet entries (for testing).
206 * Vnet 1 is physical, vnets 2 to 10 are insecure, vnets above
207 * 10 are secure.
208 *
209 * @return 0 on success, negative error code otherwise
210 */
211 static int vnet_setup(void){
212 int err = 0;
213 int i, n = 3;
214 int security = vnet_security_default;
215 uint32_t vnetid;
216 Vnet *vnet;
218 for(i=0; i<n; i++){
219 err = Vnet_alloc(&vnet);
220 if(err) break;
221 vnetid = VNET_VIF + i;
222 vnet->vnet = toVnetId(vnetid);
223 sprintf(vnet->device, "vnif%04x", vnetid);
224 vnet->security = (vnetid > 10 ? security : 0);
225 err = Vnet_create(vnet);
226 if(err) break;
227 }
228 return err;
229 }
231 int vnet_key_equal_fn(void *k1, void *k2){
232 VnetId *key1 = k1;
233 VnetId *key2 = k2;
234 return VnetId_eq(key1, key2);
235 }
237 Hashcode vnet_key_hash_fn(void *k){
238 VnetId *key = k;
239 return VnetId_hash(0, key);
240 }
242 /** Initialize the vnet table and the physical vnet.
243 *
244 * @return 0 on success, error code otherwise
245 */
246 int vnet_init(void){
247 int err = 0;
249 vnet_table = HashTable_new(0);
250 if(!vnet_table){
251 err = -ENOMEM;
252 goto exit;
253 }
254 vnet_table->key_equal_fn = vnet_key_equal_fn;
255 vnet_table->key_hash_fn = vnet_key_hash_fn;
256 vnet_table->entry_free_fn = vnet_entry_free_fn;
258 err = Vnet_alloc(&vnet_physical);
259 if(err) goto exit;
260 vnet_physical->vnet = toVnetId(VNET_PHYS);
261 vnet_physical->security = 0;
262 err = Vnet_add(vnet_physical);
263 if(err) goto exit;
264 err = vnet_setup();
265 if(err) goto exit;
266 err = varp_init();
267 if(err) goto exit;
268 err = vif_init();
269 exit:
270 return err;
271 }
273 void vnet_exit(void){
274 vif_exit();
275 varp_exit();
276 HashTable_free(vnet_table);
277 vnet_table = NULL;
278 }
280 inline int skb_xmit(struct sk_buff *skb){
281 int err = 0;
282 struct rtable *rt = NULL;
284 dprintf(">\n");
285 skb->protocol = htons(ETH_P_IP);
286 err = skb_route(skb, &rt);
287 if(err){
288 wprintf("> skb_route=%d\n", err);
289 wprintf("> dev=%s idx=%d src=%u.%u.%u.%u dst=%u.%u.%u.%u tos=%d\n",
290 (skb->dev ? skb->dev->name : "???"),
291 (skb->dev ? skb->dev->ifindex : -1),
292 NIPQUAD(skb->nh.iph->saddr),
293 NIPQUAD(skb->nh.iph->daddr),
294 skb->nh.iph->tos);
296 goto exit;
297 }
298 skb->dst = &rt->u.dst;
299 if(!skb->dev){
300 skb->dev = rt->u.dst.dev;
301 }
303 ip_select_ident(skb->nh.iph, &rt->u.dst, NULL);
305 if(skb->nh.iph->saddr == 0){
306 skb->nh.iph->saddr = rt->rt_src;
307 }
309 skb->nh.iph->check = 0;
310 skb->nh.iph->check = ip_compute_csum(skb->nh.raw, (skb->nh.iph->ihl << 2));
312 err = neigh_compat_output(skb);
314 exit:
315 dprintf("< err=%d\n", err);
316 return err;
317 }
319 /** Called when a vif sends a packet to the network.
320 * Encapsulates the packet for its vnet and forwards it.
321 *
322 * @param skb packet
323 * @return 0 on success, error code otherwise
324 *
325 * @todo fixme
326 */
327 int vnet_skb_send(struct sk_buff *skb, VnetId *vnet){
328 int err = 0;
329 VnetId vnet_phys = toVnetId(VNET_PHYS);
331 dprintf(">\n");
332 skb->dev = NULL;
333 if(!vnet || VnetId_eq(vnet, &vnet_phys)){
334 // No vnet or physical vnet, send direct to the network.
335 skb_xmit(skb);
336 } else {
337 err = varp_output(skb, vnet);
338 }
339 dprintf("< err=%d\n", err);
340 return err;
341 }
343 /** Receive an skb for a vnet.
344 * We make the skb come out of the vif for the vnet, and
345 * let ethernet bridging forward it to related interfaces.
346 * If the dest is broadcast, goes to all vifs on the vnet.
347 * If the dest is unicast, goes to the addressed vif on the vnet.
348 *
349 * The packet must have skb->mac.raw set and skb->data must point
350 * after the device (ethernet) header.
351 *
352 * @param skb packet
353 * @param vnet packet vnet
354 * @param vmac packet vmac
355 * @return 0 on success, error code otherwise
356 */
357 int vnet_skb_recv(struct sk_buff *skb, VnetId *vnet, Vmac *vmac){
358 int err = 0;
359 Vnet *info = NULL;
361 err = Vnet_lookup(vnet, &info);
362 if(err) goto exit;
363 skb->dev = info->dev;
364 netif_rx(skb);
365 exit:
366 if(info) Vnet_decref(info);
367 if(err){
368 kfree_skb(skb);
369 }
370 return err;
371 }
373 /** Determine ESP security mode for a new SA.
374 *
375 * @param spi incoming spi
376 * @param protocol incoming protocol
377 * @param addr source address
378 * @return security level or negative error code
379 *
380 * @todo Need to check spi, and do some lookup for security params.
381 */
382 int vnet_sa_security(u32 spi, int protocol, u32 addr){
383 int security = vnet_security_default;
384 dprintf("< security=%x\n", security);
385 return security;
386 }
388 /** Create a new SA for incoming traffic.
389 *
390 * @param spi incoming spi
391 * @param protocol incoming protocol
392 * @param addr source address
393 * @param sa return parameter for SA
394 * @return 0 on success, error code otherwise
395 */
396 int vnet_sa_create(u32 spi, int protocol, u32 addr, SAState **sa){
397 int err = 0;
398 int security = vnet_sa_security(spi, protocol, addr);
399 if(security < 0){
400 err = security;
401 goto exit;
402 }
403 err = sa_create(security, spi, protocol, addr, sa);
404 exit:
405 return err;
406 }
408 /** Check that a context has the correct properties w.r.t. a vnet.
409 * The context must be secure if the vnet requires security.
410 *
411 * @param vnet vnet id
412 * @param context context
413 * @return 0 on success, error code otherwise
414 *
415 * @todo Need to check that the sa provides the correct security level.
416 */
417 int vnet_check_context(VnetId *vnet, SkbContext *context, Vnet **val){
418 int err = 0;
419 Vnet *info = NULL;
420 SAState *sa = NULL;
422 err = Vnet_lookup(vnet, &info);
423 if(err){
424 goto exit;
425 }
426 if(!info->security) goto exit;
427 err = -EINVAL;
428 if(!context){
429 wprintf("> No security context\n");
430 goto exit;
431 }
432 if(context->protocol != IPPROTO_ESP){
433 wprintf("> Invalid protocol: wanted %d, got %d\n",
434 IPPROTO_ESP, context->protocol);
435 goto exit;
436 }
437 sa = context->data;
438 //todo: Check security properties of the SA are correct w.r.t. the vnet.
439 //Something like sa->security == info->security;
440 err = 0;
441 exit:
442 *val = info;
443 return err;
444 }
446 /** Open function for SA tunnels.
447 *
448 * @param tunnel to open
449 * @return 0 on success, error code otherwise
450 */
451 static int sa_tunnel_open(Tunnel *tunnel){
452 int err = 0;
453 //dprintf(">\n");
454 //dprintf("< err=%d\n", err);
455 return err;
456 }
458 /** Close function for SA tunnels.
459 *
460 * @param tunnel to close (OK if null)
461 */
462 static void sa_tunnel_close(Tunnel *tunnel){
463 SAState *sa;
464 if(!tunnel) return;
465 sa = tunnel->data;
466 if(!sa) return;
467 SAState_decref(sa);
468 tunnel->data = NULL;
469 }
471 /** Packet send function for SA tunnels.
472 *
473 * @param tunnel to send on
474 * @param skb packet to send
475 * @return 0 on success, negative error code on error
476 */
477 static int sa_tunnel_send(Tunnel *tunnel, struct sk_buff *skb){
478 int err = -EINVAL;
479 SAState *sa;
480 if(!tunnel){
481 wprintf("> Null tunnel!\n");
482 goto exit;
483 }
484 sa = tunnel->data;
485 if(!sa){
486 wprintf("> Null SA!\n");
487 goto exit;
488 }
489 err = SAState_send(sa, skb, tunnel->base);
490 exit:
491 return err;
492 }
494 /** Functions used by SA tunnels. */
495 static TunnelType _sa_tunnel_type = {
496 .name = "SA",
497 .open = sa_tunnel_open,
498 .close = sa_tunnel_close,
499 .send = sa_tunnel_send
500 };
502 /** Functions used by SA tunnels. */
503 TunnelType *sa_tunnel_type = &_sa_tunnel_type;
505 /** Open a tunnel for a vnet to a given address.
506 *
507 * @param vnet vnet id
508 * @param addr destination address
509 * @param tunnel return parameter
510 * @return 0 on success, error code otherwise
511 */
512 int vnet_tunnel_open(VnetId *vnet, VarpAddr *addr, Tunnel **tunnel){
513 extern TunnelType *etherip_tunnel_type;
514 int err = 0;
515 Vnet *info = NULL;
516 Tunnel *base_tunnel = NULL;
517 Tunnel *sa_tunnel = NULL;
518 Tunnel *etherip_tunnel = NULL;
520 err = Vnet_lookup(vnet, &info);
521 if(err) goto exit;
522 if(info->security){
523 SAState *sa = NULL;
524 //FIXME: Assuming IPv4 for now.
525 u32 ipaddr = addr->u.ip4.s_addr;
526 err = Tunnel_create(sa_tunnel_type, vnet, addr, base_tunnel, &sa_tunnel);
527 if(err) goto exit;
528 err = sa_create(info->security, 0, IPPROTO_ESP, ipaddr, &sa);
529 if(err) goto exit;
530 sa_tunnel->data = sa;
531 base_tunnel = sa_tunnel;
532 }
533 err = Tunnel_create(etherip_tunnel_type, vnet, addr, base_tunnel, &etherip_tunnel);
534 if(err) goto exit;
535 err = Tunnel_add(etherip_tunnel);
536 exit:
537 Tunnel_decref(sa_tunnel);
538 Vnet_decref(info);
539 if(err){
540 *tunnel = NULL;
541 } else {
542 *tunnel = etherip_tunnel;
543 }
544 return err;
545 }
547 /** Lookup a tunnel for a vnet to a given address.
548 * Uses an existing tunnel if there is one.
549 *
550 * @param vnet vnet id
551 * @param addr care-of address
552 * @param tunnel return parameter
553 * @return 0 on success, error code otherwise
554 */
555 int vnet_tunnel_lookup(VnetId *vnet, VarpAddr *addr, Tunnel **tunnel){
556 int err = 0;
557 *tunnel = Tunnel_lookup(vnet, addr);
558 if(!*tunnel){
559 err = vnet_tunnel_open(vnet, addr, tunnel);
560 }
561 return err;
562 }
564 /** Send a packet on the appropriate tunnel.
565 *
566 * @param vnet vnet
567 * @param addr tunnel endpoint
568 * @param skb packet
569 * @return 0 on success, error code otherwise
570 */
571 int vnet_tunnel_send(VnetId *vnet, VarpAddr *addr, struct sk_buff *skb){
572 int err = 0;
573 Tunnel *tunnel = NULL;
574 err = vnet_tunnel_lookup(vnet, addr, &tunnel);
575 if(err) goto exit;
576 err = Tunnel_send(tunnel, skb);
577 Tunnel_decref(tunnel);
578 exit:
579 return err;
580 }
582 static void __exit vnet_module_exit(void){
583 ProcFS_exit();
584 sa_table_exit();
585 vnet_exit();
586 esp_module_exit();
587 etherip_module_exit();
588 tunnel_module_exit();
589 random_module_exit();
590 }
592 /** Initialize the vnet module.
593 * Failure is fatal.
594 *
595 * @return 0 on success, error code otherwise
596 */
597 static int __init vnet_module_init(void){
598 int err = 0;
600 dprintf(">\n");
601 err = random_module_init();
602 if(err) wprintf("> random_module_init err=%d\n", err);
603 if(err) goto exit;
604 err = tunnel_module_init();
605 if(err) wprintf("> tunnel_module_init err=%d\n", err);
606 if(err) goto exit;
607 err = etherip_module_init();
608 if(err) wprintf("> etherip_module_init err=%d\n", err);
609 if(err) goto exit;
610 err = esp_module_init();
611 if(err) wprintf("> esp_module_init err=%d\n", err);
612 if(err) goto exit;
613 err = vnet_init();
614 if(err) wprintf("> vnet_init err=%d\n", err);
615 if(err) goto exit;
616 sa_algorithm_probe_all();
617 err = sa_table_init();
618 if(err) wprintf("> sa_table_init err=%d\n", err);
619 if(err) goto exit;
620 ProcFS_init();
621 exit:
622 if(err < 0){
623 vnet_module_exit();
624 wprintf("< err=%d\n", err);
625 }
626 return err;
627 }
629 module_init(vnet_module_init);
630 module_exit(vnet_module_exit);
631 MODULE_LICENSE("GPL");