blob: 3326aba2f8653f473e772ba88d358f44eb7928a6 [file] [log] [blame]
Neale Rannsd792d9c2017-10-21 10:53:20 -07001/*
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 * bier_dispositon : The BIER dispositon object
17 *
18 * A BIER dispositon object is present in the IP mcast output list
19 * and represents the dispositon of a BIER bitmask. After BIER header
20 * dispositon the packet is forward within the appropriate/specifid
21 * BIER table
22 */
23
24#include <vnet/bier/bier_disp_entry.h>
25#include <vnet/bier/bier_hdr_inlines.h>
26#include <vnet/fib/fib_path_list.h>
27#include <vnet/dpo/drop_dpo.h>
28
29/**
30 * The memory pool of all imp objects
31 */
32bier_disp_entry_t *bier_disp_entry_pool;
33
34/**
35 * When constructing the BIER imp ID from an index and BSL, shift
36 * the BSL this far
37 */
38#define BIER_DISP_ENTRY_ID_HLEN_SHIFT 24
39
40static void
41bier_disp_entry_lock_i (bier_disp_entry_t *bde)
42{
43 bde->bde_locks++;
44}
45
46void
47bier_disp_entry_lock (index_t bdei)
48{
49 bier_disp_entry_lock_i(bier_disp_entry_get(bdei));
50}
51
52static index_t
53bier_disp_entry_get_index(bier_disp_entry_t *bde)
54{
55 return (bde - bier_disp_entry_pool);
56}
57
58index_t
59bier_disp_entry_add_or_lock (void)
60{
61 dpo_id_t invalid = DPO_INVALID;
62 bier_hdr_proto_id_t pproto;
63 bier_disp_entry_t *bde;
64
65 pool_get_aligned(bier_disp_entry_pool, bde, CLIB_CACHE_LINE_BYTES);
66
67 bde->bde_locks = 0;
68
69 FOR_EACH_BIER_HDR_PROTO(pproto)
70 {
71 bde->bde_fwd[pproto].bde_dpo = invalid;
72 bde->bde_fwd[pproto].bde_rpf_id = ~0;
73 bde->bde_pl[pproto] = FIB_NODE_INDEX_INVALID;
74 }
75
76 bier_disp_entry_lock_i(bde);
77 return (bier_disp_entry_get_index(bde));
78}
79
80void
81bier_disp_entry_unlock (index_t bdei)
82{
83 bier_disp_entry_t *bde;
84
85 if (INDEX_INVALID == bdei)
86 {
87 return;
88 }
89
90 bde = bier_disp_entry_get(bdei);
91
92 bde->bde_locks--;
93
94 if (0 == bde->bde_locks)
95 {
96 bier_hdr_proto_id_t pproto;
97
98 FOR_EACH_BIER_HDR_PROTO(pproto)
99 {
100 dpo_unlock(&bde->bde_fwd[pproto].bde_dpo);
101 bde->bde_fwd[pproto].bde_rpf_id = ~0;
102 fib_path_list_unlock(bde->bde_pl[pproto]);
103 }
104 pool_put(bier_disp_entry_pool, bde);
105 }
106}
107
108typedef struct bier_disp_entry_path_list_walk_ctx_t_
109{
110 u32 bdew_rpf_id;
111} bier_disp_entry_path_list_walk_ctx_t;
112
113static fib_path_list_walk_rc_t
114bier_disp_entry_path_list_walk (fib_node_index_t pl_index,
115 fib_node_index_t path_index,
116 void *arg)
117{
118 bier_disp_entry_path_list_walk_ctx_t *ctx = arg;
119
120 ctx->bdew_rpf_id = fib_path_get_rpf_id(path_index);
121
122 if (~0 != ctx->bdew_rpf_id)
123 {
124 return (FIB_PATH_LIST_WALK_STOP);
125 }
126 return (FIB_PATH_LIST_WALK_CONTINUE);
127}
128
129static void
130bier_disp_entry_restack (bier_disp_entry_t *bde,
131 bier_hdr_proto_id_t pproto)
132{
133 dpo_id_t via_dpo = DPO_INVALID;
134 fib_node_index_t pli;
135
136 pli = bde->bde_pl[pproto];
137
138 if (FIB_NODE_INDEX_INVALID == pli)
139 {
140 dpo_copy(&via_dpo,
141 drop_dpo_get(bier_hdr_proto_to_dpo(pproto)));
142 }
143 else
144 {
145 fib_path_list_contribute_forwarding(pli,
146 fib_forw_chain_type_from_dpo_proto(
147 bier_hdr_proto_to_dpo(pproto)),
148 &via_dpo);
149
150 bier_disp_entry_path_list_walk_ctx_t ctx = {
151 .bdew_rpf_id = ~0,
152 };
153
154 fib_path_list_walk(pli, bier_disp_entry_path_list_walk, &ctx);
155 bde->bde_fwd[pproto].bde_rpf_id = ctx.bdew_rpf_id;
156 }
157
158 dpo_stack(DPO_BIER_DISP_ENTRY,
159 DPO_PROTO_BIER,
160 &bde->bde_fwd[pproto].bde_dpo,
161 &via_dpo);
162}
163
164void
165bier_disp_entry_path_add (index_t bdei,
166 bier_hdr_proto_id_t pproto,
167 const fib_route_path_t *rpaths)
168{
169 fib_node_index_t *pli, old_pli;
170 bier_disp_entry_t *bde;
171
172 bde = bier_disp_entry_get(bdei);
173 pli = &bde->bde_pl[pproto];
174 old_pli = *pli;
175
176 /*
177 * create a new or update the exisitng path-list for this
178 * payload protocol
179 */
180 if (FIB_NODE_INDEX_INVALID == *pli)
181 {
182 *pli = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED |
183 FIB_PATH_LIST_FLAG_NO_URPF),
184 rpaths);
185 }
186 else
187 {
188 *pli = fib_path_list_copy_and_path_add(old_pli,
189 (FIB_PATH_LIST_FLAG_SHARED |
190 FIB_PATH_LIST_FLAG_NO_URPF),
191 rpaths);
192 }
193
194 fib_path_list_lock(*pli);
195 fib_path_list_unlock(old_pli);
196
197 bier_disp_entry_restack(bde, pproto);
198}
199
200int
201bier_disp_entry_path_remove (index_t bdei,
202 bier_hdr_proto_id_t pproto,
203 const fib_route_path_t *rpaths)
204{
205 fib_node_index_t *pli, old_pli;
206 bier_disp_entry_t *bde;
207
208 bde = bier_disp_entry_get(bdei);
209 pli = &bde->bde_pl[pproto];
210 old_pli = *pli;
211
212 /*
213 * update the exisitng path-list for this payload protocol
214 */
215 if (FIB_NODE_INDEX_INVALID != *pli)
216 {
217 *pli = fib_path_list_copy_and_path_remove(old_pli,
218 (FIB_PATH_LIST_FLAG_SHARED |
219 FIB_PATH_LIST_FLAG_NO_URPF),
220 rpaths);
221
222 fib_path_list_lock(*pli);
223 fib_path_list_unlock(old_pli);
224
225 bier_disp_entry_restack(bde, pproto);
226 }
227
228 /*
229 * if there are no path-list defined for any payload protocol
230 * then this entry is OK for removal
231 */
232 int remove = 1;
233
234 FOR_EACH_BIER_HDR_PROTO(pproto)
235 {
236 if (FIB_NODE_INDEX_INVALID != bde->bde_pl[pproto])
237 {
238 remove = 0;
239 break;
240 }
241 }
242
243 return (remove);
244}
245
246u8*
247format_bier_disp_entry (u8* s, va_list *args)
248{
249 index_t bdei = va_arg (*args, index_t);
250 u32 indent = va_arg(*args, u32);
251 bier_show_flags_t flags = va_arg(*args, bier_show_flags_t);
252 bier_hdr_proto_id_t pproto;
253 bier_disp_entry_t *bde;
254
255 bde = bier_disp_entry_get(bdei);
256
257 s = format(s, "bier-disp:[%d]", bdei);
258
259 FOR_EACH_BIER_HDR_PROTO(pproto)
260 {
261 if (INDEX_INVALID != bde->bde_pl[pproto])
262 {
263 s = format(s, "\n");
264 s = fib_path_list_format(bde->bde_pl[pproto], s);
265
266 if (flags & BIER_SHOW_DETAIL)
267 {
268 s = format(s, "\n%UForwarding:",
269 format_white_space, indent);
270 s = format(s, "\n%Urpf-id:%d",
271 format_white_space, indent+1,
272 bde->bde_fwd[pproto].bde_rpf_id);
273 s = format(s, "\n%U%U",
274 format_white_space, indent+1,
275 format_dpo_id, &bde->bde_fwd[pproto].bde_dpo, indent+2);
276 }
277 }
278 }
279 return (s);
280}
281
282void
283bier_disp_entry_contribute_forwarding (index_t bdei,
284 dpo_id_t *dpo)
285{
286 dpo_set(dpo, DPO_BIER_DISP_ENTRY, DPO_PROTO_BIER, bdei);
287}
288
289const static char* const bier_disp_entry_bier_nodes[] =
290{
291 "bier-disp-dispatch",
292 NULL,
293};
294
295const static char* const * const bier_disp_entry_nodes[DPO_PROTO_NUM] =
296{
297 [DPO_PROTO_BIER] = bier_disp_entry_bier_nodes,
298};
299
300static void
301bier_disp_entry_dpo_lock (dpo_id_t *dpo)
302{
303 bier_disp_entry_lock(dpo->dpoi_index);
304}
305
306static void
307bier_disp_entry_dpo_unlock (dpo_id_t *dpo)
308{
309 bier_disp_entry_unlock(dpo->dpoi_index);
310}
311
312static void
313bier_disp_entry_dpo_mem_show (void)
314{
315 fib_show_memory_usage("BIER dispositon",
316 pool_elts(bier_disp_entry_pool),
317 pool_len(bier_disp_entry_pool),
318 sizeof(bier_disp_entry_t));
319}
320
321static u8*
322format_bier_disp_entry_dpo (u8* s, va_list *ap)
323{
324 index_t index = va_arg(*ap, index_t);
325 u32 indent = va_arg(*ap, u32);
326
327 s = format(s, "%U", format_bier_disp_entry, index, indent, BIER_SHOW_DETAIL);
328
329 return (s);
330}
331
332const static dpo_vft_t bier_disp_entry_vft = {
333 .dv_lock = bier_disp_entry_dpo_lock,
334 .dv_unlock = bier_disp_entry_dpo_unlock,
335 .dv_format = format_bier_disp_entry_dpo,
336 .dv_mem_show = bier_disp_entry_dpo_mem_show,
337};
338
339clib_error_t *
340bier_disp_entry_db_module_init (vlib_main_t *vm)
341{
342 dpo_register(DPO_BIER_DISP_ENTRY,
343 &bier_disp_entry_vft,
344 bier_disp_entry_nodes);
345
346 return (NULL);
347}
348
349VLIB_INIT_FUNCTION (bier_disp_entry_db_module_init);
350
351static clib_error_t *
352show_bier_disp_entry (vlib_main_t * vm,
353 unformat_input_t * input,
354 vlib_cli_command_t * cmd)
355{
356 index_t bdei;
357
358 bdei = INDEX_INVALID;
359
360 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
361 if (unformat (input, "%d", &bdei))
362 ;
363 else
364 {
365 break;
366 }
367 }
368
369 if (INDEX_INVALID == bdei)
370 {
371 return (NULL);
372 }
373 else
374 {
375 vlib_cli_output(vm, "%U", format_bier_disp_entry, bdei, 1,
376 BIER_SHOW_DETAIL);
377 }
378 return (NULL);
379}
380
381VLIB_CLI_COMMAND (show_bier_disp_entry_node, static) = {
382 .path = "show bier disp entry",
383 .short_help = "show bier disp entry index",
384 .function = show_bier_disp_entry,
385};