29d205943acb68955e4a500f3017f348c43a5ed8
[sliver-openvswitch.git] / datapath / table-hash.c
1 /*
2  * Distributed under the terms of the GNU GPL version 2.
3  * Copyright (c) 2007, 2008 The Board of Trustees of The Leland 
4  * Stanford Junior University
5  */
6
7 #include "table.h"
8 #include "crc32.h"
9 #include "flow.h"
10 #include "datapath.h"
11
12 #include <linux/slab.h>
13 #include <linux/vmalloc.h>
14 #include <linux/mm.h>
15 #include <linux/highmem.h>
16 #include <asm/pgtable.h>
17
18 static void *kmem_alloc(size_t);
19 static void *kmem_zalloc(size_t);
20 static void kmem_free(void *, size_t);
21
22 struct sw_table_hash {
23         struct sw_table swt;
24         struct crc32 crc32;
25         unsigned int n_flows;
26         unsigned int bucket_mask; /* Number of buckets minus 1. */
27         struct sw_flow **buckets;
28 };
29
30 static struct sw_flow **find_bucket(struct sw_table *swt,
31                                                                         const struct sw_flow_key *key)
32 {
33         struct sw_table_hash *th = (struct sw_table_hash *) swt;
34         unsigned int crc = crc32_calculate(&th->crc32, key, 
35                                 offsetof(struct sw_flow_key, wildcards));
36         return &th->buckets[crc & th->bucket_mask];
37 }
38
39 static struct sw_flow *table_hash_lookup(struct sw_table *swt,
40                                                                                  const struct sw_flow_key *key)
41 {
42         struct sw_flow *flow = *find_bucket(swt, key);
43         return flow && flow_keys_equal(&flow->key, key) ? flow : NULL;
44 }
45
46 static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow)
47 {
48         struct sw_table_hash *th = (struct sw_table_hash *) swt;
49         struct sw_flow **bucket;
50         int retval;
51
52         if (flow->key.wildcards != 0)
53                 return 0;
54
55         bucket = find_bucket(swt, &flow->key);
56         if (*bucket == NULL) {
57                 th->n_flows++;
58                 rcu_assign_pointer(*bucket, flow);
59                 retval = 1;
60         } else {
61                 struct sw_flow *old_flow = *bucket;
62                 if (flow_keys_equal(&old_flow->key, &flow->key)) {
63                         rcu_assign_pointer(*bucket, flow);
64                         flow_deferred_free(old_flow);
65                         retval = 1;
66                 } else {
67                         retval = 0;
68                 }
69         }
70         return retval;
71 }
72
73 static int table_hash_modify(struct sw_table *swt, 
74                 const struct sw_flow_key *key, uint16_t priority, int strict,
75                 const struct ofp_action *actions, int n_actions) 
76 {
77         struct sw_table_hash *th = (struct sw_table_hash *) swt;
78         unsigned int count = 0;
79
80         if (key->wildcards == 0) {
81                 struct sw_flow **bucket = find_bucket(swt, key);
82                 struct sw_flow *flow = *bucket;
83                 if (flow && flow_matches_desc(&flow->key, key, strict)
84                                 && (!strict || (flow->priority == priority))) {
85                         flow_replace_acts(flow, actions, n_actions);
86                         count = 1;
87                 }
88         } else {
89                 unsigned int i;
90
91                 for (i = 0; i <= th->bucket_mask; i++) {
92                         struct sw_flow **bucket = &th->buckets[i];
93                         struct sw_flow *flow = *bucket;
94                         if (flow && flow_matches_desc(&flow->key, key, strict)
95                                         && (!strict || (flow->priority == priority))) {
96                                 flow_replace_acts(flow, actions, n_actions);
97                                 count++;
98                         }
99                 }
100         }
101         return count;
102 }
103
104 /* Caller must update n_flows. */
105 static int do_delete(struct sw_flow **bucket, struct sw_flow *flow)
106 {
107         rcu_assign_pointer(*bucket, NULL);
108         flow_deferred_free(flow);
109         return 1;
110 }
111
112 /* Returns number of deleted flows.  We can ignore the priority
113  * argument, since all exact-match entries are the same (highest)
114  * priority. */
115 static int table_hash_delete(struct sw_table *swt,
116                                                          const struct sw_flow_key *key, 
117                                                          uint16_t priority, int strict)
118 {
119         struct sw_table_hash *th = (struct sw_table_hash *) swt;
120         unsigned int count = 0;
121
122         if (key->wildcards == 0) {
123                 struct sw_flow **bucket = find_bucket(swt, key);
124                 struct sw_flow *flow = *bucket;
125                 if (flow && flow_keys_equal(&flow->key, key))
126                         count = do_delete(bucket, flow);
127         } else {
128                 unsigned int i;
129
130                 for (i = 0; i <= th->bucket_mask; i++) {
131                         struct sw_flow **bucket = &th->buckets[i];
132                         struct sw_flow *flow = *bucket;
133                         if (flow && flow_matches_desc(&flow->key, key, strict))
134                                 count += do_delete(bucket, flow);
135                 }
136         }
137         th->n_flows -= count;
138         return count;
139 }
140
141 static int table_hash_timeout(struct datapath *dp, struct sw_table *swt)
142 {
143         struct sw_table_hash *th = (struct sw_table_hash *) swt;
144         unsigned int i;
145         int count = 0;
146
147         mutex_lock(&dp_mutex);
148         for (i = 0; i <= th->bucket_mask; i++) {
149                 struct sw_flow **bucket = &th->buckets[i];
150                 struct sw_flow *flow = *bucket;
151                 if (flow) {
152                         int reason = flow_timeout(flow);
153                         if (reason >= 0) {
154                                 count += do_delete(bucket, flow); 
155                                 dp_send_flow_expired(dp, flow, reason);
156                         }
157                 }
158         }
159         th->n_flows -= count;
160         mutex_unlock(&dp_mutex);
161
162         return count;
163 }
164
165 static void table_hash_destroy(struct sw_table *swt)
166 {
167         struct sw_table_hash *th = (struct sw_table_hash *) swt;
168         unsigned int i;
169         for (i = 0; i <= th->bucket_mask; i++)
170         if (th->buckets[i])
171                 flow_free(th->buckets[i]);
172         kmem_free(th->buckets, (th->bucket_mask + 1) * sizeof *th->buckets);
173         kfree(th);
174 }
175
176 static int table_hash_iterate(struct sw_table *swt,
177                               const struct sw_flow_key *key,
178                               struct sw_table_position *position,
179                               int (*callback)(struct sw_flow *, void *private),
180                               void *private) 
181 {
182         struct sw_table_hash *th = (struct sw_table_hash *) swt;
183
184         if (position->private[0] > th->bucket_mask)
185                 return 0;
186
187         if (key->wildcards == 0) {
188                 struct sw_flow *flow;
189                 int error;
190
191                 flow = table_hash_lookup(swt, key);
192                 if (!flow)
193                         return 0;
194
195                 error = callback(flow, private);
196                 if (!error)
197                         position->private[0] = -1;
198                 return error;
199         } else {
200                 int i;
201
202                 for (i = position->private[0]; i <= th->bucket_mask; i++) {
203                         struct sw_flow *flow = th->buckets[i];
204                         if (flow && flow_matches_1wild(&flow->key, key)) {
205                                 int error = callback(flow, private);
206                                 if (error) {
207                                         position->private[0] = i;
208                                         return error;
209                                 }
210                         }
211                 }
212                 return 0;
213         }
214 }
215 static void table_hash_stats(struct sw_table *swt,
216                                  struct sw_table_stats *stats) 
217 {
218         struct sw_table_hash *th = (struct sw_table_hash *) swt;
219         stats->name = "hash";
220         stats->wildcards = 0;          /* No wildcards are supported. */
221         stats->n_flows   = th->n_flows;
222         stats->max_flows = th->bucket_mask + 1;
223         stats->n_matched = swt->n_matched;
224 }
225
226 struct sw_table *table_hash_create(unsigned int polynomial,
227                         unsigned int n_buckets)
228 {
229         struct sw_table_hash *th;
230         struct sw_table *swt;
231
232         th = kzalloc(sizeof *th, GFP_KERNEL);
233         if (th == NULL)
234                 return NULL;
235
236         BUG_ON(n_buckets & (n_buckets - 1));
237         th->buckets = kmem_zalloc(n_buckets * sizeof *th->buckets);
238         if (th->buckets == NULL) {
239                 printk("failed to allocate %u buckets\n", n_buckets);
240                 kfree(th);
241                 return NULL;
242         }
243         th->bucket_mask = n_buckets - 1;
244
245         swt = &th->swt;
246         swt->lookup = table_hash_lookup;
247         swt->insert = table_hash_insert;
248         swt->delete = table_hash_delete;
249         swt->timeout = table_hash_timeout;
250         swt->destroy = table_hash_destroy;
251         swt->iterate = table_hash_iterate;
252         swt->stats = table_hash_stats;
253
254         crc32_init(&th->crc32, polynomial);
255         th->n_flows = 0;
256
257         return swt;
258 }
259
260 /* Double-hashing table. */
261
262 struct sw_table_hash2 {
263         struct sw_table swt;
264         struct sw_table *subtable[2];
265 };
266
267 static struct sw_flow *table_hash2_lookup(struct sw_table *swt,
268                                                                                   const struct sw_flow_key *key)
269 {
270         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
271         int i;
272         
273         for (i = 0; i < 2; i++) {
274                 struct sw_flow *flow = *find_bucket(t2->subtable[i], key);
275                 if (flow && flow_keys_equal(&flow->key, key))
276                         return flow;
277         }
278         return NULL;
279 }
280
281 static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow)
282 {
283         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
284
285         if (table_hash_insert(t2->subtable[0], flow))
286                 return 1;
287         return table_hash_insert(t2->subtable[1], flow);
288 }
289
290 static int table_hash2_modify(struct sw_table *swt, 
291                 const struct sw_flow_key *key, uint16_t priority, int strict,
292                 const struct ofp_action *actions, int n_actions)
293 {
294         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
295         return (table_hash_modify(t2->subtable[0], key, priority, strict, 
296                                         actions, n_actions)
297                         + table_hash_modify(t2->subtable[1], key, priority, strict, 
298                                         actions, n_actions));
299 }
300
301 static int table_hash2_delete(struct sw_table *swt,
302                                                           const struct sw_flow_key *key, 
303                                                           uint16_t priority, int strict)
304 {
305         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
306         return (table_hash_delete(t2->subtable[0], key, priority, strict)
307                         + table_hash_delete(t2->subtable[1], key, priority, strict));
308 }
309
310 static int table_hash2_timeout(struct datapath *dp, struct sw_table *swt)
311 {
312         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
313         return (table_hash_timeout(dp, t2->subtable[0])
314                         + table_hash_timeout(dp, t2->subtable[1]));
315 }
316
317 static void table_hash2_destroy(struct sw_table *swt)
318 {
319         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
320         table_hash_destroy(t2->subtable[0]);
321         table_hash_destroy(t2->subtable[1]);
322         kfree(t2);
323 }
324
325 static int table_hash2_iterate(struct sw_table *swt,
326                                const struct sw_flow_key *key,
327                                struct sw_table_position *position,
328                                int (*callback)(struct sw_flow *, void *),
329                                void *private)
330 {
331         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
332         int i;
333
334         for (i = position->private[1]; i < 2; i++) {
335                 int error = table_hash_iterate(t2->subtable[i], key, position,
336                                                callback, private);
337                 if (error) {
338                         return error;
339                 }
340                 position->private[0] = 0;
341                 position->private[1]++;
342         }
343         return 0;
344 }
345
346 static void table_hash2_stats(struct sw_table *swt,
347                                  struct sw_table_stats *stats)
348 {
349         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
350         struct sw_table_stats substats[2];
351         int i;
352
353         for (i = 0; i < 2; i++)
354                 table_hash_stats(t2->subtable[i], &substats[i]);
355         stats->name = "hash2";
356         stats->wildcards = 0;          /* No wildcards are supported. */
357         stats->n_flows   = substats[0].n_flows + substats[1].n_flows;
358         stats->max_flows = substats[0].max_flows + substats[1].max_flows;
359         stats->n_matched = swt->n_matched;
360 }
361
362 struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0,
363                                                                         unsigned int poly1, unsigned int buckets1)
364
365 {
366         struct sw_table_hash2 *t2;
367         struct sw_table *swt;
368
369         t2 = kzalloc(sizeof *t2, GFP_KERNEL);
370         if (t2 == NULL)
371                 return NULL;
372
373         t2->subtable[0] = table_hash_create(poly0, buckets0);
374         if (t2->subtable[0] == NULL)
375                 goto out_free_t2;
376
377         t2->subtable[1] = table_hash_create(poly1, buckets1);
378         if (t2->subtable[1] == NULL)
379                 goto out_free_subtable0;
380
381         swt = &t2->swt;
382         swt->lookup = table_hash2_lookup;
383         swt->insert = table_hash2_insert;
384         swt->modify = table_hash2_modify;
385         swt->delete = table_hash2_delete;
386         swt->timeout = table_hash2_timeout;
387         swt->destroy = table_hash2_destroy;
388         swt->iterate = table_hash2_iterate;
389         swt->stats = table_hash2_stats;
390
391         return swt;
392
393 out_free_subtable0:
394         table_hash_destroy(t2->subtable[0]);
395 out_free_t2:
396         kfree(t2);
397         return NULL;
398 }
399
400 /* From fs/xfs/linux-2.4/kmem.c. */
401
402 static void *
403 kmem_alloc(size_t size)
404 {
405         void *ptr;
406
407 #ifdef KMALLOC_MAX_SIZE
408         if (size > KMALLOC_MAX_SIZE)
409                 return NULL;
410 #endif
411         ptr = kmalloc(size, GFP_KERNEL);
412         if (!ptr) {
413                 ptr = vmalloc(size);
414                 if (ptr)
415                         printk("openflow: used vmalloc for %lu bytes\n", 
416                                         (unsigned long)size);
417         }
418         return ptr;
419 }
420
421 static void *
422 kmem_zalloc(size_t size)
423 {
424         void *ptr = kmem_alloc(size);
425         if (ptr)
426                 memset(ptr, 0, size);
427         return ptr;
428 }
429
430 static void
431 kmem_free(void *ptr, size_t size)
432 {
433         if (((unsigned long)ptr < VMALLOC_START) ||
434                 ((unsigned long)ptr >= VMALLOC_END)) {
435                 kfree(ptr);
436         } else {
437                 vfree(ptr);
438         }
439 }