BIER: fix support for longer bit-string lengths
[vpp.git] / src / vnet / bier / bier_disp_table.c
1 /*
2  * Copyright (c) 2017 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/bier/bier_disp_table.h>
17 #include <vnet/bier/bier_disp_entry.h>
18
19 /**
20  * memory pool for disposition tables
21  */
22 bier_disp_table_t *bier_disp_table_pool;
23
24 /**
25  * Hash table to map client table IDs to VPP index
26  */
27 static uword *bier_disp_table_id_to_index;
28
29 static index_t
30 bier_disp_table_get_index (const bier_disp_table_t *bdt)
31 {
32     return (bdt - bier_disp_table_pool);
33 }
34
35 static void
36 bier_disp_table_lock_i (bier_disp_table_t *bdt)
37 {
38     bdt->bdt_locks++;
39 }
40
41 index_t
42 bier_disp_table_find(u32 table_id)
43 {
44     uword *p;
45
46     p = hash_get(bier_disp_table_id_to_index, table_id);
47
48     if (NULL != p)
49     {
50         return (p[0]);
51     }
52
53     return (INDEX_INVALID);
54 }
55
56 index_t
57 bier_disp_table_add_or_lock (u32 table_id)
58 {
59     bier_disp_table_t *bdt;
60     index_t bdti;
61
62     bdti = bier_disp_table_find(table_id);
63
64     if (INDEX_INVALID == bdti)
65     {
66         pool_get_aligned(bier_disp_table_pool, bdt,
67                          CLIB_CACHE_LINE_BYTES);
68
69         bdt->bdt_table_id = table_id;
70         bdt->bdt_locks = 0;
71
72         hash_set(bier_disp_table_id_to_index, table_id,
73                  bier_disp_table_get_index(bdt));
74
75         /**
76          * Set the result for each entry in the DB to be invalid
77          */
78         memset(bdt->bdt_db, 0xff, sizeof(bdt->bdt_db));
79     }
80     else
81     {
82         bdt = pool_elt_at_index(bier_disp_table_pool, bdti);
83     }
84
85     bier_disp_table_lock_i(bdt);
86
87     return (bier_disp_table_get_index(bdt));
88 }
89
90 void
91 bier_disp_table_unlock_w_table_id (u32 table_id)
92 {
93     index_t bdti;
94
95     bdti = bier_disp_table_find(table_id);
96
97     if (INDEX_INVALID != bdti)
98     {
99         bier_disp_table_unlock(bdti);
100     }
101 }
102
103 void
104 bier_disp_table_unlock (index_t bdti)
105 {
106     bier_disp_table_t *bdt;
107
108     bdt = bier_disp_table_get(bdti);
109
110     bdt->bdt_locks--;
111
112     if (0 == bdt->bdt_locks)
113     {
114         u32 ii;
115
116         for (ii = 0; ii < BIER_BP_MAX; ii++)
117         {
118             bier_disp_entry_unlock(bdt->bdt_db[ii]);
119         }
120         hash_unset(bier_disp_table_id_to_index, bdt->bdt_table_id);
121         pool_put(bier_disp_table_pool, bdt);
122     }
123 }
124
125 void
126 bier_disp_table_lock (index_t bdti)
127 {
128     bier_disp_table_lock_i(bier_disp_table_get(bdti));
129 }
130
131 void
132 bier_disp_table_contribute_forwarding (index_t bdti,
133                                        dpo_id_t *dpo)
134 {
135     dpo_set(dpo,
136             DPO_BIER_DISP_TABLE,
137             DPO_PROTO_BIER,
138             bdti);
139 }
140
141
142 u8*
143 format_bier_disp_table (u8* s, va_list *ap)
144 {
145     index_t bdti = va_arg(*ap, index_t);
146     u32 indent = va_arg(*ap, u32);
147     bier_show_flags_t flags = va_arg(*ap, bier_show_flags_t);
148     bier_disp_table_t *bdt;
149
150     bdt = bier_disp_table_get(bdti);
151
152     s = format(s, "bier-disp-table:[%d]; table-id:%d locks:%d",
153                bdti, bdt->bdt_table_id, bdt->bdt_locks);
154
155     if (flags & BIER_SHOW_DETAIL)
156     {
157         u32 ii;
158
159         for (ii = 0; ii < BIER_BP_MAX; ii++)
160         {
161             if (INDEX_INVALID != bdt->bdt_db[ii])
162             {
163                 u16 src = ii;
164                 s = format(s, "\n%Usrc:%d", format_white_space, indent+1,
165                            clib_host_to_net_u16(src));
166                 s = format(s, "\n%U",
167                            format_bier_disp_entry, bdt->bdt_db[ii],
168                            indent+4, BIER_SHOW_BRIEF);
169             }
170         }
171     }
172     return (s);
173 }
174
175 static u8*
176 format_bier_disp_table_dpo (u8* s, va_list *ap)
177 {
178     index_t bdti = va_arg(*ap, index_t);
179     u32 indent = va_arg(*ap, u32);
180
181     return (format(s, "%U",
182                    format_bier_disp_table, bdti, indent,
183                    BIER_SHOW_BRIEF));
184 }
185
186 static void
187 bier_disp_table_entry_insert (index_t bdti,
188                               bier_bp_t src,
189                               index_t bdei)
190 {
191     bier_disp_table_t *bdt;
192
193     bdt = bier_disp_table_get(bdti);
194     bdt->bdt_db[clib_host_to_net_u16(src)] = bdei;
195 }
196
197 static void
198 bier_disp_table_entry_remove (index_t bdti,
199                               bier_bp_t src)
200 {
201     bier_disp_table_t *bdt;
202
203     bdt = bier_disp_table_get(bdti);
204     bdt->bdt_db[clib_host_to_net_u16(src)] = INDEX_INVALID;
205 }
206
207 static index_t
208 bier_disp_table_lookup_hton(index_t bdti,
209                             bier_bp_t bp)
210 {
211     bier_hdr_src_id_t src = bp;
212
213     return (bier_disp_table_lookup(bdti, clib_host_to_net_u16(src)));
214 }
215
216 void
217 bier_disp_table_entry_path_add (u32 table_id,
218                                 bier_bp_t src,
219                                 bier_hdr_proto_id_t payload_proto,
220                                 const fib_route_path_t *rpaths)
221 {
222     index_t bdti, bdei;
223
224     bdti = bier_disp_table_find(table_id);
225
226     if (INDEX_INVALID == bdti)
227     {
228         return;
229     }
230
231     bdei = bier_disp_table_lookup_hton(bdti, src);
232
233     if (INDEX_INVALID == bdei)
234     {
235         bdei = bier_disp_entry_add_or_lock();
236         bier_disp_table_entry_insert(bdti, src, bdei);
237     }
238
239     bier_disp_entry_path_add(bdei, payload_proto, rpaths);
240 }
241
242 void
243 bier_disp_table_entry_path_remove (u32 table_id,
244                                    bier_bp_t src,
245                                    bier_hdr_proto_id_t payload_proto,
246                                    const fib_route_path_t *rpath)
247 {
248     index_t bdti, bdei;
249
250     bdti = bier_disp_table_find(table_id);
251
252     if (INDEX_INVALID == bdti)
253     {
254         return;
255     }
256
257     bdei = bier_disp_table_lookup_hton(bdti, src);
258
259     if (INDEX_INVALID != bdei)
260     {
261         int remove;
262
263         remove = bier_disp_entry_path_remove(bdei, payload_proto, rpath);
264
265         if (remove)
266         {
267             bier_disp_table_entry_remove(bdti, src);
268             bier_disp_entry_unlock(bdei);
269         }
270     }
271 }
272
273 void
274 bier_disp_table_walk (u32 table_id,
275                       bier_disp_table_walk_fn_t fn,
276                       void *ctx)
277 {
278     const bier_disp_table_t *bdt;
279     const bier_disp_entry_t *bde;
280     index_t bdti;
281     u32 ii;
282
283     bdti = bier_disp_table_find(table_id);
284
285     if (INDEX_INVALID != bdti)
286     {
287         bdt = bier_disp_table_get(bdti);
288
289         for (ii = 0; ii < BIER_BP_MAX; ii++)
290         {
291             if (INDEX_INVALID != bdt->bdt_db[ii])
292             {
293                 u16 src = ii;
294
295                 bde = bier_disp_entry_get(bdt->bdt_db[ii]);
296
297                 fn(bdt, bde, clib_host_to_net_u16(src), ctx);
298             }
299         }
300     }
301 }
302
303 static void
304 bier_disp_table_dpo_lock (dpo_id_t *dpo)
305 {
306     bier_disp_table_lock(dpo->dpoi_index);
307 }
308
309 static void
310 bier_disp_table_dpo_unlock (dpo_id_t *dpo)
311 {
312     bier_disp_table_unlock(dpo->dpoi_index);
313 }
314
315 static void
316 bier_disp_table_dpo_mem_show (void)
317 {
318     fib_show_memory_usage("BIER disposition table",
319                           pool_elts(bier_disp_table_pool),
320                           pool_len(bier_disp_table_pool),
321                           sizeof(bier_disp_table_t));
322 }
323
324 const static dpo_vft_t bier_disp_table_dpo_vft = {
325     .dv_lock = bier_disp_table_dpo_lock,
326     .dv_unlock = bier_disp_table_dpo_unlock,
327     .dv_mem_show = bier_disp_table_dpo_mem_show,
328     .dv_format = format_bier_disp_table_dpo,
329 };
330
331 const static char *const bier_disp_table_bier_nodes[] =
332 {
333     "bier-disp-lookup",
334     NULL
335 };
336
337 const static char * const * const bier_disp_table_nodes[DPO_PROTO_NUM] =
338 {
339     [DPO_PROTO_BIER] = bier_disp_table_bier_nodes,
340 };
341
342 clib_error_t *
343 bier_disp_table_module_init (vlib_main_t *vm)
344 {
345     dpo_register(DPO_BIER_DISP_TABLE,
346                  &bier_disp_table_dpo_vft,
347                  bier_disp_table_nodes);
348
349     bier_disp_table_id_to_index = hash_create(0, sizeof(index_t));
350
351     return (NULL);
352 }
353
354 VLIB_INIT_FUNCTION (bier_disp_table_module_init);
355
356 static clib_error_t *
357 show_bier_disp_table (vlib_main_t * vm,
358                       unformat_input_t * input,
359                       vlib_cli_command_t * cmd)
360 {
361     bier_disp_table_t *bdt;
362     index_t bdti;
363
364     bdti = INDEX_INVALID;
365
366     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
367         if (unformat (input, "%d", &bdti))
368             ;
369         else if (unformat (input, "%d", &bdti))
370             ;
371         else
372         {
373             break;
374         }
375     }
376
377     if (INDEX_INVALID == bdti)
378     {
379         pool_foreach(bdt, bier_disp_table_pool,
380         ({
381             vlib_cli_output(vm, "%U", format_bier_disp_table,
382                             bier_disp_table_get_index(bdt),
383                             0, BIER_SHOW_BRIEF);
384         }));
385     }
386     else
387     {
388         vlib_cli_output(vm, "%U", format_bier_disp_table, bdti, 0,
389                         BIER_SHOW_DETAIL);
390     }
391     return (NULL);
392 }
393
394 VLIB_CLI_COMMAND (show_bier_disp_table_node, static) = {
395     .path = "show bier disp table",
396     .short_help = "show bier disp table [index]",
397     .function = show_bier_disp_table,
398 };