A Protocol Independent Hierarchical FIB (VPP-352)
[vpp.git] / vnet / vnet / fib / fib_node.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/fib/fib_node.h>
17 #include <vnet/fib/fib_node_list.h>
18
19 /*
20  * The per-type vector of virtual function tables
21  */
22 static fib_node_vft_t *fn_vfts;
23
24 /**
25  * The last registered new type
26  */
27 static fib_node_type_t last_new_type = FIB_NODE_TYPE_LAST;
28
29 /*
30  * the node type names
31  */
32 static const char *fn_type_names[] = FIB_NODE_TYPES;
33
34 const char*
35 fib_node_type_get_name (fib_node_type_t type)
36 {
37     if (type < FIB_NODE_TYPE_LAST)
38         return (fn_type_names[type]);
39     else
40     {
41         if (NULL != fn_vfts[type].fnv_format)
42         {
43             return ("fixme");
44         }
45         else
46         {
47             return ("unknown");
48         }
49     }
50 }
51
52 /**
53  * fib_node_register_type
54  *
55  * Register the function table for a given type
56  */
57 void
58 fib_node_register_type (fib_node_type_t type,
59                         const fib_node_vft_t *vft)
60 {
61     /*
62      * assert that one only registration is made per-node type
63      */
64     if (vec_len(fn_vfts) > type)
65         ASSERT(NULL == fn_vfts[type].fnv_get);
66
67     /*
68      * Assert that we are getting each of the required functions
69      */
70     ASSERT(NULL != vft->fnv_get);
71     ASSERT(NULL != vft->fnv_last_lock);
72
73     vec_validate(fn_vfts, type);
74     fn_vfts[type] = *vft;
75 }
76
77 fib_node_type_t
78 fib_node_register_new_type (const fib_node_vft_t *vft)
79 {
80     fib_node_type_t new_type;
81
82     new_type = ++last_new_type;
83
84     fib_node_register_type(new_type, vft);
85
86     return (new_type);
87 }   
88
89 static u8*
90 fib_node_format (fib_node_ptr_t *fnp, u8*s)
91 {
92     return (format(s, "{%s:%d}", fn_type_names[fnp->fnp_type], fnp->fnp_index)); 
93 }
94
95 u32
96 fib_node_child_add (fib_node_type_t parent_type,
97                     fib_node_index_t parent_index,
98                     fib_node_type_t type,
99                     fib_node_index_t index)
100 {
101     fib_node_t *parent;
102
103     parent = fn_vfts[parent_type].fnv_get(parent_index);
104
105     /*
106      * return the index of the sibling in the child list
107      */
108     fib_node_lock(parent);
109
110     if (FIB_NODE_INDEX_INVALID == parent->fn_children)
111     {
112         parent->fn_children = fib_node_list_create();
113     }   
114
115     return (fib_node_list_push_front(parent->fn_children,
116                                      0, type,
117                                      index));
118 }
119
120 void
121 fib_node_child_remove (fib_node_type_t parent_type,
122                        fib_node_index_t parent_index,
123                        fib_node_index_t sibling_index)
124 {
125     fib_node_t *parent;
126
127     parent = fn_vfts[parent_type].fnv_get(parent_index);
128
129     fib_node_list_remove(parent->fn_children, sibling_index);
130
131     if (0 == fib_node_list_get_size(parent->fn_children))
132     {
133         fib_node_list_destroy(&parent->fn_children);
134     }
135
136     fib_node_unlock(parent);
137 }
138
139
140 fib_node_back_walk_rc_t
141 fib_node_back_walk_one (fib_node_ptr_t *ptr,
142                         fib_node_back_walk_ctx_t *ctx)
143 {
144     fib_node_t *node;
145
146     node = fn_vfts[ptr->fnp_type].fnv_get(ptr->fnp_index);
147
148     return (fn_vfts[ptr->fnp_type].fnv_back_walk(node, ctx));
149 }
150
151 static int
152 fib_node_ptr_format_one_child (fib_node_ptr_t *ptr,
153                                void *arg)
154 {
155     u8 **s = (u8**) arg;
156
157     *s = fib_node_format(ptr, *s);
158
159     return (1);
160 }
161
162 u8*
163 fib_node_children_format (fib_node_list_t list,
164                           u8 *s)
165 {
166     fib_node_list_walk(list, fib_node_ptr_format_one_child, (void*)&s);
167
168     return (s);
169 }
170
171 void
172 fib_node_init (fib_node_t *node,
173                fib_node_type_t type)
174 {
175 #if CLIB_DEBUG > 0
176     /**
177      * The node's type. make sure we are dynamic/down casting correctly
178      */
179     node->fn_type = type;
180 #endif
181     node->fn_locks = 0;
182     node->fn_vft = &fn_vfts[type];
183     node->fn_children = FIB_NODE_INDEX_INVALID;
184 }
185
186 void
187 fib_node_deinit (fib_node_t *node)
188 {
189     fib_node_list_destroy(&node->fn_children);
190 }
191
192 void
193 fib_node_lock (fib_node_t *node)
194 {
195     node->fn_locks++;
196 }
197
198 void
199 fib_node_unlock (fib_node_t *node)
200 {
201     node->fn_locks--;
202
203     if (0 == node->fn_locks)
204     {
205         node->fn_vft->fnv_last_lock(node);
206     }
207 }