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