blob: 2fe2e4ab9095ec37494869206c7b032907570420 [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)),
Neale Ranns91286372017-12-05 13:24:04 -0800148 FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700149 &via_dpo);
150
151 bier_disp_entry_path_list_walk_ctx_t ctx = {
152 .bdew_rpf_id = ~0,
153 };
154
155 fib_path_list_walk(pli, bier_disp_entry_path_list_walk, &ctx);
156 bde->bde_fwd[pproto].bde_rpf_id = ctx.bdew_rpf_id;
157 }
158
159 dpo_stack(DPO_BIER_DISP_ENTRY,
160 DPO_PROTO_BIER,
161 &bde->bde_fwd[pproto].bde_dpo,
162 &via_dpo);
163}
164
165void
166bier_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 bde = bier_disp_entry_get(bdei);
174 pli = &bde->bde_pl[pproto];
175 old_pli = *pli;
176
177 /*
178 * create a new or update the exisitng path-list for this
179 * payload protocol
180 */
181 if (FIB_NODE_INDEX_INVALID == *pli)
182 {
183 *pli = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED |
184 FIB_PATH_LIST_FLAG_NO_URPF),
185 rpaths);
186 }
187 else
188 {
189 *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 fib_path_list_lock(*pli);
196 fib_path_list_unlock(old_pli);
197
198 bier_disp_entry_restack(bde, pproto);
199}
200
201int
202bier_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 bde = bier_disp_entry_get(bdei);
210 pli = &bde->bde_pl[pproto];
211 old_pli = *pli;
212
213 /*
214 * update the exisitng path-list for this payload protocol
215 */
216 if (FIB_NODE_INDEX_INVALID != *pli)
217 {
218 *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 fib_path_list_lock(*pli);
224 fib_path_list_unlock(old_pli);
225
226 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 int remove = 1;
234
235 FOR_EACH_BIER_HDR_PROTO(pproto)
236 {
237 if (FIB_NODE_INDEX_INVALID != bde->bde_pl[pproto])
238 {
239 remove = 0;
240 break;
241 }
242 }
243
244 return (remove);
245}
246
247u8*
248format_bier_disp_entry (u8* s, va_list *args)
249{
250 index_t bdei = va_arg (*args, index_t);
251 u32 indent = va_arg(*args, u32);
252 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 bde = bier_disp_entry_get(bdei);
257
Neale Ranns91286372017-12-05 13:24:04 -0800258 s = format(s, "%Ubier-disp:[%d]", format_white_space, indent, bdei);
Neale Rannsd792d9c2017-10-21 10:53:20 -0700259
260 FOR_EACH_BIER_HDR_PROTO(pproto)
261 {
262 if (INDEX_INVALID != bde->bde_pl[pproto])
263 {
Neale Ranns91286372017-12-05 13:24:04 -0800264 s = format(s, "\n%U%U\n",
265 format_white_space, indent+2,
266 format_bier_hdr_proto, pproto);
267 s = format(s, "%U", format_fib_path_list, bde->bde_pl[pproto], indent+4);
Neale Rannsd792d9c2017-10-21 10:53:20 -0700268
269 if (flags & BIER_SHOW_DETAIL)
270 {
271 s = format(s, "\n%UForwarding:",
Neale Ranns91286372017-12-05 13:24:04 -0800272 format_white_space, indent+4);
Neale Rannsd792d9c2017-10-21 10:53:20 -0700273 s = format(s, "\n%Urpf-id:%d",
Neale Ranns91286372017-12-05 13:24:04 -0800274 format_white_space, indent+6,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700275 bde->bde_fwd[pproto].bde_rpf_id);
276 s = format(s, "\n%U%U",
Neale Ranns91286372017-12-05 13:24:04 -0800277 format_white_space, indent+6,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700278 format_dpo_id, &bde->bde_fwd[pproto].bde_dpo, indent+2);
279 }
280 }
281 }
282 return (s);
283}
284
285void
286bier_disp_entry_contribute_forwarding (index_t bdei,
287 dpo_id_t *dpo)
288{
289 dpo_set(dpo, DPO_BIER_DISP_ENTRY, DPO_PROTO_BIER, bdei);
290}
291
292const static char* const bier_disp_entry_bier_nodes[] =
293{
294 "bier-disp-dispatch",
295 NULL,
296};
297
298const static char* const * const bier_disp_entry_nodes[DPO_PROTO_NUM] =
299{
300 [DPO_PROTO_BIER] = bier_disp_entry_bier_nodes,
301};
302
303static void
304bier_disp_entry_dpo_lock (dpo_id_t *dpo)
305{
306 bier_disp_entry_lock(dpo->dpoi_index);
307}
308
309static void
310bier_disp_entry_dpo_unlock (dpo_id_t *dpo)
311{
312 bier_disp_entry_unlock(dpo->dpoi_index);
313}
314
315static void
316bier_disp_entry_dpo_mem_show (void)
317{
318 fib_show_memory_usage("BIER dispositon",
319 pool_elts(bier_disp_entry_pool),
320 pool_len(bier_disp_entry_pool),
321 sizeof(bier_disp_entry_t));
322}
323
324static u8*
325format_bier_disp_entry_dpo (u8* s, va_list *ap)
326{
327 index_t index = va_arg(*ap, index_t);
328 u32 indent = va_arg(*ap, u32);
329
330 s = format(s, "%U", format_bier_disp_entry, index, indent, BIER_SHOW_DETAIL);
331
332 return (s);
333}
334
335const 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
342clib_error_t *
343bier_disp_entry_db_module_init (vlib_main_t *vm)
344{
345 dpo_register(DPO_BIER_DISP_ENTRY,
346 &bier_disp_entry_vft,
347 bier_disp_entry_nodes);
348
349 return (NULL);
350}
351
352VLIB_INIT_FUNCTION (bier_disp_entry_db_module_init);
353
354static clib_error_t *
355show_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 bdei = INDEX_INVALID;
362
363 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
364 if (unformat (input, "%d", &bdei))
365 ;
366 else
367 {
368 break;
369 }
370 }
371
372 if (INDEX_INVALID == bdei)
373 {
374 return (NULL);
375 }
376 else
377 {
378 vlib_cli_output(vm, "%U", format_bier_disp_entry, bdei, 1,
379 BIER_SHOW_DETAIL);
380 }
381 return (NULL);
382}
383
384VLIB_CLI_COMMAND (show_bier_disp_entry_node, static) = {
385 .path = "show bier disp entry",
386 .short_help = "show bier disp entry index",
387 .function = show_bier_disp_entry,
388};