blob: 80f7cfd8e56d431b92e4e7cb041b6deb055ca5aa [file] [log] [blame]
Neale Rannsd792d9c2017-10-21 10:53:20 -07001/*
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/bier/bier_entry.h>
17#include <vnet/bier/bier_update.h>
18
19#include <vnet/fib/fib_path_list.h>
20
21#include <vnet/bier/bier_fmask_db.h>
22#include <vnet/bier/bier_fmask.h>
23#include <vnet/bier/bier_table.h>
24
25bier_entry_t *bier_entry_pool;
26
27static index_t
28bier_entry_get_index (const bier_entry_t *be)
29{
30 return (be - bier_entry_pool);
31}
32
33static fib_path_list_walk_rc_t
34bier_entry_link_walk (fib_node_index_t pl_index,
35 fib_node_index_t path_index,
36 void *arg)
37{
38 bier_entry_t *be = arg;
39 index_t bfmi;
40
41 bfmi = fib_path_get_resolving_index(path_index);
42 bier_fmask_link(bfmi, be->be_bp);
43
44 return (FIB_PATH_LIST_WALK_CONTINUE);
45}
46
47static fib_path_list_walk_rc_t
48bier_entry_unlink_walk (fib_node_index_t pl_index,
49 fib_node_index_t path_index,
50 void *arg)
51{
52 bier_entry_t *be = arg;
53 index_t bfmi;
54
55 bfmi = fib_path_get_resolving_index(path_index);
56 bier_fmask_unlink(bfmi, be->be_bp);
57
58 return (FIB_PATH_LIST_WALK_CONTINUE);
59}
60
61index_t
62bier_entry_create (index_t bti,
63 bier_bp_t bp)
64{
65 bier_entry_t *be;
66
67 pool_get(bier_entry_pool, be);
68
69 be->be_bp = bp;
70 be->be_bti = bti;
71 be->be_path_list = FIB_NODE_INDEX_INVALID;
72
73 return (bier_entry_get_index(be));
74}
75
Neale Rannsd792d9c2017-10-21 10:53:20 -070076
77static void
78bier_entry_table_ecmp_walk_add_fmask (index_t btei,
79 void *arg)
80{
81 bier_entry_t *be = arg;;
82
83 /*
84 * choose a fmask from the entry's resolved set to add
85 * to ECMP table's lookup table
86 */
87 if (FIB_NODE_INDEX_INVALID != be->be_path_list)
88 {
89 const bier_table_id_t *btid;
90 dpo_id_t dpo = DPO_INVALID;
91 const dpo_id_t *choice;
92 load_balance_t *lb;
93
94 btid = bier_table_get_id(btei);
95
96 fib_path_list_contribute_forwarding(be->be_path_list,
97 FIB_FORW_CHAIN_TYPE_BIER,
Neale Ranns91286372017-12-05 13:24:04 -080098 FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
Neale Rannsd792d9c2017-10-21 10:53:20 -070099 &dpo);
100
101 /*
102 * select the appropriate bucket from the LB
103 */
Neale Ranns91286372017-12-05 13:24:04 -0800104 if (dpo.dpoi_type == DPO_LOAD_BALANCE)
105 {
106 lb = load_balance_get(dpo.dpoi_index);
107 choice = load_balance_get_bucket_i(lb,
108 btid->bti_ecmp &
109 (lb->lb_n_buckets_minus_1));
110 }
111 else
112 {
113 choice = &dpo;
114 }
Neale Rannsd792d9c2017-10-21 10:53:20 -0700115
116 if (choice->dpoi_type == DPO_BIER_FMASK)
117 {
118 bier_table_ecmp_set_fmask(btei, be->be_bp,
119 choice->dpoi_index);
120 }
121 else
122 {
123 /*
124 * any other type results in a drop, which we represent
125 * with an empty bucket
126 */
127 bier_table_ecmp_set_fmask(btei, be->be_bp,
128 INDEX_INVALID);
129 }
130
131 dpo_reset(&dpo);
132 }
133 else
134 {
135 /*
136 * no fmasks left. insert a drop
137 */
138 bier_table_ecmp_set_fmask(btei, be->be_bp, INDEX_INVALID);
139 }
140}
141
142void
Neale Rannsef90ed02018-09-13 08:45:12 -0700143bier_entry_delete (index_t bei)
144{
145 bier_entry_t *be;
146
147 be = bier_entry_get(bei);
148
149 /*
150 * if we still ahve a path-list, unlink from it
151 */
152 if (FIB_NODE_INDEX_INVALID != be->be_path_list)
153 {
154 fib_path_list_walk(be->be_path_list,
155 bier_entry_unlink_walk,
156 be);
157 fib_path_list_child_remove(be->be_path_list,
158 be->be_sibling_index);
159
160 be->be_path_list = FIB_NODE_INDEX_INVALID;
161 bier_table_ecmp_walk(be->be_bti,
162 bier_entry_table_ecmp_walk_add_fmask,
163 be);
164 }
165
166 pool_put(bier_entry_pool, be);
167}
168
169void
Neale Rannsd792d9c2017-10-21 10:53:20 -0700170bier_entry_path_add (index_t bei,
171 const fib_route_path_t *rpaths)
172{
173 fib_node_index_t old_pl_index;
174 bier_entry_t *be;
175
176 be = bier_entry_get(bei);
177 old_pl_index = be->be_path_list;
178
179 /*
180 * lock the path-list so it does not go away before we unlink
181 * from its resolved fmasks
182 */
183 fib_path_list_lock(old_pl_index);
184
185 if (FIB_NODE_INDEX_INVALID == be->be_path_list)
186 {
187 old_pl_index = FIB_NODE_INDEX_INVALID;
188 be->be_path_list = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED |
189 FIB_PATH_LIST_FLAG_NO_URPF),
190 rpaths);
191 be->be_sibling_index = fib_path_list_child_add(be->be_path_list,
192 FIB_NODE_TYPE_BIER_ENTRY,
193 bier_entry_get_index(be));
194 }
195 else
196 {
197
198 old_pl_index = be->be_path_list;
199
200 be->be_path_list =
201 fib_path_list_copy_and_path_add(old_pl_index,
202 (FIB_PATH_LIST_FLAG_SHARED |
203 FIB_PATH_LIST_FLAG_NO_URPF),
204 rpaths);
205
206 fib_path_list_child_remove(old_pl_index,
207 be->be_sibling_index);
208 be->be_sibling_index = fib_path_list_child_add(be->be_path_list,
209 FIB_NODE_TYPE_BIER_ENTRY,
210 bier_entry_get_index(be));
211 }
212 /*
213 * link the entry's bit-position to each fmask in the new path-list
214 * then unlink from the old.
215 */
216 fib_path_list_walk(be->be_path_list,
217 bier_entry_link_walk,
218 be);
219 if (FIB_NODE_INDEX_INVALID != old_pl_index)
220 {
221 fib_path_list_walk(old_pl_index,
222 bier_entry_unlink_walk,
223 be);
224 }
225
226 /*
227 * update the ECNP tables with the new choice
228 */
229 bier_table_ecmp_walk(be->be_bti,
230 bier_entry_table_ecmp_walk_add_fmask,
231 be);
232
233 /*
234 * symmetric unlock. The old path-list may not exist hereinafter
235 */
236 fib_path_list_unlock(old_pl_index);
237}
238
Neale Rannsef90ed02018-09-13 08:45:12 -0700239void
240bier_entry_path_update (index_t bei,
241 const fib_route_path_t *rpaths)
242{
243 fib_node_index_t old_pl_index;
244 bier_entry_t *be;
245
246 be = bier_entry_get(bei);
247 old_pl_index = be->be_path_list;
248
249 /*
250 * lock the path-list so it does not go away before we unlink
251 * from its resolved fmasks
252 */
253 fib_path_list_lock(old_pl_index);
254
255 if (FIB_NODE_INDEX_INVALID != old_pl_index)
256 {
257 fib_path_list_child_remove(old_pl_index,
258 be->be_sibling_index);
259 }
260
261 be->be_path_list = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED |
262 FIB_PATH_LIST_FLAG_NO_URPF),
263 rpaths);
264 be->be_sibling_index = fib_path_list_child_add(be->be_path_list,
265 FIB_NODE_TYPE_BIER_ENTRY,
266 bier_entry_get_index(be));
267
268 /*
269 * link the entry's bit-position to each fmask in the new path-list
270 * then unlink from the old.
271 */
272 fib_path_list_walk(be->be_path_list,
273 bier_entry_link_walk,
274 be);
275 if (FIB_NODE_INDEX_INVALID != old_pl_index)
276 {
277 fib_path_list_walk(old_pl_index,
278 bier_entry_unlink_walk,
279 be);
280 }
281
282 /*
283 * update the ECNP tables with the new choice
284 */
285 bier_table_ecmp_walk(be->be_bti,
286 bier_entry_table_ecmp_walk_add_fmask,
287 be);
288
289 /*
290 * symmetric unlock. The old path-list may not exist hereinafter
291 */
292 fib_path_list_unlock(old_pl_index);
293}
294
Neale Rannsd792d9c2017-10-21 10:53:20 -0700295int
296bier_entry_path_remove (index_t bei,
297 const fib_route_path_t *rpaths)
298{
299 fib_node_index_t old_pl_index;
300 bier_entry_t *be;
301
302 be = bier_entry_get(bei);
303 old_pl_index = be->be_path_list;
304
305 fib_path_list_lock(old_pl_index);
306
307 ASSERT (FIB_NODE_INDEX_INVALID != be->be_path_list);
308
309 be->be_path_list =
310 fib_path_list_copy_and_path_remove(old_pl_index,
311 (FIB_PATH_LIST_FLAG_SHARED |
312 FIB_PATH_LIST_FLAG_NO_URPF),
313 rpaths);
314
315 if (be->be_path_list != old_pl_index)
316 {
317 /*
318 * a path was removed
319 */
320 fib_path_list_child_remove(old_pl_index,
321 be->be_sibling_index);
322
323 if (FIB_NODE_INDEX_INVALID != be->be_path_list)
324 {
325 /*
326 * link the entry's bit-position to each fmask in the new path-list
327 * then unlink from the old.
328 */
329 fib_path_list_walk(be->be_path_list,
330 bier_entry_link_walk,
331 be);
332 be->be_sibling_index =
333 fib_path_list_child_add(be->be_path_list,
334 FIB_NODE_TYPE_BIER_ENTRY,
335 bier_entry_get_index(be));
336 }
337
338 fib_path_list_walk(old_pl_index,
339 bier_entry_unlink_walk,
340 be);
341 }
342 fib_path_list_unlock(old_pl_index);
343
Neale Rannsd792d9c2017-10-21 10:53:20 -0700344 /*
345 * update the ECNP tables with the new choice
346 */
347 bier_table_ecmp_walk(be->be_bti,
348 bier_entry_table_ecmp_walk_add_fmask,
349 be);
350
351 return (fib_path_list_get_n_paths(be->be_path_list));
352}
353
354void
355bier_entry_contribute_forwarding(index_t bei,
356 dpo_id_t *dpo)
357{
358 bier_entry_t *be = bier_entry_get(bei);
359
360 fib_path_list_contribute_forwarding(be->be_path_list,
361 FIB_FORW_CHAIN_TYPE_BIER,
Neale Ranns91286372017-12-05 13:24:04 -0800362 FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700363 dpo);
364}
365
366u8*
367format_bier_entry (u8* s, va_list *ap)
368{
369 index_t bei = va_arg(*ap, index_t);
370 bier_show_flags_t flags = va_arg(*ap, bier_show_flags_t);
371
372 bier_entry_t *be = bier_entry_get(bei);
373
374 s = format(s, " bp:%d\n", be->be_bp);
375 s = fib_path_list_format(be->be_path_list, s);
376
377 if (flags & BIER_SHOW_DETAIL)
378 {
379 dpo_id_t dpo = DPO_INVALID;
380
381 bier_entry_contribute_forwarding(bei, &dpo);
382
383 s = format(s, " forwarding:\n");
384 s = format(s, " %U",
385 format_dpo_id, &dpo, 2);
386 s = format(s, "\n");
387 }
388
389 return (s);
390}
391
392static fib_node_t *
393bier_entry_get_node (fib_node_index_t index)
394{
395 bier_entry_t *be = bier_entry_get(index);
396 return (&(be->be_node));
397}
398
399static bier_entry_t*
400bier_entry_get_from_node (fib_node_t *node)
401{
402 return ((bier_entry_t*)(((char*)node) -
403 STRUCT_OFFSET_OF(bier_entry_t,
404 be_node)));
405}
406
407static void
408bier_entry_last_lock_gone (fib_node_t *node)
409{
410 /*
411 * the lifetime of the entry is managed by the table.
412 */
413 ASSERT(0);
414}
415
416/*
417 * A back walk has reached this BIER entry
418 */
419static fib_node_back_walk_rc_t
420bier_entry_back_walk_notify (fib_node_t *node,
421 fib_node_back_walk_ctx_t *ctx)
422{
423 /*
424 * re-populate the ECMP tables with new choices
425 */
426 bier_entry_t *be = bier_entry_get_from_node(node);
427
428 bier_table_ecmp_walk(be->be_bti,
429 bier_entry_table_ecmp_walk_add_fmask,
430 be);
431
432 /*
433 * no need to propagate further up the graph.
434 */
435 return (FIB_NODE_BACK_WALK_CONTINUE);
436}
437
438/*
439 * The BIER fmask's graph node virtual function table
440 */
441static const fib_node_vft_t bier_entry_vft = {
442 .fnv_get = bier_entry_get_node,
443 .fnv_last_lock = bier_entry_last_lock_gone,
444 .fnv_back_walk = bier_entry_back_walk_notify,
445};
446
447clib_error_t *
448bier_entry_module_init (vlib_main_t * vm)
449{
450 fib_node_register_type (FIB_NODE_TYPE_BIER_ENTRY, &bier_entry_vft);
451
452 return (NULL);
453}
454
455VLIB_INIT_FUNCTION (bier_entry_module_init);