VOM: mroutes
[vpp.git] / src / 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 #include <vnet/fib/fib_table.h>
19 #include <vnet/mfib/mfib_table.h>
20
21 /*
22  * The per-type vector of virtual function tables
23  */
24 static fib_node_vft_t *fn_vfts;
25
26 /**
27  * The last registered new type
28  */
29 static fib_node_type_t last_new_type = FIB_NODE_TYPE_LAST;
30
31 /*
32  * the node type names
33  */
34 static const char *fn_type_names[] = FIB_NODE_TYPES;
35
36 const char*
37 fib_node_type_get_name (fib_node_type_t type)
38 {
39     if (type < FIB_NODE_TYPE_LAST)
40         return (fn_type_names[type]);
41     else
42     {
43         if (NULL != fn_vfts[type].fnv_format)
44         {
45             return ("fixme");
46         }
47         else
48         {
49             return ("unknown");
50         }
51     }
52 }
53
54 /**
55  * fib_node_register_type
56  *
57  * Register the function table for a given type
58  */
59 void
60 fib_node_register_type (fib_node_type_t type,
61                         const fib_node_vft_t *vft)
62 {
63     /*
64      * assert that one only registration is made per-node type
65      */
66     if (vec_len(fn_vfts) > type)
67         ASSERT(NULL == fn_vfts[type].fnv_get);
68
69     /*
70      * Assert that we are getting each of the required functions
71      */
72     ASSERT(NULL != vft->fnv_get);
73     ASSERT(NULL != vft->fnv_last_lock);
74
75     vec_validate(fn_vfts, type);
76     fn_vfts[type] = *vft;
77 }
78
79 fib_node_type_t
80 fib_node_register_new_type (const fib_node_vft_t *vft)
81 {
82     fib_node_type_t new_type;
83
84     new_type = ++last_new_type;
85
86     fib_node_register_type(new_type, vft);
87
88     return (new_type);
89 }   
90
91 static u8*
92 fib_node_format (fib_node_ptr_t *fnp, u8*s)
93 {
94     return (format(s, "{%s:%d}", fn_type_names[fnp->fnp_type], fnp->fnp_index)); 
95 }
96
97 u32
98 fib_node_child_add (fib_node_type_t parent_type,
99                     fib_node_index_t parent_index,
100                     fib_node_type_t type,
101                     fib_node_index_t index)
102 {
103     fib_node_t *parent;
104
105     parent = fn_vfts[parent_type].fnv_get(parent_index);
106
107     /*
108      * return the index of the sibling in the child list
109      */
110     fib_node_lock(parent);
111
112     if (FIB_NODE_INDEX_INVALID == parent->fn_children)
113     {
114         parent->fn_children = fib_node_list_create();
115     }   
116
117     return (fib_node_list_push_front(parent->fn_children,
118                                      0, type,
119                                      index));
120 }
121
122 void
123 fib_node_child_remove (fib_node_type_t parent_type,
124                        fib_node_index_t parent_index,
125                        fib_node_index_t sibling_index)
126 {
127     fib_node_t *parent;
128
129     parent = fn_vfts[parent_type].fnv_get(parent_index);
130
131     fib_node_list_remove(parent->fn_children, sibling_index);
132
133     if (0 == fib_node_list_get_size(parent->fn_children))
134     {
135         fib_node_list_destroy(&parent->fn_children);
136     }
137
138     fib_node_unlock(parent);
139 }
140
141 u32
142 fib_node_get_n_children (fib_node_type_t parent_type,
143                          fib_node_index_t parent_index)
144 {
145     fib_node_t *parent;
146
147     parent = fn_vfts[parent_type].fnv_get(parent_index);
148
149     return (fib_node_list_get_size(parent->fn_children));
150 }
151
152
153 fib_node_back_walk_rc_t
154 fib_node_back_walk_one (fib_node_ptr_t *ptr,
155                         fib_node_back_walk_ctx_t *ctx)
156 {
157     fib_node_t *node;
158
159     node = fn_vfts[ptr->fnp_type].fnv_get(ptr->fnp_index);
160
161     return (fn_vfts[ptr->fnp_type].fnv_back_walk(node, ctx));
162 }
163
164 static int
165 fib_node_ptr_format_one_child (fib_node_ptr_t *ptr,
166                                void *arg)
167 {
168     u8 **s = (u8**) arg;
169
170     *s = fib_node_format(ptr, *s);
171
172     return (1);
173 }
174
175 u8*
176 fib_node_children_format (fib_node_list_t list,
177                           u8 *s)
178 {
179     fib_node_list_walk(list, fib_node_ptr_format_one_child, (void*)&s);
180
181     return (s);
182 }
183
184 void
185 fib_node_init (fib_node_t *node,
186                fib_node_type_t type)
187 {
188     /**
189      * The node's type. used to retrieve the VFT.
190      */
191     node->fn_type = type;
192     node->fn_locks = 0;
193     node->fn_children = FIB_NODE_INDEX_INVALID;
194 }
195
196 void
197 fib_node_deinit (fib_node_t *node)
198 {
199     fib_node_list_destroy(&node->fn_children);
200 }
201
202 void
203 fib_node_lock (fib_node_t *node)
204 {
205     node->fn_locks++;
206 }
207
208 void
209 fib_node_unlock (fib_node_t *node)
210 {
211     node->fn_locks--;
212
213     if (0 == node->fn_locks)
214     {
215         fn_vfts[node->fn_type].fnv_last_lock(node);
216     }
217 }
218
219 void
220 fib_show_memory_usage (const char *name,
221                        u32 in_use_elts,
222                        u32 allocd_elts,
223                        size_t size_elt)
224 {
225     vlib_cli_output (vlib_get_main(), "%=30s %=5d %=8d/%=9d   %d/%d ",
226                      name, size_elt,
227                      in_use_elts, allocd_elts,
228                      in_use_elts*size_elt, allocd_elts*size_elt);
229 }
230
231 static clib_error_t *
232 fib_memory_show (vlib_main_t * vm,
233                  unformat_input_t * input,
234                  vlib_cli_command_t * cmd)
235 {
236     fib_node_vft_t *vft;
237
238     vlib_cli_output (vm, "FIB memory");
239     vlib_cli_output (vm, "  Tables:");
240     vlib_cli_output (vm, "%=30s %=6s %=8s", "SAFI", "Number", "Bytes");
241     vlib_cli_output (vm, "%U", format_fib_table_memory);
242     vlib_cli_output (vm, "%U", format_mfib_table_memory);
243     vlib_cli_output (vm, "  Nodes:");
244     vlib_cli_output (vm, "%=30s %=5s %=8s/%=9s   totals",
245                      "Name","Size", "in-use", "allocated");
246
247     vec_foreach(vft, fn_vfts)
248     {
249         if (NULL != vft->fnv_mem_show)
250             vft->fnv_mem_show();
251     }
252
253     fib_node_list_memory_show();
254
255     return (NULL);
256 }
257
258 /* *INDENT-OFF* */
259 /*?
260  * The '<em>sh fib memory </em>' command displays the memory usage for each
261  * FIB object type.
262  *
263  * @cliexpar
264  * @cliexstart{show fib memory}
265  *FIB memory
266  * Tables:
267  *            SAFI              Number   Bytes
268  *        IPv4 unicast             2    673066
269  *        IPv6 unicast             2    1054608
270  *            MPLS                 1    4194312
271  *       IPv4 multicast            2     2322
272  *       IPv6 multicast            2      ???
273  * Nodes:
274  *            Name               Size  in-use /allocated   totals
275  *            Entry               96     20   /    20      1920/1920
276  *        Entry Source            32      0   /    0       0/0
277  *    Entry Path-Extensions       60      0   /    0       0/0
278  *       multicast-Entry         192     12   /    12      2304/2304
279  *          Path-list             40     28   /    28      1120/1120
280  *          uRPF-list             16     20   /    20      320/320
281  *            Path                72     28   /    28      2016/2016
282  *     Node-list elements         20     28   /    28      560/560
283  *       Node-list heads          8      30   /    30      240/240
284  * @cliexend
285 ?*/
286 VLIB_CLI_COMMAND (show_fib_memory, static) = {
287     .path = "show fib memory",
288     .function = fib_memory_show,
289     .short_help = "show fib memory",
290 };
291 /* *INDENT-ON* */