dpdk: Add support for Mellanox ConnectX-4 devices
[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
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 u32
140 fib_node_get_n_children (fib_node_type_t parent_type,
141                          fib_node_index_t parent_index)
142 {
143     fib_node_t *parent;
144
145     parent = fn_vfts[parent_type].fnv_get(parent_index);
146
147     return (fib_node_list_get_size(parent->fn_children));
148 }
149
150
151 fib_node_back_walk_rc_t
152 fib_node_back_walk_one (fib_node_ptr_t *ptr,
153                         fib_node_back_walk_ctx_t *ctx)
154 {
155     fib_node_t *node;
156
157     node = fn_vfts[ptr->fnp_type].fnv_get(ptr->fnp_index);
158
159     return (fn_vfts[ptr->fnp_type].fnv_back_walk(node, ctx));
160 }
161
162 static int
163 fib_node_ptr_format_one_child (fib_node_ptr_t *ptr,
164                                void *arg)
165 {
166     u8 **s = (u8**) arg;
167
168     *s = fib_node_format(ptr, *s);
169
170     return (1);
171 }
172
173 u8*
174 fib_node_children_format (fib_node_list_t list,
175                           u8 *s)
176 {
177     fib_node_list_walk(list, fib_node_ptr_format_one_child, (void*)&s);
178
179     return (s);
180 }
181
182 void
183 fib_node_init (fib_node_t *node,
184                fib_node_type_t type)
185 {
186 #if CLIB_DEBUG > 0
187     /**
188      * The node's type. make sure we are dynamic/down casting correctly
189      */
190     node->fn_type = type;
191 #endif
192     node->fn_locks = 0;
193     node->fn_vft = &fn_vfts[type];
194     node->fn_children = FIB_NODE_INDEX_INVALID;
195 }
196
197 void
198 fib_node_deinit (fib_node_t *node)
199 {
200     fib_node_list_destroy(&node->fn_children);
201 }
202
203 void
204 fib_node_lock (fib_node_t *node)
205 {
206     node->fn_locks++;
207 }
208
209 void
210 fib_node_unlock (fib_node_t *node)
211 {
212     node->fn_locks--;
213
214     if (0 == node->fn_locks)
215     {
216         node->fn_vft->fnv_last_lock(node);
217     }
218 }
219
220 void
221 fib_show_memory_usage (const char *name,
222                        u32 in_use_elts,
223                        u32 allocd_elts,
224                        size_t size_elt)
225 {
226     vlib_cli_output (vlib_get_main(), "%=30s %=5d %=8d/%=9d   %d/%d ",
227                      name, size_elt,
228                      in_use_elts, allocd_elts,
229                      in_use_elts*size_elt, allocd_elts*size_elt);
230 }
231
232 static clib_error_t *
233 fib_memory_show (vlib_main_t * vm,
234                  unformat_input_t * input,
235                  vlib_cli_command_t * cmd)
236 {
237     fib_node_vft_t *vft;
238
239     vlib_cli_output (vm, "FIB memory");
240     vlib_cli_output (vm, "%=30s %=5s %=8s/%=9s   totals",
241                      "Name","Size", "in-use", "allocated");
242
243     vec_foreach(vft, fn_vfts)
244     {
245         if (NULL != vft->fnv_mem_show)
246             vft->fnv_mem_show();
247     }
248
249     fib_node_list_memory_show();
250
251     return (NULL);
252 }
253
254 /* *INDENT-OFF* */
255 /*?
256  * The '<em>sh fib memory </em>' command displays the memory usage for each
257  * FIB object type.
258  *
259  * @cliexpar
260  * @cliexstart{show fib memory}
261  * FIB memory
262  *             Name               Size  in-use /allocated   totals
263  *             Entry              120     11   /    11      1320/1320
264  *         Entry Source            32     11   /    11      352/352
265  *     Entry Path-Extensions       44      0   /    0       0/0
266  *           Path-list             40     11   /    11      440/440
267  *             Path                88     11   /    11      968/968
268  *      Node-list elements         20     11   /    11      220/220
269  *        Node-list heads          8      13   /    13      104/104
270  * @cliexend
271 ?*/
272 VLIB_CLI_COMMAND (show_fib_memory, static) = {
273     .path = "show fib memory",
274     .function = fib_memory_show,
275     .short_help = "show fib memory",
276 };
277 /* *INDENT-ON* */