86e19201e555c2d808c876df6a43b180580a0c3b
[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_header *actions, size_t actions_len) 
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, actions_len);
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, actions_len);
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_lookup  = swt->n_lookup;
224         stats->n_matched = swt->n_matched;
225 }
226
227 struct sw_table *table_hash_create(unsigned int polynomial,
228                         unsigned int n_buckets)
229 {
230         struct sw_table_hash *th;
231         struct sw_table *swt;
232
233         th = kzalloc(sizeof *th, GFP_KERNEL);
234         if (th == NULL)
235                 return NULL;
236
237         BUG_ON(n_buckets & (n_buckets - 1));
238         th->buckets = kmem_zalloc(n_buckets * sizeof *th->buckets);
239         if (th->buckets == NULL) {
240                 printk("failed to allocate %u buckets\n", n_buckets);
241                 kfree(th);
242                 return NULL;
243         }
244         th->bucket_mask = n_buckets - 1;
245
246         swt = &th->swt;
247         swt->lookup = table_hash_lookup;
248         swt->insert = table_hash_insert;
249         swt->delete = table_hash_delete;
250         swt->timeout = table_hash_timeout;
251         swt->destroy = table_hash_destroy;
252         swt->iterate = table_hash_iterate;
253         swt->stats = table_hash_stats;
254
255         crc32_init(&th->crc32, polynomial);
256         th->n_flows = 0;
257
258         return swt;
259 }
260
261 /* Double-hashing table. */
262
263 struct sw_table_hash2 {
264         struct sw_table swt;
265         struct sw_table *subtable[2];
266 };
267
268 static struct sw_flow *table_hash2_lookup(struct sw_table *swt,
269                                                                                   const struct sw_flow_key *key)
270 {
271         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
272         int i;
273         
274         for (i = 0; i < 2; i++) {
275                 struct sw_flow *flow = *find_bucket(t2->subtable[i], key);
276                 if (flow && flow_keys_equal(&flow->key, key))
277                         return flow;
278         }
279         return NULL;
280 }
281
282 static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow)
283 {
284         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
285
286         if (table_hash_insert(t2->subtable[0], flow))
287                 return 1;
288         return table_hash_insert(t2->subtable[1], flow);
289 }
290
291 static int table_hash2_modify(struct sw_table *swt, 
292                 const struct sw_flow_key *key, uint16_t priority, int strict,
293                 const struct ofp_action_header *actions, size_t actions_len)
294 {
295         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
296         return (table_hash_modify(t2->subtable[0], key, priority, strict, 
297                                         actions, actions_len)
298                         + table_hash_modify(t2->subtable[1], key, priority, strict, 
299                                         actions, actions_len));
300 }
301
302 static int table_hash2_delete(struct sw_table *swt,
303                                                           const struct sw_flow_key *key, 
304                                                           uint16_t priority, int strict)
305 {
306         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
307         return (table_hash_delete(t2->subtable[0], key, priority, strict)
308                         + table_hash_delete(t2->subtable[1], key, priority, strict));
309 }
310
311 static int table_hash2_timeout(struct datapath *dp, struct sw_table *swt)
312 {
313         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
314         return (table_hash_timeout(dp, t2->subtable[0])
315                         + table_hash_timeout(dp, t2->subtable[1]));
316 }
317
318 static void table_hash2_destroy(struct sw_table *swt)
319 {
320         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
321         table_hash_destroy(t2->subtable[0]);
322         table_hash_destroy(t2->subtable[1]);
323         kfree(t2);
324 }
325
326 static int table_hash2_iterate(struct sw_table *swt,
327                                const struct sw_flow_key *key,
328                                struct sw_table_position *position,
329                                int (*callback)(struct sw_flow *, void *),
330                                void *private)
331 {
332         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
333         int i;
334
335         for (i = position->private[1]; i < 2; i++) {
336                 int error = table_hash_iterate(t2->subtable[i], key, position,
337                                                callback, private);
338                 if (error) {
339                         return error;
340                 }
341                 position->private[0] = 0;
342                 position->private[1]++;
343         }
344         return 0;
345 }
346
347 static void table_hash2_stats(struct sw_table *swt,
348                                  struct sw_table_stats *stats)
349 {
350         struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
351         struct sw_table_stats substats[2];
352         int i;
353
354         for (i = 0; i < 2; i++)
355                 table_hash_stats(t2->subtable[i], &substats[i]);
356         stats->name = "hash2";
357         stats->wildcards = 0;          /* No wildcards are supported. */
358         stats->n_flows   = substats[0].n_flows + substats[1].n_flows;
359         stats->max_flows = substats[0].max_flows + substats[1].max_flows;
360         stats->n_lookup  = swt->n_lookup;
361         stats->n_matched = swt->n_matched;
362 }
363
364 struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0,
365                                                                         unsigned int poly1, unsigned int buckets1)
366
367 {
368         struct sw_table_hash2 *t2;
369         struct sw_table *swt;
370
371         t2 = kzalloc(sizeof *t2, GFP_KERNEL);
372         if (t2 == NULL)
373                 return NULL;
374
375         t2->subtable[0] = table_hash_create(poly0, buckets0);
376         if (t2->subtable[0] == NULL)
377                 goto out_free_t2;
378
379         t2->subtable[1] = table_hash_create(poly1, buckets1);
380         if (t2->subtable[1] == NULL)
381                 goto out_free_subtable0;
382
383         swt = &t2->swt;
384         swt->lookup = table_hash2_lookup;
385         swt->insert = table_hash2_insert;
386         swt->modify = table_hash2_modify;
387         swt->delete = table_hash2_delete;
388         swt->timeout = table_hash2_timeout;
389         swt->destroy = table_hash2_destroy;
390         swt->iterate = table_hash2_iterate;
391         swt->stats = table_hash2_stats;
392
393         return swt;
394
395 out_free_subtable0:
396         table_hash_destroy(t2->subtable[0]);
397 out_free_t2:
398         kfree(t2);
399         return NULL;
400 }
401
402 /* From fs/xfs/linux-2.4/kmem.c. */
403
404 static void *
405 kmem_alloc(size_t size)
406 {
407         void *ptr;
408
409 #ifdef KMALLOC_MAX_SIZE
410         if (size > KMALLOC_MAX_SIZE)
411                 return NULL;
412 #endif
413         ptr = kmalloc(size, GFP_KERNEL);
414         if (!ptr) {
415                 ptr = vmalloc(size);
416                 if (ptr)
417                         printk("openflow: used vmalloc for %lu bytes\n", 
418                                         (unsigned long)size);
419         }
420         return ptr;
421 }
422
423 static void *
424 kmem_zalloc(size_t size)
425 {
426         void *ptr = kmem_alloc(size);
427         if (ptr)
428                 memset(ptr, 0, size);
429         return ptr;
430 }
431
432 static void
433 kmem_free(void *ptr, size_t size)
434 {
435         if (((unsigned long)ptr < VMALLOC_START) ||
436                 ((unsigned long)ptr >= VMALLOC_END)) {
437                 kfree(ptr);
438         } else {
439                 vfree(ptr);
440         }
441 }