Import from old repository commit 61ef2b42a9c4ba8e1600f15bb0236765edc2ad45.
[cascardo/ovs.git] / lib / port-array.h
1 /*
2  * Copyright (c) 2008, 2009 Nicira Networks.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #ifndef PORT_ARRAY_H
18 #define PORT_ARRAY_H 1
19
20 #include <assert.h>
21 #include "openflow/openflow.h"
22 #include "util.h"
23
24 static inline uint16_t
25 port_array_extract_bits__(uint16_t data, int start, int count)
26 {
27     return (data >> start) & ((1u << count) - 1);
28 }
29
30 /* Level 1: most-significant bits. */
31 #define PORT_ARRAY_L1_BITS 5
32 #define PORT_ARRAY_L1_SHIFT (PORT_ARRAY_L3_BITS + PORT_ARRAY_L2_BITS)
33 #define PORT_ARRAY_L1_SIZE (1u << PORT_ARRAY_L1_BITS)
34 #define PORT_ARRAY_L1(IDX) \
35     port_array_extract_bits__(IDX, PORT_ARRAY_L1_SHIFT, PORT_ARRAY_L1_BITS)
36
37 /* Level 2: middle bits. */
38 #define PORT_ARRAY_L2_BITS 5
39 #define PORT_ARRAY_L2_SHIFT PORT_ARRAY_L3_BITS
40 #define PORT_ARRAY_L2_SIZE (1u << PORT_ARRAY_L2_BITS)
41 #define PORT_ARRAY_L2(IDX) \
42     port_array_extract_bits__(IDX, PORT_ARRAY_L2_SHIFT, PORT_ARRAY_L2_BITS)
43
44 /* Level 3: least-significant bits. */
45 #define PORT_ARRAY_L3_BITS 6
46 #define PORT_ARRAY_L3_SHIFT 0
47 #define PORT_ARRAY_L3_SIZE (1u << PORT_ARRAY_L3_BITS)
48 #define PORT_ARRAY_L3(IDX) \
49     port_array_extract_bits__(IDX, PORT_ARRAY_L3_SHIFT, PORT_ARRAY_L3_BITS)
50
51 #define PORT_ARRAY_SIZE (1u << (PORT_ARRAY_L1_BITS      \
52                                 + PORT_ARRAY_L2_BITS    \
53                                 + PORT_ARRAY_L3_BITS))
54
55 BUILD_ASSERT_DECL(PORT_ARRAY_SIZE > 0xffff);
56
57 /* A "sparse array" of up to 65536 elements (numbered 0...65535), implemented
58  * as a 3-level trie.  Most efficient when the elements are clustered
59  * together. */
60 struct port_array {
61     struct port_array_l2 *l1[1u << PORT_ARRAY_L1_BITS];
62 };
63
64 struct port_array_l2 {
65     struct port_array_l3 *l2[1u << PORT_ARRAY_L2_BITS];
66 };
67
68 struct port_array_l3 {
69     void *l3[1u << PORT_ARRAY_L3_BITS];
70 };
71
72 /* Returns the value of the element numbered 'idx' in 'pa', or a null pointer
73  * if no element numbered 'idx' has been set. */
74 static inline void *
75 port_array_get(const struct port_array *pa, uint16_t idx)
76 {
77     unsigned int l1_idx = PORT_ARRAY_L1(idx);
78     unsigned int l2_idx = PORT_ARRAY_L2(idx);
79     unsigned int l3_idx = PORT_ARRAY_L3(idx);
80     return pa->l1[l1_idx]->l2[l2_idx]->l3[l3_idx];
81 }
82
83 void port_array_init(struct port_array *);
84 void port_array_destroy(struct port_array *);
85 void port_array_clear(struct port_array *);
86 void port_array_set(struct port_array *, uint16_t idx, void *);
87 void *port_array_first(const struct port_array *, unsigned int *);
88 void *port_array_next(const struct port_array *, unsigned int *);
89 unsigned int port_array_count(const struct port_array *);
90
91 #define PORT_ARRAY_FOR_EACH(DATA, ARRAY, PORT_NO)                       \
92     for ((DATA) = port_array_first(ARRAY, &(PORT_NO)); (DATA) != NULL;  \
93          (DATA) = port_array_next(ARRAY, &(PORT_NO)))
94
95 #endif /* port-array.h */