source: trunk/packages/xen-3.1/xen-3.1/tools/vnet/vnet-module/tunnel.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 7.1 KB
Line 
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 */
19#ifdef __KERNEL__
20
21#include <linux/config.h>
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/skbuff.h>
25#include <linux/spinlock.h>
26
27#else
28
29#include "sys_kernel.h"
30#include "spinlock.h"
31#include "skbuff.h"
32
33#endif
34
35#include <tunnel.h>
36#include <vnet.h>
37#include <varp.h>
38#include "hash_table.h"
39
40#define MODULE_NAME "VNET"
41#define DEBUG 1
42#undef DEBUG
43#include "debug.h"
44
45/** Table of tunnels, indexed by vnet and addr. */
46HashTable *tunnel_table = NULL;
47rwlock_t tunnel_table_lock = RW_LOCK_UNLOCKED;
48
49#define tunnel_read_lock(flags)    read_lock_irqsave(&tunnel_table_lock, (flags))
50#define tunnel_read_unlock(flags)  read_unlock_irqrestore(&tunnel_table_lock, (flags))
51#define tunnel_write_lock(flags)   write_lock_irqsave(&tunnel_table_lock, (flags))
52#define tunnel_write_unlock(flags) write_unlock_irqrestore(&tunnel_table_lock, (flags))
53
54void Tunnel_free(Tunnel *tunnel){
55    tunnel->type->close(tunnel);
56    Tunnel_decref(tunnel->base);
57    kfree(tunnel);
58}
59
60void Tunnel_print(Tunnel *tunnel){
61    if(tunnel){
62        iprintf("Tunnel<%p base=%p ref=%02d type=%s>\n",
63               tunnel,
64               tunnel->base,
65               atomic_read(&tunnel->refcount),
66               tunnel->type->name);
67        if(tunnel->base){
68            Tunnel_print(tunnel->base);
69        }
70    } else {
71        iprintf("Tunnel<%p base=%p ref=%02d type=%s>\n",
72               NULL, NULL, 0, "ip");
73    }
74}
75
76int Tunnel_create(TunnelType *type, VnetId *vnet, VarpAddr *addr,
77                  Tunnel *base, Tunnel **val){
78    int err = 0;
79    Tunnel *tunnel = NULL;
80    if(!type || !type->open || !type->send || !type->close){
81        err = -EINVAL;
82        goto exit;
83    }
84    tunnel = kmalloc(sizeof(Tunnel), GFP_ATOMIC);
85    if(!tunnel){
86        err = -ENOMEM;
87        goto exit;
88    }
89    atomic_set(&tunnel->refcount, 1);
90    tunnel->key.vnet = *vnet;
91    tunnel->key.addr = *addr;
92    tunnel->type = type;
93    tunnel->data = NULL;
94    tunnel->send_stats = (TunnelStats){};
95    Tunnel_incref(base);
96    tunnel->base = base;
97    err = type->open(tunnel);
98  exit:
99    if(err && tunnel){
100        Tunnel_decref(tunnel);
101        tunnel = NULL;
102    }
103    *val = tunnel;
104    dprintf("< err=%d\n", err);
105    return err;
106}
107
108void TunnelStats_update(TunnelStats *stats, int len, int err){
109    dprintf(">len=%d  err=%d\n", len, err);
110    if(err){
111        stats->dropped_bytes += len;
112        stats->dropped_packets++;
113    } else {
114        stats->bytes += len;
115        stats->packets++;
116    }
117    dprintf("<\n");
118}
119
120static inline Hashcode tunnel_table_key_hash_fn(void *k){
121    return hash_hvoid(0, k, sizeof(TunnelKey));
122}
123
124static int tunnel_table_key_equal_fn(void *k1, void *k2){
125    return memcmp(k1, k2, sizeof(TunnelKey)) == 0;
126}
127
128static void tunnel_table_entry_free_fn(HashTable *table, HTEntry *entry){
129    Tunnel *tunnel;
130    if(!entry) return;
131    tunnel = entry->value;
132    Tunnel_decref(tunnel);
133    HTEntry_free(entry);
134}
135
136int Tunnel_init(void){
137    int err = 0;
138    dprintf(">\n");
139    tunnel_table = HashTable_new(0);
140    if(!tunnel_table){
141        err = -ENOMEM;
142        goto exit;
143    }
144    tunnel_table->entry_free_fn = tunnel_table_entry_free_fn;
145    tunnel_table->key_size = sizeof(TunnelKey);
146    tunnel_table->key_hash_fn = tunnel_table_key_hash_fn;
147    tunnel_table->key_equal_fn = tunnel_table_key_equal_fn;
148  exit:
149    dprintf("< err=%d\n", err);
150    return err;
151}
152   
153/** Lookup tunnel state by vnet and destination.
154 * The caller must drop the tunnel reference when done.
155 *
156 * @param vnet vnet
157 * @param addr destination address
158 * @return 0 on success
159 */
160int Tunnel_lookup(VnetId *vnet, VarpAddr *addr, Tunnel **tunnel){
161    unsigned long flags;
162    TunnelKey key = { .vnet = *vnet, .addr = *addr };
163    dprintf(">\n");
164    tunnel_read_lock(flags);
165    *tunnel = HashTable_get(tunnel_table, &key);
166    tunnel_read_unlock(flags);
167    Tunnel_incref(*tunnel);
168    dprintf("< tunnel=%p\n", *tunnel);
169    return (*tunnel ? 0 : -ENOENT);
170}
171
172/** Get a tunnel to a given vnet and destination, creating
173 * a tunnel if necessary.
174 * The caller must drop the tunnel reference when done.
175 *
176 * @param vnet vnet
177 * @param addr destination address
178 * @param ctor tunnel constructor
179 * @parma ptunnel return parameter for the tunnel
180 * @return 0 on success
181 */
182int Tunnel_open(VnetId *vnet, VarpAddr *addr,
183                int (*ctor)(VnetId *vnet, VarpAddr *addr, Tunnel **ptunnel),
184                Tunnel **ptunnel){
185    int err = 0;
186    Tunnel *tunnel = NULL;
187    unsigned long flags;
188    TunnelKey key = { .vnet = *vnet, .addr = *addr };
189
190    tunnel_write_lock(flags);
191    tunnel = HashTable_get(tunnel_table, &key);
192    if(!tunnel){
193        err = ctor(vnet, addr, &tunnel);
194        if(err) goto exit;
195        if(!HashTable_add(tunnel_table, tunnel, tunnel)){
196            err = -ENOMEM;
197            goto exit;
198        }
199    }
200  exit:
201    tunnel_write_unlock(flags);
202    if(err){
203        Tunnel_decref(tunnel);
204        *ptunnel = NULL;
205    } else {
206        Tunnel_incref(tunnel);
207        *ptunnel = tunnel;
208    }
209    return err;
210}
211
212int Tunnel_add(Tunnel *tunnel){
213    int err = 0;
214    unsigned long flags;
215    dprintf(">\n");
216    tunnel_write_lock(flags);
217    if(HashTable_add(tunnel_table, tunnel, tunnel)){
218        Tunnel_incref(tunnel);   
219    } else {
220        err = -ENOMEM;
221    }
222    tunnel_write_unlock(flags);
223    dprintf("< err=%d\n", err);
224    return err;
225}
226
227int Tunnel_del(Tunnel *tunnel){
228    int err;
229    unsigned long flags;
230    tunnel_write_lock(flags);
231    err = HashTable_remove(tunnel_table, tunnel);
232    tunnel_write_unlock(flags);
233    return err;
234}
235
236/** Do tunnel send processing on a packet.
237 *
238 * @param tunnel tunnel state
239 * @param skb packet
240 * @return 0 on success, error code otherwise
241 */
242int Tunnel_send(Tunnel *tunnel, struct sk_buff *skb){
243    int err = 0;
244    dprintf("> tunnel=%p skb=%p\n", tunnel, skb);
245    if(tunnel){
246        int len = skb->len;
247        dprintf("> type=%s type->send...\n", tunnel->type->name);
248        // Must not refer to skb after sending - might have been freed.
249        err = tunnel->type->send(tunnel, skb);
250        TunnelStats_update(&tunnel->send_stats, len, err);
251    } else {
252        err = skb_xmit(skb);
253    }
254    dprintf("< err=%d\n", err);
255    return err;
256}
257
258int __init tunnel_module_init(void){
259    return Tunnel_init();
260}
261
262void __exit tunnel_module_exit(void){
263    unsigned long flags;
264    tunnel_write_lock(flags);
265    if(tunnel_table){
266        HashTable_free(tunnel_table);
267        tunnel_table = NULL;
268    }
269    tunnel_write_unlock(flags);
270}
Note: See TracBrowser for help on using the repository browser.