Line data Source code
1 : /*
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/adj/adj.h>
17 : #include <vnet/dpo/load_balance.h>
18 : #include <vnet/dpo/mpls_label_dpo.h>
19 : #include <vnet/dpo/drop_dpo.h>
20 : #include <vnet/dpo/replicate_dpo.h>
21 :
22 : #include <vnet/fib/fib_entry_src.h>
23 : #include <vnet/fib/fib_table.h>
24 : #include <vnet/fib/fib_path_ext.h>
25 : #include <vnet/fib/fib_urpf_list.h>
26 : #include <vnet/fib/fib_entry_delegate.h>
27 :
28 : /*
29 : * per-source type vft
30 : */
31 : static fib_entry_src_vft_t fib_entry_src_bh_vft[FIB_SOURCE_BH_MAX];
32 :
33 : /**
34 : * Get the VFT for a given source. This is a combination of the source
35 : * enum and the interposer flags
36 : */
37 : const fib_entry_src_vft_t*
38 568212 : fib_entry_src_get_vft (const fib_entry_src_t *esrc)
39 : {
40 : fib_source_behaviour_t bh;
41 :
42 568212 : bh = fib_source_get_behaviour(esrc->fes_src);
43 :
44 568212 : if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_INTERPOSE)
45 : {
46 429 : return (&fib_entry_src_bh_vft[FIB_SOURCE_BH_INTERPOSE]);
47 : }
48 :
49 567783 : ASSERT(bh < FIB_SOURCE_BH_MAX);
50 567783 : return (&fib_entry_src_bh_vft[bh]);
51 : }
52 :
53 : static void
54 17 : fib_entry_src_copy_default (const fib_entry_src_t *orig_src,
55 : const fib_entry_t *fib_entry,
56 : fib_entry_src_t *copy_src)
57 : {
58 17 : clib_memcpy(©_src->u, &orig_src->u, sizeof(copy_src->u));
59 17 : }
60 :
61 : void
62 5175 : fib_entry_src_behaviour_register (fib_source_behaviour_t bh,
63 : const fib_entry_src_vft_t *vft)
64 : {
65 5175 : fib_entry_src_bh_vft[bh] = *vft;
66 :
67 5175 : if (NULL == fib_entry_src_bh_vft[bh].fesv_copy)
68 : {
69 4600 : fib_entry_src_bh_vft[bh].fesv_copy = fib_entry_src_copy_default;
70 : }
71 5175 : }
72 :
73 : static int
74 4499 : fib_entry_src_cmp_for_sort (void * v1,
75 : void * v2)
76 : {
77 4499 : fib_entry_src_t *esrc1 = v1, *esrc2 = v2;
78 :
79 4499 : return (fib_source_get_prio(esrc1->fes_src) -
80 4499 : fib_source_get_prio(esrc2->fes_src));
81 : }
82 :
83 : static void
84 45365 : fib_entry_src_action_init (fib_entry_t *fib_entry,
85 : fib_source_t source,
86 : fib_entry_flag_t flags)
87 : {
88 45365 : fib_entry_src_t esrc = {
89 : .fes_pl = FIB_NODE_INDEX_INVALID,
90 : .fes_flags = FIB_ENTRY_SRC_FLAG_NONE,
91 : .fes_src = source,
92 : .fes_entry_flags = flags,
93 : };
94 :
95 45365 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, &esrc, fesv_init, (&esrc));
96 :
97 45365 : vec_add1(fib_entry->fe_srcs, esrc);
98 45365 : vec_sort_with_function(fib_entry->fe_srcs,
99 : fib_entry_src_cmp_for_sort);
100 45365 : }
101 :
102 : static fib_entry_src_t *
103 665523 : fib_entry_src_find_i (const fib_entry_t *fib_entry,
104 : fib_source_t source,
105 : u32 *index)
106 :
107 : {
108 : fib_entry_src_t *esrc;
109 : int ii;
110 :
111 665523 : ii = 0;
112 819613 : vec_foreach(esrc, fib_entry->fe_srcs)
113 : {
114 644243 : if (esrc->fes_src == source)
115 : {
116 490153 : if (NULL != index)
117 : {
118 35297 : *index = ii;
119 : }
120 490153 : return (esrc);
121 : }
122 : else
123 : {
124 154090 : ii++;
125 : }
126 : }
127 :
128 175370 : return (NULL);
129 : }
130 :
131 : fib_entry_src_t *
132 630226 : fib_entry_src_find (const fib_entry_t *fib_entry,
133 : fib_source_t source)
134 :
135 : {
136 630226 : return (fib_entry_src_find_i(fib_entry, source, NULL));
137 : }
138 :
139 : int
140 176908 : fib_entry_is_sourced (fib_node_index_t fib_entry_index,
141 : fib_source_t source)
142 : {
143 : fib_entry_t *fib_entry;
144 :
145 176908 : fib_entry = fib_entry_get(fib_entry_index);
146 :
147 176908 : return (NULL != fib_entry_src_find(fib_entry, source));
148 : }
149 :
150 : int
151 552 : fib_entry_is_marked (fib_node_index_t fib_entry_index,
152 : fib_source_t source)
153 : {
154 : fib_entry_t *fib_entry;
155 : fib_entry_src_t *esrc;
156 :
157 552 : fib_entry = fib_entry_get(fib_entry_index);
158 :
159 552 : esrc = fib_entry_src_find(fib_entry, source);
160 :
161 552 : if (NULL == esrc)
162 : {
163 84 : return (0);
164 : }
165 : else
166 : {
167 468 : return (!!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_STALE));
168 : }
169 : }
170 :
171 : void
172 468 : fib_entry_mark (fib_node_index_t fib_entry_index,
173 : fib_source_t source)
174 : {
175 : fib_entry_t *fib_entry;
176 : fib_entry_src_t *esrc;
177 :
178 468 : fib_entry = fib_entry_get(fib_entry_index);
179 :
180 468 : esrc = fib_entry_src_find(fib_entry, source);
181 :
182 468 : if (NULL != esrc)
183 : {
184 468 : esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_STALE;
185 : }
186 468 : }
187 :
188 : static fib_entry_src_t *
189 47283 : fib_entry_src_find_or_create (fib_entry_t *fib_entry,
190 : fib_source_t source,
191 : fib_entry_flag_t flags)
192 : {
193 : fib_entry_src_t *esrc;
194 :
195 47283 : esrc = fib_entry_src_find(fib_entry, source);
196 :
197 47283 : if (NULL == esrc)
198 : {
199 45365 : fib_entry_src_action_init(fib_entry, source, flags);
200 : }
201 :
202 47283 : return (fib_entry_src_find(fib_entry, source));
203 : }
204 :
205 : static void
206 35297 : fib_entry_src_action_deinit (fib_entry_t *fib_entry,
207 : fib_source_t source)
208 :
209 : {
210 : fib_entry_src_t *esrc;
211 35297 : u32 index = ~0;
212 :
213 35297 : esrc = fib_entry_src_find_i(fib_entry, source, &index);
214 :
215 35297 : ASSERT(NULL != esrc);
216 :
217 35297 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_deinit, (esrc));
218 :
219 35297 : fib_path_ext_list_flush(&esrc->fes_path_exts);
220 35297 : vec_del1(fib_entry->fe_srcs, index);
221 35297 : vec_sort_with_function(fib_entry->fe_srcs,
222 : fib_entry_src_cmp_for_sort);
223 35297 : }
224 :
225 : fib_entry_src_cover_res_t
226 4289 : fib_entry_src_action_cover_change (fib_entry_t *fib_entry,
227 : fib_entry_src_t *esrc)
228 : {
229 4289 : FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_cover_change,
230 : (esrc, fib_entry));
231 :
232 12 : fib_entry_src_cover_res_t res = {
233 : .install = !0,
234 : .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
235 : };
236 12 : return (res);
237 : }
238 :
239 : fib_entry_src_cover_res_t
240 15 : fib_entry_src_action_cover_update (fib_entry_t *fib_entry,
241 : fib_entry_src_t *esrc)
242 : {
243 15 : FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_cover_update,
244 : (esrc, fib_entry));
245 :
246 4 : fib_entry_src_cover_res_t res = {
247 : .install = !0,
248 : .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
249 : };
250 4 : return (res);
251 : }
252 :
253 : typedef struct fib_entry_src_collect_forwarding_ctx_t_
254 : {
255 : load_balance_path_t *next_hops;
256 : const fib_entry_t *fib_entry;
257 : i32 start_source_index, end_source_index;
258 : fib_forward_chain_type_t fct;
259 : int n_recursive_constrained;
260 : u16 preference;
261 : dpo_proto_t payload_proto;
262 : } fib_entry_src_collect_forwarding_ctx_t;
263 :
264 : /**
265 : * @brief Determine whether this FIB entry should use a load-balance MAP
266 : * to support PIC edge fast convergence
267 : */
268 : static load_balance_flags_t
269 79876 : fib_entry_calc_lb_flags (fib_entry_src_collect_forwarding_ctx_t *ctx,
270 : const fib_entry_src_t *esrc)
271 : {
272 : /**
273 : * We'll use a LB map if the path-list has multiple recursive paths.
274 : * recursive paths implies BGP, and hence scale.
275 : */
276 82501 : if (ctx->n_recursive_constrained > 1 &&
277 2625 : fib_path_list_is_popular(esrc->fes_pl))
278 : {
279 1931 : return (LOAD_BALANCE_FLAG_USES_MAP);
280 : }
281 77945 : return (LOAD_BALANCE_FLAG_NONE);
282 : }
283 :
284 : static int
285 1457 : fib_entry_src_valid_out_label (mpls_label_t label)
286 : {
287 1457 : return ((MPLS_LABEL_IS_REAL(label) ||
288 32 : MPLS_LABEL_POP == label ||
289 32 : MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL == label ||
290 2914 : MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL == label ||
291 : MPLS_IETF_IMPLICIT_NULL_LABEL == label));
292 : }
293 :
294 : static dpo_proto_t
295 80209 : fib_prefix_get_payload_proto (const fib_prefix_t *pfx)
296 : {
297 80209 : switch (pfx->fp_proto)
298 : {
299 44694 : case FIB_PROTOCOL_IP4:
300 44694 : return (DPO_PROTO_IP4);
301 34784 : case FIB_PROTOCOL_IP6:
302 34784 : return (DPO_PROTO_IP6);
303 731 : case FIB_PROTOCOL_MPLS:
304 731 : return (pfx->fp_payload_proto);
305 : }
306 :
307 0 : ASSERT(0);
308 0 : return (DPO_PROTO_IP4);
309 : }
310 :
311 : static void
312 72595 : fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
313 : fib_entry_src_collect_forwarding_ctx_t *ctx)
314 : {
315 : load_balance_path_t *nh;
316 :
317 : /*
318 : * no extension => no out-going label for this path. that's OK
319 : * in the case of an IP or EOS chain, but not for non-EOS
320 : */
321 72595 : switch (ctx->fct)
322 : {
323 69208 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
324 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
325 : case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
326 : case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
327 : case FIB_FORW_CHAIN_TYPE_BIER:
328 : /*
329 : * EOS traffic with no label to stack, we need the IP Adj
330 : */
331 69208 : vec_add2(ctx->next_hops, nh, 1);
332 :
333 69208 : nh->path_index = path_index;
334 69208 : nh->path_weight = fib_path_get_weight(path_index);
335 69208 : fib_path_contribute_forwarding(path_index, ctx->fct,
336 69208 : ctx->payload_proto, &nh->path_dpo);
337 :
338 69208 : break;
339 1667 : case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
340 3046 : if (fib_path_is_exclusive(path_index) ||
341 1379 : fib_path_is_deag(path_index))
342 : {
343 290 : vec_add2(ctx->next_hops, nh, 1);
344 :
345 290 : nh->path_index = path_index;
346 290 : nh->path_weight = fib_path_get_weight(path_index);
347 290 : fib_path_contribute_forwarding(path_index,
348 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
349 290 : ctx->payload_proto,
350 290 : &nh->path_dpo);
351 : }
352 1667 : break;
353 1720 : case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
354 : {
355 : /*
356 : * no label. we need a chain based on the payload. fixup.
357 : */
358 1720 : vec_add2(ctx->next_hops, nh, 1);
359 :
360 1720 : nh->path_index = path_index;
361 1720 : nh->path_weight = fib_path_get_weight(path_index);
362 1720 : fib_path_contribute_forwarding(path_index,
363 1720 : ctx->fct,
364 1720 : ctx->payload_proto,
365 1720 : &nh->path_dpo);
366 1720 : fib_path_stack_mpls_disp(path_index,
367 1720 : ctx->payload_proto,
368 : FIB_MPLS_LSP_MODE_PIPE,
369 1720 : &nh->path_dpo);
370 :
371 1720 : break;
372 : }
373 0 : case FIB_FORW_CHAIN_TYPE_ETHERNET:
374 : case FIB_FORW_CHAIN_TYPE_NSH:
375 0 : ASSERT(0);
376 0 : break;
377 : }
378 72595 : }
379 :
380 : static fib_path_list_walk_rc_t
381 113696 : fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
382 : fib_node_index_t path_index,
383 : void *arg)
384 : {
385 : fib_entry_src_collect_forwarding_ctx_t *ctx;
386 : const fib_entry_src_t *esrc;
387 : fib_path_ext_t *path_ext;
388 : u32 n_nhs;
389 :
390 113696 : ctx = arg;
391 113696 : n_nhs = vec_len(ctx->next_hops);
392 :
393 : /*
394 : * walk the paths and extension of the best non-interpose source
395 : */
396 113696 : esrc = &ctx->fib_entry->fe_srcs[ctx->end_source_index];
397 :
398 : /*
399 : * if the path is not resolved, don't include it.
400 : */
401 113696 : if (!fib_path_is_resolved(path_index))
402 : {
403 33124 : return (FIB_PATH_LIST_WALK_CONTINUE);
404 : }
405 :
406 80572 : if (fib_path_is_recursive_constrained(path_index))
407 : {
408 15154 : ctx->n_recursive_constrained += 1;
409 : }
410 80572 : if (0xffff == ctx->preference)
411 : {
412 : /*
413 : * not set a preference yet, so the first path we encounter
414 : * sets the preference we are collecting.
415 : */
416 57713 : ctx->preference = fib_path_get_preference(path_index);
417 : }
418 22859 : else if (ctx->preference != fib_path_get_preference(path_index))
419 : {
420 : /*
421 : * this path does not belong to the same preference as the
422 : * previous paths encountered. we are done now.
423 : */
424 6510 : return (FIB_PATH_LIST_WALK_STOP);
425 : }
426 :
427 : /*
428 : * get the matching path-extension for the path being visited.
429 : */
430 74062 : path_ext = fib_path_ext_list_find_by_path_index(&esrc->fes_path_exts,
431 : path_index);
432 :
433 74062 : if (NULL != path_ext)
434 : {
435 17109 : switch (path_ext->fpe_type)
436 : {
437 1457 : case FIB_PATH_EXT_MPLS:
438 1457 : if (fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0].fml_value))
439 : {
440 : /*
441 : * found a matching extension. stack it to obtain the forwarding
442 : * info for this path.
443 : */
444 1457 : ctx->next_hops =
445 1457 : fib_path_ext_stack(path_ext,
446 1457 : ctx->payload_proto,
447 1457 : ctx->fct,
448 : ctx->next_hops);
449 : }
450 : else
451 : {
452 0 : fib_entry_src_get_path_forwarding(path_index, ctx);
453 : }
454 1457 : break;
455 15652 : case FIB_PATH_EXT_ADJ:
456 15652 : if (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & path_ext->fpe_adj_flags)
457 : {
458 15642 : fib_entry_src_get_path_forwarding(path_index, ctx);
459 : }
460 : /*
461 : * else
462 : * the path does not refine the cover, meaning that
463 : * the adjacency does/does not match the sub-net on the link.
464 : * So this path does not contribute forwarding.
465 : */
466 15652 : break;
467 : }
468 17109 : }
469 : else
470 : {
471 56953 : fib_entry_src_get_path_forwarding(path_index, ctx);
472 : }
473 :
474 : /*
475 : * a this point 'ctx' has the DPO the path contributed, plus
476 : * any labels from path extensions.
477 : * check if there are any interpose sources that want to contribute
478 : */
479 74062 : if (n_nhs < vec_len(ctx->next_hops))
480 : {
481 : /*
482 : * the path contributed a new choice.
483 : */
484 : const fib_entry_src_vft_t *vft;
485 :
486 : /*
487 : * roll up the sources that are interposes
488 : */
489 : i32 index;
490 :
491 72673 : for (index = ctx->end_source_index;
492 145391 : index >= ctx->start_source_index;
493 72718 : index--)
494 : {
495 : const dpo_id_t *interposer;
496 :
497 72718 : esrc = &ctx->fib_entry->fe_srcs[index];
498 72718 : vft = fib_entry_src_get_vft(esrc);
499 :
500 72718 : if (!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_CONTRIBUTING) ||
501 72718 : !(esrc->fes_entry_flags & FIB_ENTRY_FLAG_INTERPOSE))
502 72671 : continue;
503 :
504 47 : ASSERT(vft->fesv_contribute_interpose);
505 47 : interposer = vft->fesv_contribute_interpose(esrc, ctx->fib_entry);
506 :
507 47 : if (NULL != interposer)
508 : {
509 47 : dpo_id_t clone = DPO_INVALID;
510 :
511 47 : dpo_mk_interpose(interposer,
512 47 : &ctx->next_hops[n_nhs].path_dpo,
513 : &clone);
514 :
515 47 : dpo_copy(&ctx->next_hops[n_nhs].path_dpo, &clone);
516 47 : dpo_reset(&clone);
517 : }
518 : }
519 : }
520 :
521 74062 : return (FIB_PATH_LIST_WALK_CONTINUE);
522 : }
523 :
524 : void
525 80209 : fib_entry_src_mk_lb (fib_entry_t *fib_entry,
526 : fib_source_t source,
527 : fib_forward_chain_type_t fct,
528 : dpo_id_t *dpo_lb)
529 : {
530 : const fib_entry_src_t *esrc;
531 : dpo_proto_t lb_proto;
532 : u32 start, end;
533 :
534 : /*
535 : * The source passed here is the 'best', i.e. the one the client
536 : * wants. however, if it's an interpose then it does not contribute
537 : * the forwarding, the next best source that is not an interpose does.
538 : * So roll down the sources, to find the best non-interpose
539 : */
540 80209 : vec_foreach_index (start, fib_entry->fe_srcs)
541 : {
542 80209 : if (source == fib_entry->fe_srcs[start].fes_src)
543 80209 : break;
544 : }
545 80266 : for (end = start; end < vec_len (fib_entry->fe_srcs); end++)
546 : {
547 80260 : if (!(fib_entry->fe_srcs[end].fes_entry_flags &
548 80203 : FIB_ENTRY_FLAG_INTERPOSE) &&
549 80203 : (fib_entry->fe_srcs[end].fes_flags &
550 : FIB_ENTRY_SRC_FLAG_CONTRIBUTING))
551 80203 : break;
552 : }
553 80209 : if (end == vec_len(fib_entry->fe_srcs))
554 : {
555 : /* didn't find any contributing non-interpose sources */
556 6 : end = start;
557 : }
558 :
559 80209 : esrc = &fib_entry->fe_srcs[end];
560 :
561 : /*
562 : * If the entry has path extensions then we construct a load-balance
563 : * by stacking the extensions on the forwarding chains of the paths.
564 : * Otherwise we use the load-balance of the path-list
565 : */
566 160418 : fib_entry_src_collect_forwarding_ctx_t ctx = {
567 : .fib_entry = fib_entry,
568 : .next_hops = NULL,
569 : .n_recursive_constrained = 0,
570 : .fct = fct,
571 : .preference = 0xffff,
572 : .start_source_index = start,
573 : .end_source_index = end,
574 80209 : .payload_proto = fib_prefix_get_payload_proto(&fib_entry->fe_prefix),
575 : };
576 :
577 : /*
578 : * As an optimisation we allocate the vector of next-hops to be sized
579 : * equal to the maximum number of paths we will need, which is also the
580 : * most likely number we will need, since in most cases the paths are 'up'.
581 : */
582 80209 : vec_validate(ctx.next_hops, fib_path_list_get_n_paths(esrc->fes_pl));
583 80209 : vec_reset_length(ctx.next_hops);
584 :
585 80209 : lb_proto = fib_forw_chain_type_to_dpo_proto(fct);
586 :
587 80209 : fib_path_list_walk(esrc->fes_pl,
588 : fib_entry_src_collect_forwarding,
589 : &ctx);
590 :
591 80209 : if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_EXCLUSIVE)
592 : {
593 : /*
594 : * the client provided the DPO that the entry should link to.
595 : * all entries must link to a LB, so if it is an LB already
596 : * then we can use it.
597 : */
598 1112 : if ((1 == vec_len(ctx.next_hops)) &&
599 1112 : (DPO_LOAD_BALANCE == ctx.next_hops[0].path_dpo.dpoi_type))
600 : {
601 308 : dpo_copy(dpo_lb, &ctx.next_hops[0].path_dpo);
602 308 : dpo_reset(&ctx.next_hops[0].path_dpo);
603 308 : return;
604 : }
605 : }
606 :
607 79901 : if (!dpo_id_is_valid(dpo_lb))
608 : {
609 : /*
610 : * first time create
611 : */
612 40658 : if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
613 : {
614 6 : dpo_set(dpo_lb,
615 : DPO_REPLICATE,
616 : lb_proto,
617 6 : MPLS_IS_REPLICATE | replicate_create(0, lb_proto));
618 : }
619 : else
620 : {
621 : fib_protocol_t flow_hash_proto;
622 : flow_hash_config_t fhc;
623 :
624 : /*
625 : * if the protocol for the LB we are building does not match that
626 : * of the fib_entry (i.e. we are build the [n]EOS LB for an IPv[46]
627 : * then the fib_index is not an index that relates to the table
628 : * type we need. So get the default flow-hash config instead.
629 : */
630 40652 : flow_hash_proto = dpo_proto_to_fib(lb_proto);
631 40652 : if (fib_entry->fe_prefix.fp_proto != flow_hash_proto)
632 : {
633 375 : fhc = fib_table_get_default_flow_hash_config(flow_hash_proto);
634 : }
635 : else
636 : {
637 40277 : fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
638 : flow_hash_proto);
639 : }
640 :
641 40652 : dpo_set(dpo_lb,
642 : DPO_LOAD_BALANCE,
643 : lb_proto,
644 : load_balance_create(0, lb_proto, fhc));
645 : }
646 : }
647 :
648 79901 : if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
649 : {
650 : /*
651 : * MPLS multicast
652 : */
653 25 : replicate_multipath_update(dpo_lb, ctx.next_hops);
654 : }
655 : else
656 : {
657 79876 : load_balance_multipath_update(dpo_lb,
658 79876 : ctx.next_hops,
659 79876 : fib_entry_calc_lb_flags(&ctx, esrc));
660 79876 : vec_free(ctx.next_hops);
661 :
662 : /*
663 : * if this entry is sourced by the uRPF-exempt source then we
664 : * append the always present local0 interface (index 0) to the
665 : * uRPF list so it is not empty. that way packets pass the loose check.
666 : */
667 79876 : index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
668 :
669 79876 : if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
670 79875 : FIB_SOURCE_URPF_EXEMPT) ||
671 84960 : (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
672 5085 : (0 == fib_urpf_check_size(ui)))
673 : {
674 : /*
675 : * The uRPF list we get from the path-list is shared by all
676 : * other users of the list, but the uRPF exemption applies
677 : * only to this prefix. So we need our own list.
678 : */
679 5085 : ui = fib_urpf_list_alloc_and_lock();
680 5085 : fib_urpf_list_append(ui, 0);
681 5085 : fib_urpf_list_bake(ui);
682 5085 : load_balance_set_urpf(dpo_lb->dpoi_index, ui);
683 5085 : fib_urpf_list_unlock(ui);
684 : }
685 : else
686 : {
687 74791 : load_balance_set_urpf(dpo_lb->dpoi_index, ui);
688 : }
689 79876 : load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
690 79876 : fib_entry_get_flags_i(fib_entry));
691 : }
692 : }
693 :
694 : void
695 77739 : fib_entry_src_action_install (fib_entry_t *fib_entry,
696 : fib_source_t source)
697 : {
698 : /*
699 : * Install the forwarding chain for the given source into the forwarding
700 : * tables
701 : */
702 : fib_forward_chain_type_t fct;
703 : int insert;
704 :
705 77739 : fct = fib_entry_get_default_chain_type(fib_entry);
706 :
707 : /*
708 : * Every entry has its own load-balance object. All changes to the entry's
709 : * forwarding result in an inplace modify of the load-balance. This means
710 : * the load-balance object only needs to be added to the forwarding
711 : * DB once, when it is created.
712 : */
713 77739 : insert = !dpo_id_is_valid(&fib_entry->fe_lb);
714 :
715 77739 : fib_entry_src_mk_lb(fib_entry, source, fct, &fib_entry->fe_lb);
716 :
717 77739 : ASSERT(dpo_id_is_valid(&fib_entry->fe_lb));
718 77739 : FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb);
719 :
720 : /*
721 : * insert the adj into the data-plane forwarding trie
722 : */
723 77739 : if (insert)
724 : {
725 40613 : fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
726 : &fib_entry->fe_prefix,
727 40613 : &fib_entry->fe_lb);
728 : }
729 :
730 : /*
731 : * if any of the other chain types are already created they will need
732 : * updating too
733 : */
734 : fib_entry_delegate_type_t fdt;
735 : fib_entry_delegate_t *fed;
736 :
737 777390 : FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
738 : {
739 : fib_entry_src_mk_lb(fib_entry, source,
740 : fib_entry_delegate_type_to_chain_type(fdt),
741 : &fed->fd_dpo);
742 : });
743 77739 : }
744 :
745 : void
746 37879 : fib_entry_src_action_uninstall (fib_entry_t *fib_entry)
747 : {
748 : /*
749 : * uninstall the forwarding chain from the forwarding tables
750 : */
751 37879 : FIB_ENTRY_DBG(fib_entry, "uninstall");
752 :
753 37879 : if (dpo_id_is_valid(&fib_entry->fe_lb))
754 : {
755 30572 : fib_table_fwding_dpo_remove(
756 : fib_entry->fe_fib_index,
757 : &fib_entry->fe_prefix,
758 30572 : &fib_entry->fe_lb);
759 :
760 30572 : dpo_reset(&fib_entry->fe_lb);
761 : }
762 37879 : }
763 :
764 : static void
765 78412 : fib_entry_recursive_loop_detect_i (fib_node_index_t path_list_index)
766 : {
767 78412 : fib_node_index_t *entries = NULL;
768 :
769 78412 : fib_path_list_recursive_loop_detect(path_list_index, &entries);
770 :
771 78412 : vec_free(entries);
772 78412 : }
773 :
774 : /*
775 : * fib_entry_src_action_copy
776 : *
777 : * copy a source data from another entry to this one
778 : */
779 : static fib_entry_t *
780 21 : fib_entry_src_action_copy (fib_entry_t *fib_entry,
781 : const fib_entry_src_t *orig_src)
782 : {
783 : fib_entry_src_t *esrc;
784 :
785 21 : esrc = fib_entry_src_find_or_create(fib_entry,
786 21 : orig_src->fes_src,
787 21 : orig_src->fes_entry_flags);
788 :
789 21 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_copy,
790 : (orig_src, fib_entry, esrc));
791 :
792 21 : fib_path_list_unlock(esrc->fes_pl);
793 :
794 : /*
795 : * copy over all the data ...
796 : */
797 21 : esrc->fes_flags = orig_src->fes_flags;
798 21 : esrc->fes_pl = orig_src->fes_pl;
799 :
800 : /*
801 : * ... then update
802 : */
803 21 : esrc->fes_ref_count = 1;
804 21 : esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_INHERITED;
805 21 : esrc->fes_flags &= ~(FIB_ENTRY_SRC_FLAG_ACTIVE |
806 : FIB_ENTRY_SRC_FLAG_CONTRIBUTING);
807 21 : esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
808 :
809 : /*
810 : * the source owns a lock on the entry
811 : */
812 21 : fib_path_list_lock(esrc->fes_pl);
813 21 : fib_entry_lock(fib_entry_get_index(fib_entry));
814 :
815 21 : return (fib_entry);
816 : }
817 :
818 : /*
819 : * fib_entry_src_action_update
820 : *
821 : * copy a source data from another entry to this one
822 : */
823 : static fib_entry_src_t *
824 35 : fib_entry_src_action_update_from_cover (fib_entry_t *fib_entry,
825 : const fib_entry_src_t *orig_src)
826 : {
827 : fib_entry_src_t *esrc;
828 :
829 35 : esrc = fib_entry_src_find_or_create(fib_entry,
830 35 : orig_src->fes_src,
831 35 : orig_src->fes_entry_flags);
832 :
833 : /*
834 : * the source owns a lock on the entry
835 : */
836 35 : fib_path_list_unlock(esrc->fes_pl);
837 35 : esrc->fes_pl = orig_src->fes_pl;
838 35 : fib_path_list_lock(esrc->fes_pl);
839 :
840 35 : return (esrc);
841 : }
842 :
843 : static fib_table_walk_rc_t
844 106 : fib_entry_src_covered_inherit_add_i (fib_entry_t *fib_entry,
845 : const fib_entry_src_t *cover_src)
846 : {
847 : fib_entry_src_t *esrc;
848 :
849 106 : esrc = fib_entry_src_find(fib_entry, cover_src->fes_src);
850 :
851 106 : if (cover_src == esrc)
852 : {
853 49 : return (FIB_TABLE_WALK_CONTINUE);
854 : }
855 :
856 57 : if (NULL != esrc)
857 : {
858 : /*
859 : * the covered entry already has this source.
860 : */
861 36 : if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
862 : {
863 : /*
864 : * the covered source is itself a COVERED_INHERIT, i.e.
865 : * it also pushes this source down the sub-tree.
866 : * We consider this more specific covered to be the owner
867 : * of the sub-tree from this point down.
868 : */
869 2 : return (FIB_TABLE_WALK_SUB_TREE_STOP);
870 : }
871 34 : if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
872 : {
873 : /*
874 : * The covered's source data has been inherited, presumably
875 : * from this cover, i.e. this is a modify.
876 : */
877 34 : esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
878 34 : fib_entry_source_change(fib_entry, esrc->fes_src, esrc->fes_src);
879 : }
880 : else
881 : {
882 : /*
883 : * The covered's source was not inherited and it is also
884 : * not inheriting. Nevertheless, it still owns the sub-tree from
885 : * this point down.
886 : */
887 0 : return (FIB_TABLE_WALK_SUB_TREE_STOP);
888 : }
889 : }
890 : else
891 : {
892 : /*
893 : * The covered does not have this source - add it.
894 : */
895 : fib_source_t best_source;
896 :
897 21 : best_source = fib_entry_get_best_source(
898 : fib_entry_get_index(fib_entry));
899 :
900 21 : fib_entry_src_action_copy(fib_entry, cover_src);
901 21 : fib_entry_source_change(fib_entry, best_source, cover_src->fes_src);
902 :
903 : }
904 55 : return (FIB_TABLE_WALK_CONTINUE);
905 : }
906 :
907 : static fib_table_walk_rc_t
908 104 : fib_entry_src_covered_inherit_walk_add (fib_node_index_t fei,
909 : void *ctx)
910 : {
911 104 : return (fib_entry_src_covered_inherit_add_i(fib_entry_get(fei), ctx));
912 : }
913 :
914 : static fib_table_walk_rc_t
915 24 : fib_entry_src_covered_inherit_walk_remove (fib_node_index_t fei,
916 : void *ctx)
917 : {
918 : fib_entry_src_t *cover_src, *esrc;
919 : fib_entry_t *fib_entry;
920 :
921 24 : fib_entry = fib_entry_get(fei);
922 :
923 24 : cover_src = ctx;
924 24 : esrc = fib_entry_src_find(fib_entry, cover_src->fes_src);
925 :
926 24 : if (cover_src == esrc)
927 : {
928 8 : return (FIB_TABLE_WALK_CONTINUE);
929 : }
930 :
931 16 : if (NULL != esrc)
932 : {
933 : /*
934 : * the covered entry already has this source.
935 : */
936 15 : if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
937 : {
938 : /*
939 : * the covered source is itself a COVERED_INHERIT, i.e.
940 : * it also pushes this source down the sub-tree.
941 : * We consider this more specific covered to be the owner
942 : * of the sub-tree from this point down.
943 : */
944 1 : return (FIB_TABLE_WALK_SUB_TREE_STOP);
945 : }
946 14 : if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
947 : {
948 : /*
949 : * The covered's source data has been inherited, presumably
950 : * from this cover
951 : */
952 : fib_entry_src_flag_t remaining;
953 :
954 14 : remaining = fib_entry_special_remove(fei, cover_src->fes_src);
955 :
956 14 : ASSERT(FIB_ENTRY_SRC_FLAG_ADDED == remaining);
957 : }
958 : else
959 : {
960 : /*
961 : * The covered's source was not inherited and it is also
962 : * not inheriting. Nevertheless, it still owns the sub-tree from
963 : * this point down.
964 : */
965 0 : return (FIB_TABLE_WALK_SUB_TREE_STOP);
966 : }
967 : }
968 : else
969 : {
970 : /*
971 : * The covered does not have this source - that's an error,
972 : * since it should have inherited, but there is nothing we can do
973 : * about it now.
974 : */
975 : }
976 15 : return (FIB_TABLE_WALK_CONTINUE);
977 : }
978 :
979 : void
980 36564 : fib_entry_src_inherit (const fib_entry_t *cover,
981 : fib_entry_t *covered)
982 : {
983 : CLIB_UNUSED(fib_source_t source);
984 : const fib_entry_src_t *src;
985 :
986 73197 : FOR_EACH_SRC_ADDED(cover, src, source,
987 : ({
988 : if ((src->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
989 : (src->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
990 : {
991 : fib_entry_src_covered_inherit_add_i(covered, src);
992 : }
993 : }))
994 36564 : }
995 :
996 : static void
997 44216 : fib_entry_src_covered_inherit_add (fib_entry_t *fib_entry,
998 : fib_source_t source)
999 :
1000 : {
1001 : fib_entry_src_t *esrc;
1002 :
1003 44216 : esrc = fib_entry_src_find(fib_entry, source);
1004 :
1005 44216 : ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
1006 :
1007 44216 : if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
1008 44202 : (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
1009 : {
1010 54 : fib_table_sub_tree_walk(fib_entry->fe_fib_index,
1011 54 : fib_entry->fe_prefix.fp_proto,
1012 : &fib_entry->fe_prefix,
1013 : fib_entry_src_covered_inherit_walk_add,
1014 : esrc);
1015 : }
1016 44216 : }
1017 :
1018 : static void
1019 31479 : fib_entry_src_covered_inherit_remove (fib_entry_t *fib_entry,
1020 : fib_entry_src_t *esrc)
1021 :
1022 : {
1023 31479 : ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
1024 :
1025 31479 : if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
1026 : {
1027 8 : fib_table_sub_tree_walk(fib_entry->fe_fib_index,
1028 8 : fib_entry->fe_prefix.fp_proto,
1029 : &fib_entry->fe_prefix,
1030 : fib_entry_src_covered_inherit_walk_remove,
1031 : esrc);
1032 : }
1033 31479 : }
1034 :
1035 : void
1036 41497 : fib_entry_src_action_activate (fib_entry_t *fib_entry,
1037 : fib_source_t source)
1038 :
1039 : {
1040 : int houston_we_are_go_for_install;
1041 : const fib_entry_src_vft_t *vft;
1042 : fib_entry_src_t *esrc;
1043 :
1044 41497 : esrc = fib_entry_src_find(fib_entry, source);
1045 :
1046 41497 : ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
1047 41497 : ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
1048 :
1049 41497 : esrc->fes_flags |= (FIB_ENTRY_SRC_FLAG_ACTIVE |
1050 : FIB_ENTRY_SRC_FLAG_CONTRIBUTING);
1051 41497 : vft = fib_entry_src_get_vft(esrc);
1052 :
1053 41497 : if (NULL != vft->fesv_activate)
1054 : {
1055 24404 : houston_we_are_go_for_install = vft->fesv_activate(esrc, fib_entry);
1056 : }
1057 : else
1058 : {
1059 : /*
1060 : * the source is not providing an activate function, we'll assume
1061 : * therefore it has no objection to installing the entry
1062 : */
1063 17093 : houston_we_are_go_for_install = !0;
1064 : }
1065 :
1066 : /*
1067 : * link to the path-list provided by the source, and go check
1068 : * if that forms any loops in the graph.
1069 : */
1070 41497 : fib_entry->fe_parent = esrc->fes_pl;
1071 41497 : fib_entry->fe_sibling =
1072 41497 : fib_path_list_child_add(fib_entry->fe_parent,
1073 : FIB_NODE_TYPE_ENTRY,
1074 : fib_entry_get_index(fib_entry));
1075 :
1076 41497 : fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
1077 :
1078 41497 : FIB_ENTRY_DBG(fib_entry, "activate: %d",
1079 : fib_entry->fe_parent);
1080 :
1081 : /*
1082 : * If this source should push its state to covered prefixs, do that now.
1083 : */
1084 41497 : fib_entry_src_covered_inherit_add(fib_entry, source);
1085 :
1086 41497 : if (0 != houston_we_are_go_for_install)
1087 : {
1088 41061 : fib_entry_src_action_install(fib_entry, source);
1089 : }
1090 : else
1091 : {
1092 436 : fib_entry_src_action_uninstall(fib_entry);
1093 : }
1094 41497 : }
1095 :
1096 : void
1097 31479 : fib_entry_src_action_deactivate (fib_entry_t *fib_entry,
1098 : fib_source_t source)
1099 :
1100 : {
1101 : fib_node_index_t path_list_index;
1102 : fib_entry_src_t *esrc;
1103 :
1104 31479 : esrc = fib_entry_src_find(fib_entry, source);
1105 :
1106 31479 : ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
1107 :
1108 31479 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_deactivate,
1109 : (esrc, fib_entry));
1110 :
1111 31479 : esrc->fes_flags &= ~(FIB_ENTRY_SRC_FLAG_ACTIVE |
1112 : FIB_ENTRY_SRC_FLAG_CONTRIBUTING);
1113 :
1114 31479 : FIB_ENTRY_DBG(fib_entry, "deactivate: %d", fib_entry->fe_parent);
1115 :
1116 : /*
1117 : * If this source should pull its state from covered prefixs, do that now.
1118 : * If this source also has the INHERITED flag set then it has a cover
1119 : * that wants to push down forwarding. We only want the covereds to see
1120 : * one update.
1121 : */
1122 31479 : fib_entry_src_covered_inherit_remove(fib_entry, esrc);
1123 :
1124 : /*
1125 : * un-link from an old path-list. Check for any loops this will clear
1126 : */
1127 31479 : path_list_index = fib_entry->fe_parent;
1128 31479 : fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
1129 :
1130 31479 : fib_entry_recursive_loop_detect_i(path_list_index);
1131 :
1132 : /*
1133 : * this will unlock the path-list, so it may be invalid thereafter.
1134 : */
1135 31479 : fib_path_list_child_remove(path_list_index, fib_entry->fe_sibling);
1136 31479 : fib_entry->fe_sibling = FIB_NODE_INDEX_INVALID;
1137 31479 : }
1138 :
1139 : static void
1140 88558 : fib_entry_src_action_fwd_update (const fib_entry_t *fib_entry,
1141 : fib_source_t source)
1142 : {
1143 : fib_entry_src_t *esrc;
1144 :
1145 185297 : vec_foreach(esrc, fib_entry->fe_srcs)
1146 : {
1147 96739 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_fwd_update,
1148 : (esrc, fib_entry, source));
1149 : }
1150 88558 : }
1151 :
1152 : void
1153 41237 : fib_entry_src_action_reactivate (fib_entry_t *fib_entry,
1154 : fib_source_t source)
1155 : {
1156 : fib_node_index_t path_list_index;
1157 : const fib_entry_src_vft_t *vft;
1158 : fib_entry_src_t *esrc;
1159 : int remain_installed;
1160 :
1161 41237 : esrc = fib_entry_src_find(fib_entry, source);
1162 :
1163 41237 : ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
1164 :
1165 41237 : FIB_ENTRY_DBG(fib_entry, "reactivate: %d to %d",
1166 : fib_entry->fe_parent,
1167 : esrc->fes_pl);
1168 :
1169 : /*
1170 : * call the source to reactive and get the go/no-go to remain installed
1171 : */
1172 41237 : vft = fib_entry_src_get_vft(esrc);
1173 :
1174 41237 : if (NULL != vft->fesv_reactivate)
1175 : {
1176 14501 : remain_installed = vft->fesv_reactivate(esrc, fib_entry);
1177 : }
1178 : else
1179 : {
1180 26736 : remain_installed = 1;
1181 : }
1182 :
1183 41237 : if (fib_entry->fe_parent != esrc->fes_pl)
1184 : {
1185 : /*
1186 : * un-link from an old path-list. Check for any loops this will clear
1187 : */
1188 2718 : path_list_index = fib_entry->fe_parent;
1189 2718 : fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
1190 :
1191 : /*
1192 : * temporary lock so it doesn't get deleted when this entry is no
1193 : * longer a child.
1194 : */
1195 2718 : fib_path_list_lock(path_list_index);
1196 :
1197 : /*
1198 : * this entry is no longer a child. after unlinking check if any loops
1199 : * were broken
1200 : */
1201 2718 : fib_path_list_child_remove(path_list_index,
1202 : fib_entry->fe_sibling);
1203 :
1204 2718 : fib_entry_recursive_loop_detect_i(path_list_index);
1205 :
1206 : /*
1207 : * link to the path-list provided by the source, and go check
1208 : * if that forms any loops in the graph.
1209 : */
1210 2718 : fib_entry->fe_parent = esrc->fes_pl;
1211 2718 : fib_entry->fe_sibling =
1212 2718 : fib_path_list_child_add(fib_entry->fe_parent,
1213 : FIB_NODE_TYPE_ENTRY,
1214 : fib_entry_get_index(fib_entry));
1215 :
1216 2718 : fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
1217 2718 : fib_path_list_unlock(path_list_index);
1218 :
1219 : /*
1220 : * If this source should push its state to covered prefixs, do that now.
1221 : */
1222 2718 : fib_entry_src_covered_inherit_add(fib_entry, source);
1223 : }
1224 :
1225 41237 : if (!remain_installed)
1226 : {
1227 4559 : fib_entry_src_action_uninstall(fib_entry);
1228 : }
1229 : else
1230 : {
1231 36678 : fib_entry_src_action_install(fib_entry, source);
1232 : }
1233 41237 : fib_entry_src_action_fwd_update(fib_entry, source);
1234 41237 : }
1235 :
1236 : fib_entry_t *
1237 47321 : fib_entry_src_action_installed (fib_entry_t *fib_entry,
1238 : fib_source_t source)
1239 : {
1240 : fib_entry_src_t *esrc;
1241 :
1242 47321 : esrc = fib_entry_src_find(fib_entry, source);
1243 :
1244 47321 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_installed,
1245 : (esrc, fib_entry));
1246 :
1247 47321 : fib_entry_src_action_fwd_update(fib_entry, source);
1248 :
1249 47321 : return (fib_entry);
1250 : }
1251 :
1252 : /*
1253 : * fib_entry_src_action_add
1254 : *
1255 : * Adding a source can result in a new fib_entry being created, which
1256 : * can inturn mean the pool is realloc'd and thus the entry passed as
1257 : * an argument it also realloc'd
1258 : * @return the original entry
1259 : */
1260 : fib_entry_t *
1261 47226 : fib_entry_src_action_add (fib_entry_t *fib_entry,
1262 : fib_source_t source,
1263 : fib_entry_flag_t flags,
1264 : const dpo_id_t *dpo)
1265 : {
1266 : fib_entry_src_t *esrc;
1267 :
1268 47226 : esrc = fib_entry_src_find_or_create(fib_entry, source, flags);
1269 :
1270 47226 : ASSERT(esrc->fes_ref_count < 255);
1271 47226 : esrc->fes_ref_count++;
1272 :
1273 47226 : if (flags != esrc->fes_entry_flags)
1274 : {
1275 0 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_flags_change,
1276 : (esrc, fib_entry, flags));
1277 : }
1278 47226 : esrc->fes_entry_flags = flags;
1279 :
1280 47226 : if (1 != esrc->fes_ref_count)
1281 : {
1282 : /*
1283 : * we only want to add the source on the 0->1 transition
1284 : */
1285 1882 : return (fib_entry);
1286 : }
1287 :
1288 45344 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_add,
1289 : (esrc,
1290 : fib_entry,
1291 : flags,
1292 : fib_entry_get_dpo_proto(fib_entry),
1293 : dpo));
1294 :
1295 45344 : esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1296 :
1297 45344 : fib_path_list_lock(esrc->fes_pl);
1298 :
1299 : /*
1300 : * the source owns a lock on the entry
1301 : */
1302 45344 : fib_entry_lock(fib_entry_get_index(fib_entry));
1303 :
1304 45344 : return (fib_entry);
1305 : }
1306 :
1307 : /*
1308 : * fib_entry_src_action_update
1309 : *
1310 : * Adding a source can result in a new fib_entry being created, which
1311 : * can inturn mean the pool is realloc'd and thus the entry passed as
1312 : * an argument it also realloc'd
1313 : * @return the original entry
1314 : */
1315 : fib_entry_t *
1316 1 : fib_entry_src_action_update (fib_entry_t *fib_entry,
1317 : fib_source_t source,
1318 : fib_entry_flag_t flags,
1319 : const dpo_id_t *dpo)
1320 : {
1321 : fib_node_index_t old_path_list_index;
1322 : fib_entry_src_t *esrc;
1323 :
1324 1 : esrc = fib_entry_src_find_or_create(fib_entry, source, flags);
1325 :
1326 1 : if (NULL == esrc)
1327 : {
1328 0 : return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
1329 : }
1330 :
1331 1 : old_path_list_index = esrc->fes_pl;
1332 1 : esrc->fes_entry_flags = flags;
1333 :
1334 1 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_add,
1335 : (esrc,
1336 : fib_entry,
1337 : flags,
1338 : fib_entry_get_dpo_proto(fib_entry),
1339 : dpo));
1340 :
1341 1 : esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1342 :
1343 1 : fib_path_list_lock(esrc->fes_pl);
1344 1 : fib_path_list_unlock(old_path_list_index);
1345 :
1346 1 : return (fib_entry);
1347 : }
1348 :
1349 : fib_entry_src_flag_t
1350 37128 : fib_entry_src_action_remove_or_update_inherit (fib_entry_t *fib_entry,
1351 : fib_source_t source)
1352 : {
1353 : fib_entry_src_t *esrc;
1354 :
1355 37128 : esrc = fib_entry_src_find(fib_entry, source);
1356 :
1357 37128 : if (NULL == esrc)
1358 17 : return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1359 :
1360 37111 : if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) &&
1361 7 : (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
1362 : {
1363 : fib_entry_src_t *cover_src;
1364 : fib_node_index_t coveri;
1365 : fib_entry_t *cover;
1366 :
1367 : /*
1368 : * this source was pushing inherited state, but so is its
1369 : * cover. Now that this source is going away, we need to
1370 : * pull the covers forwarding and use it to update the covereds.
1371 : * Go grab the path-list from the cover, rather than start a walk from
1372 : * the cover, so we don't recursively update this entry.
1373 : */
1374 1 : coveri = fib_table_get_less_specific(fib_entry->fe_fib_index,
1375 : &fib_entry->fe_prefix);
1376 :
1377 : /*
1378 : * only the default route has itself as its own cover, but the
1379 : * default route cannot have inherited from something else.
1380 : */
1381 1 : ASSERT(coveri != fib_entry_get_index(fib_entry));
1382 :
1383 1 : cover = fib_entry_get(coveri);
1384 1 : cover_src = fib_entry_src_find(cover, source);
1385 :
1386 1 : ASSERT(NULL != cover_src);
1387 :
1388 1 : esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
1389 1 : esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
1390 :
1391 : /*
1392 : * Now push the new state from the cover down to the covereds
1393 : */
1394 1 : fib_entry_src_covered_inherit_add(fib_entry, source);
1395 :
1396 1 : return (esrc->fes_flags);
1397 : }
1398 : else
1399 : {
1400 37110 : return (fib_entry_src_action_remove(fib_entry, source));
1401 : }
1402 : }
1403 :
1404 : fib_entry_src_flag_t
1405 37117 : fib_entry_src_action_remove (fib_entry_t *fib_entry,
1406 : fib_source_t source)
1407 :
1408 : {
1409 : fib_node_index_t old_path_list;
1410 : fib_entry_src_flag_t sflags;
1411 : fib_entry_src_t *esrc;
1412 :
1413 37117 : esrc = fib_entry_src_find(fib_entry, source);
1414 :
1415 37117 : if (NULL == esrc)
1416 0 : return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1417 :
1418 37117 : esrc->fes_ref_count--;
1419 37117 : sflags = esrc->fes_flags;
1420 :
1421 37117 : if (0 != esrc->fes_ref_count)
1422 : {
1423 : /*
1424 : * only remove the source on the 1->0 transisition
1425 : */
1426 1820 : return (sflags);
1427 : }
1428 :
1429 35297 : if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE)
1430 : {
1431 31185 : fib_entry_src_action_deactivate(fib_entry, source);
1432 : }
1433 4112 : else if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_CONTRIBUTING)
1434 : {
1435 9 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_deactivate,
1436 : (esrc, fib_entry));
1437 9 : esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_CONTRIBUTING;
1438 : }
1439 :
1440 35297 : old_path_list = esrc->fes_pl;
1441 :
1442 35297 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_remove, (esrc));
1443 :
1444 35297 : fib_path_list_unlock(old_path_list);
1445 35297 : fib_entry_unlock(fib_entry_get_index(fib_entry));
1446 :
1447 35297 : sflags &= ~FIB_ENTRY_SRC_FLAG_ADDED;
1448 35297 : fib_entry_src_action_deinit(fib_entry, source);
1449 :
1450 35297 : return (sflags);
1451 : }
1452 :
1453 : /*
1454 : * fib_route_attached_cross_table
1455 : *
1456 : * Return true the the route is attached via an interface that
1457 : * is not in the same table as the route
1458 : */
1459 : static int
1460 48552 : fib_route_attached_cross_table (const fib_entry_t *fib_entry,
1461 : const fib_route_path_t *rpath)
1462 : {
1463 48552 : const fib_prefix_t *pfx = &fib_entry->fe_prefix;
1464 :
1465 48552 : switch (pfx->fp_proto)
1466 : {
1467 54 : case FIB_PROTOCOL_MPLS:
1468 : /* MPLS routes are never imported/exported */
1469 54 : return (0);
1470 17672 : case FIB_PROTOCOL_IP6:
1471 : /* Ignore link local addresses these also can't be imported/exported */
1472 17672 : if (ip6_address_is_link_local_unicast (&pfx->fp_addr.ip6))
1473 : {
1474 4236 : return (0);
1475 : }
1476 13436 : break;
1477 30826 : case FIB_PROTOCOL_IP4:
1478 30826 : break;
1479 : }
1480 :
1481 : /*
1482 : * an attached path and entry's fib index not equal to interface's index
1483 : */
1484 61806 : if (fib_route_path_is_attached(rpath) &&
1485 17544 : fib_entry->fe_fib_index !=
1486 17544 : fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
1487 : rpath->frp_sw_if_index))
1488 : {
1489 10 : return (!0);
1490 : }
1491 44252 : return (0);
1492 : }
1493 :
1494 : fib_path_list_flags_t
1495 56503 : fib_entry_src_flags_2_path_list_flags (fib_entry_flag_t eflags)
1496 : {
1497 56503 : fib_path_list_flags_t plf = FIB_PATH_LIST_FLAG_NONE;
1498 :
1499 56503 : if (eflags & FIB_ENTRY_FLAG_DROP)
1500 : {
1501 6725 : plf |= FIB_PATH_LIST_FLAG_DROP;
1502 : }
1503 56503 : if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
1504 : {
1505 1485 : plf |= FIB_PATH_LIST_FLAG_EXCLUSIVE;
1506 : }
1507 56503 : if (eflags & FIB_ENTRY_FLAG_LOCAL)
1508 : {
1509 14443 : plf |= FIB_PATH_LIST_FLAG_LOCAL;
1510 : }
1511 :
1512 56503 : return (plf);
1513 : }
1514 :
1515 : static void
1516 34339 : fib_entry_flags_update (const fib_entry_t *fib_entry,
1517 : const fib_route_path_t *rpaths,
1518 : fib_path_list_flags_t *pl_flags,
1519 : fib_entry_src_t *esrc)
1520 : {
1521 : const fib_route_path_t *rpath;
1522 :
1523 82891 : vec_foreach(rpath, rpaths)
1524 : {
1525 48552 : if ((esrc->fes_src == FIB_SOURCE_API) ||
1526 29197 : (esrc->fes_src == FIB_SOURCE_CLI))
1527 : {
1528 19383 : if (fib_route_path_is_attached(rpath))
1529 : {
1530 12437 : esrc->fes_entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
1531 : }
1532 : else
1533 : {
1534 6946 : esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_ATTACHED;
1535 : }
1536 19383 : if (rpath->frp_flags & FIB_ROUTE_PATH_DEAG)
1537 : {
1538 64 : esrc->fes_entry_flags |= FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT;
1539 : }
1540 : }
1541 48552 : if (fib_route_attached_cross_table(fib_entry, rpath) &&
1542 10 : !(esrc->fes_entry_flags & FIB_ENTRY_FLAG_NO_ATTACHED_EXPORT))
1543 : {
1544 10 : esrc->fes_entry_flags |= FIB_ENTRY_FLAG_IMPORT;
1545 : }
1546 : else
1547 : {
1548 48542 : esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_IMPORT;
1549 : }
1550 : }
1551 34339 : }
1552 :
1553 : /*
1554 : * fib_entry_src_action_add
1555 : *
1556 : * Adding a source can result in a new fib_entry being created, which
1557 : * can inturn mean the pool is realloc'd and thus the entry passed as
1558 : * an argument it also realloc'd
1559 : * @return the entry
1560 : */
1561 : fib_entry_t*
1562 357 : fib_entry_src_action_path_add (fib_entry_t *fib_entry,
1563 : fib_source_t source,
1564 : fib_entry_flag_t flags,
1565 : const fib_route_path_t *rpaths)
1566 : {
1567 : fib_node_index_t old_path_list;
1568 : fib_path_list_flags_t pl_flags;
1569 : fib_entry_src_t *esrc;
1570 :
1571 357 : esrc = fib_entry_src_find(fib_entry, source);
1572 357 : if (NULL == esrc)
1573 : {
1574 : const dpo_id_t *dpo;
1575 :
1576 68 : if (flags == FIB_ENTRY_FLAG_EXCLUSIVE) {
1577 0 : dpo = &rpaths->dpo;
1578 : } else {
1579 68 : dpo = drop_dpo_get(fib_entry_get_dpo_proto(fib_entry));
1580 : }
1581 :
1582 : fib_entry =
1583 68 : fib_entry_src_action_add(fib_entry,
1584 : source,
1585 : flags,
1586 : dpo);
1587 68 : esrc = fib_entry_src_find(fib_entry, source);
1588 : }
1589 :
1590 : /*
1591 : * we are no doubt modifying a path-list. If the path-list
1592 : * is shared, and hence not modifiable, then the index returned
1593 : * will be for a different path-list. This FIB entry to needs
1594 : * to maintain its lock appropriately.
1595 : */
1596 357 : old_path_list = esrc->fes_pl;
1597 :
1598 357 : ASSERT(FIB_ENTRY_SRC_VFT_EXISTS(esrc, fesv_path_add));
1599 :
1600 357 : pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1601 357 : fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
1602 :
1603 357 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_path_add,
1604 : (esrc, fib_entry, pl_flags, rpaths));
1605 :
1606 357 : fib_path_list_lock(esrc->fes_pl);
1607 357 : fib_path_list_unlock(old_path_list);
1608 :
1609 357 : return (fib_entry);
1610 : }
1611 :
1612 : /*
1613 : * fib_entry_src_action_swap
1614 : *
1615 : * The source is providing new paths to replace the old ones.
1616 : * Adding a source can result in a new fib_entry being created, which
1617 : * can inturn mean the pool is realloc'd and thus the entry passed as
1618 : * an argument it also realloc'd
1619 : * @return the entry
1620 : */
1621 : fib_entry_t*
1622 28385 : fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
1623 : fib_source_t source,
1624 : fib_entry_flag_t flags,
1625 : const fib_route_path_t *rpaths)
1626 : {
1627 : fib_node_index_t old_path_list;
1628 : fib_path_list_flags_t pl_flags;
1629 : fib_entry_src_t *esrc;
1630 :
1631 28385 : esrc = fib_entry_src_find(fib_entry, source);
1632 :
1633 28385 : if (NULL == esrc)
1634 : {
1635 : const dpo_id_t *dpo;
1636 :
1637 188 : if (flags == FIB_ENTRY_FLAG_EXCLUSIVE) {
1638 0 : dpo = &rpaths->dpo;
1639 : } else {
1640 188 : dpo = drop_dpo_get(fib_entry_get_dpo_proto(fib_entry));
1641 : }
1642 :
1643 188 : fib_entry = fib_entry_src_action_add(fib_entry,
1644 : source,
1645 : flags,
1646 : dpo);
1647 188 : esrc = fib_entry_src_find(fib_entry, source);
1648 : }
1649 : else
1650 : {
1651 28197 : if (flags != esrc->fes_entry_flags)
1652 : {
1653 2173 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_flags_change,
1654 : (esrc, fib_entry, flags));
1655 : }
1656 28197 : esrc->fes_entry_flags = flags;
1657 : }
1658 :
1659 : /*
1660 : * swapping paths may create a new path-list (or may use an existing shared)
1661 : * but we are certainly getting a different one. This FIB entry to needs
1662 : * to maintain its lock appropriately.
1663 : */
1664 28385 : old_path_list = esrc->fes_pl;
1665 :
1666 28385 : ASSERT(FIB_ENTRY_SRC_VFT_EXISTS(esrc, fesv_path_swap));
1667 :
1668 28385 : pl_flags = fib_entry_src_flags_2_path_list_flags(flags);
1669 :
1670 28385 : fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
1671 :
1672 28385 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_path_swap,
1673 : (esrc, fib_entry,
1674 : pl_flags, rpaths));
1675 :
1676 28385 : fib_path_list_lock(esrc->fes_pl);
1677 28385 : fib_path_list_unlock(old_path_list);
1678 :
1679 28385 : return (fib_entry);
1680 : }
1681 :
1682 : fib_entry_src_flag_t
1683 5597 : fib_entry_src_action_path_remove (fib_entry_t *fib_entry,
1684 : fib_source_t source,
1685 : const fib_route_path_t *rpaths)
1686 : {
1687 : fib_path_list_flags_t pl_flags;
1688 : fib_node_index_t old_path_list;
1689 : fib_entry_src_t *esrc;
1690 :
1691 5597 : esrc = fib_entry_src_find(fib_entry, source);
1692 :
1693 5597 : ASSERT(NULL != esrc);
1694 5597 : ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
1695 :
1696 : /*
1697 : * we no doubt modifying a path-list. If the path-list
1698 : * is shared, and hence not modifiable, then the index returned
1699 : * will be for a different path-list. This FIB entry to needs
1700 : * to maintain its lock appropriately.
1701 : */
1702 5597 : old_path_list = esrc->fes_pl;
1703 :
1704 5597 : ASSERT(FIB_ENTRY_SRC_VFT_EXISTS(esrc, fesv_path_remove));
1705 :
1706 5597 : pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1707 5597 : fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
1708 :
1709 5597 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_path_remove,
1710 : (esrc, pl_flags, rpaths));
1711 :
1712 : /*
1713 : * lock the new path-list, unlock the old if it had one
1714 : */
1715 5597 : fib_path_list_unlock(old_path_list);
1716 :
1717 5597 : if (FIB_NODE_INDEX_INVALID != esrc->fes_pl) {
1718 16 : fib_path_list_lock(esrc->fes_pl);
1719 16 : return (FIB_ENTRY_SRC_FLAG_ADDED);
1720 : }
1721 : else
1722 : {
1723 : /*
1724 : * no more paths left from this source
1725 : */
1726 5581 : fib_entry_src_action_remove_or_update_inherit(fib_entry, source);
1727 5581 : return (FIB_ENTRY_SRC_FLAG_NONE);
1728 : }
1729 : }
1730 :
1731 : u8*
1732 216 : fib_entry_src_format (fib_entry_t *fib_entry,
1733 : fib_source_t source,
1734 : u8* s)
1735 : {
1736 : fib_entry_src_t *esrc;
1737 :
1738 216 : esrc = fib_entry_src_find(fib_entry, source);
1739 :
1740 216 : FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_format, (esrc, s));
1741 :
1742 145 : return (s);
1743 : }
1744 :
1745 : adj_index_t
1746 0 : fib_entry_get_adj_for_source (fib_node_index_t fib_entry_index,
1747 : fib_source_t source)
1748 : {
1749 : fib_entry_t *fib_entry;
1750 : fib_entry_src_t *esrc;
1751 :
1752 0 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1753 0 : return (ADJ_INDEX_INVALID);
1754 :
1755 0 : fib_entry = fib_entry_get(fib_entry_index);
1756 0 : esrc = fib_entry_src_find(fib_entry, source);
1757 :
1758 0 : if (NULL != esrc)
1759 : {
1760 0 : if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1761 : {
1762 0 : return (fib_path_list_get_adj(
1763 : esrc->fes_pl,
1764 0 : fib_entry_get_default_chain_type(fib_entry)));
1765 : }
1766 : }
1767 0 : return (ADJ_INDEX_INVALID);
1768 : }
1769 :
1770 : const int
1771 0 : fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
1772 : fib_source_t source,
1773 : dpo_id_t *dpo)
1774 : {
1775 : fib_entry_t *fib_entry;
1776 : fib_entry_src_t *esrc;
1777 :
1778 0 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1779 0 : return (0);
1780 :
1781 0 : fib_entry = fib_entry_get(fib_entry_index);
1782 0 : esrc = fib_entry_src_find(fib_entry, source);
1783 :
1784 0 : if (NULL != esrc)
1785 : {
1786 0 : if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1787 : {
1788 0 : fib_path_list_contribute_forwarding(
1789 : esrc->fes_pl,
1790 0 : fib_entry_get_default_chain_type(fib_entry),
1791 : FIB_PATH_LIST_FWD_FLAG_NONE,
1792 : dpo);
1793 :
1794 0 : return (dpo_id_is_valid(dpo));
1795 : }
1796 : }
1797 0 : return (0);
1798 : }
1799 :
1800 : fib_node_index_t
1801 0 : fib_entry_get_path_list_for_source (fib_node_index_t fib_entry_index,
1802 : fib_source_t source)
1803 : {
1804 : fib_entry_t *fib_entry;
1805 : fib_entry_src_t *esrc;
1806 :
1807 0 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1808 0 : return FIB_NODE_INDEX_INVALID;
1809 :
1810 0 : fib_entry = fib_entry_get(fib_entry_index);
1811 0 : esrc = fib_entry_src_find(fib_entry, source);
1812 :
1813 0 : if (esrc)
1814 0 : return esrc->fes_pl;
1815 :
1816 0 : return FIB_NODE_INDEX_INVALID;
1817 : }
1818 :
1819 : u32
1820 2121 : fib_entry_get_resolving_interface_for_source (fib_node_index_t entry_index,
1821 : fib_source_t source)
1822 : {
1823 : fib_entry_t *fib_entry;
1824 : fib_entry_src_t *esrc;
1825 :
1826 2121 : fib_entry = fib_entry_get(entry_index);
1827 :
1828 2121 : esrc = fib_entry_src_find(fib_entry, source);
1829 :
1830 2121 : if (NULL != esrc)
1831 : {
1832 2121 : if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1833 : {
1834 2121 : return (fib_path_list_get_resolving_interface(esrc->fes_pl));
1835 : }
1836 : }
1837 0 : return (~0);
1838 : }
1839 :
1840 : fib_entry_flag_t
1841 20578 : fib_entry_get_flags_for_source (fib_node_index_t entry_index,
1842 : fib_source_t source)
1843 : {
1844 : fib_entry_t *fib_entry;
1845 : fib_entry_src_t *esrc;
1846 :
1847 20578 : fib_entry = fib_entry_get(entry_index);
1848 :
1849 20578 : esrc = fib_entry_src_find(fib_entry, source);
1850 :
1851 20578 : if (NULL != esrc)
1852 : {
1853 18117 : return (esrc->fes_entry_flags);
1854 : }
1855 :
1856 2461 : return (FIB_ENTRY_FLAG_NONE);
1857 : }
1858 :
1859 : fib_source_t
1860 413851 : fib_entry_get_source_i (const fib_entry_t *fib_entry)
1861 : {
1862 : /* the vector of sources is deliberately arranged in priority order */
1863 413851 : if (0 == vec_len(fib_entry->fe_srcs))
1864 71279 : return (FIB_SOURCE_INVALID);
1865 342572 : return (vec_elt(fib_entry->fe_srcs, 0).fes_src);
1866 : }
1867 :
1868 : fib_entry_flag_t
1869 673462 : fib_entry_get_flags_i (const fib_entry_t *fib_entry)
1870 : {
1871 : /* the vector of sources is deliberately arranged in priority order */
1872 673462 : if (0 == vec_len(fib_entry->fe_srcs))
1873 132999 : return (FIB_ENTRY_FLAG_NONE);
1874 540463 : return (vec_elt(fib_entry->fe_srcs, 0).fes_entry_flags);
1875 : }
1876 :
1877 : void
1878 281 : fib_entry_set_source_data (fib_node_index_t fib_entry_index,
1879 : fib_source_t source,
1880 : const void *data)
1881 : {
1882 : fib_entry_t *fib_entry;
1883 : fib_entry_src_t *esrc;
1884 :
1885 281 : fib_entry = fib_entry_get(fib_entry_index);
1886 281 : esrc = fib_entry_src_find(fib_entry, source);
1887 :
1888 281 : if (NULL != esrc)
1889 : {
1890 281 : FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_set_data,
1891 : (esrc, fib_entry, data));
1892 : }
1893 281 : }
1894 :
1895 : const void*
1896 140 : fib_entry_get_source_data (fib_node_index_t fib_entry_index,
1897 : fib_source_t source)
1898 : {
1899 : fib_entry_t *fib_entry;
1900 : fib_entry_src_t *esrc;
1901 :
1902 140 : fib_entry = fib_entry_get(fib_entry_index);
1903 140 : esrc = fib_entry_src_find(fib_entry, source);
1904 :
1905 140 : if (NULL != esrc)
1906 : {
1907 140 : FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_get_data,
1908 : (esrc, fib_entry));
1909 : }
1910 0 : return (NULL);
1911 : }
1912 :
1913 : void
1914 575 : fib_entry_src_module_init (void)
1915 : {
1916 575 : fib_entry_src_rr_register();
1917 575 : fib_entry_src_interface_register();
1918 575 : fib_entry_src_interpose_register();
1919 575 : fib_entry_src_drop_register();
1920 575 : fib_entry_src_simple_register();
1921 575 : fib_entry_src_api_register();
1922 575 : fib_entry_src_adj_register();
1923 575 : fib_entry_src_mpls_register();
1924 575 : fib_entry_src_lisp_register();
1925 575 : }
|