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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <vlib/vlib.h>
17 #include <vnet/ip/format.h>
18 #include <vnet/ip/lookup.h>
19 #include <vnet/adj/adj.h>
20 #include <vnet/dpo/load_balance.h>
21 #include <vnet/dpo/drop_dpo.h>
23 #include <vnet/fib/fib_entry.h>
24 #include <vnet/fib/fib_walk.h>
25 #include <vnet/fib/fib_entry_src.h>
26 #include <vnet/fib/fib_entry_cover.h>
27 #include <vnet/fib/fib_table.h>
28 #include <vnet/fib/fib_internal.h>
29 #include <vnet/fib/fib_attached_export.h>
30 #include <vnet/fib/fib_path_ext.h>
33 * Array of strings/names for the FIB sources
35 static const char *fib_source_names[] = FIB_SOURCES;
36 static const char *fib_attribute_names[] = FIB_ENTRY_ATTRIBUTES;
39 * Pool for all fib_entries
41 static fib_entry_t *fib_entry_pool;
44 fib_entry_get (fib_node_index_t index)
46 return (pool_elt_at_index(fib_entry_pool, index));
50 fib_entry_get_node (fib_node_index_t index)
52 return ((fib_node_t*)fib_entry_get(index));
56 fib_entry_get_index (const fib_entry_t * fib_entry)
58 return (fib_entry - fib_entry_pool);
62 fib_entry_get_proto (const fib_entry_t * fib_entry)
64 return (fib_entry->fe_prefix.fp_proto);
68 * @brief Turn the chain type requested by the client into the one they
71 static fib_forward_chain_type_t
72 fib_entry_chain_type_fixup (const fib_entry_t *entry,
73 fib_forward_chain_type_t fct)
75 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == fct)
78 * The EOS chain is a tricky since one cannot know the adjacency
79 * to link to without knowing what the packets payload protocol
80 * will be once the label is popped.
82 fib_forward_chain_type_t dfct;
84 dfct = fib_entry_get_default_chain_type(entry);
86 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == dfct)
89 * If the entry being asked is a eos-MPLS label entry,
90 * then use the payload-protocol field, that we stashed there
91 * for just this purpose
93 return (fib_forw_chain_type_from_dpo_proto(
94 entry->fe_prefix.fp_payload_proto));
97 * else give them what this entry would be by default. i.e. if it's a v6
98 * entry, then the label its local labelled should be carrying v6 traffic.
99 * If it's a non-EOS label entry, then there are more labels and we want
108 fib_forward_chain_type_t
109 fib_entry_get_default_chain_type (const fib_entry_t *fib_entry)
111 switch (fib_entry->fe_prefix.fp_proto)
113 case FIB_PROTOCOL_IP4:
114 return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
115 case FIB_PROTOCOL_IP6:
116 return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
117 case FIB_PROTOCOL_MPLS:
118 if (MPLS_EOS == fib_entry->fe_prefix.fp_eos)
120 * If the entry being asked is a eos-MPLS label entry,
121 * then use the payload-protocol field, that we stashed there
122 * for just this purpose
124 return (fib_forw_chain_type_from_dpo_proto(
125 fib_entry->fe_prefix.fp_payload_proto));
127 return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
130 return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
134 format_fib_entry (u8 * s, va_list * args)
136 fib_forward_chain_type_t fct;
137 fib_entry_attribute_t attr;
138 fib_path_ext_t *path_ext;
139 fib_entry_t *fib_entry;
140 fib_entry_src_t *src;
141 fib_node_index_t fei;
146 fei = va_arg (*args, fib_node_index_t);
147 level = va_arg (*args, int);
148 fib_entry = fib_entry_get(fei);
150 s = format (s, "%U", format_fib_prefix, &fib_entry->fe_prefix);
152 if (level >= FIB_ENTRY_FORMAT_DETAIL)
154 s = format (s, " fib:%d", fib_entry->fe_fib_index);
155 s = format (s, " index:%d", fib_entry_get_index(fib_entry));
156 s = format (s, " locks:%d", fib_entry->fe_node.fn_locks);
158 FOR_EACH_SRC_ADDED(fib_entry, src, source,
160 s = format (s, "\n src:%s ",
161 fib_source_names[source]);
162 s = fib_entry_src_format(fib_entry, source, s);
163 s = format (s, " refs:%d ", src->fes_ref_count);
164 if (FIB_ENTRY_FLAG_NONE != src->fes_entry_flags) {
165 s = format(s, "flags:");
166 FOR_EACH_FIB_ATTRIBUTE(attr) {
167 if ((1<<attr) & src->fes_entry_flags) {
168 s = format (s, "%s,", fib_attribute_names[attr]);
172 s = format (s, "\n");
173 if (FIB_NODE_INDEX_INVALID != src->fes_pl)
175 s = fib_path_list_format(src->fes_pl, s);
177 if (NULL != src->fes_path_exts)
179 s = format(s, " Extensions:");
180 vec_foreach(path_ext, src->fes_path_exts)
182 s = format(s, "\n %U", format_fib_path_ext, path_ext);
187 n_covered = fib_entry_cover_get_size(fib_entry);
189 s = format(s, "\n tracking %d covered: ", n_covered);
190 s = fib_entry_cover_list_format(fib_entry, s);
192 s = fib_ae_import_format(fib_entry->fe_import, s);
193 s = fib_ae_export_format(fib_entry->fe_export, s);
195 s = format (s, "\n forwarding: ");
199 s = format (s, "\n");
202 fct = fib_entry_get_default_chain_type(fib_entry);
204 if (!dpo_id_is_valid(&fib_entry->fe_lb[fct]))
206 s = format (s, " UNRESOLVED\n");
211 if (level >= FIB_ENTRY_FORMAT_DETAIL2)
214 FOR_EACH_FIB_FORW_MPLS_CHAIN(fct)
216 s = format(s, " %U-chain\n %U",
217 format_fib_forw_chain_type, fct,
219 &fib_entry->fe_lb[fct],
226 s = format(s, " %U-chain\n %U",
227 format_fib_forw_chain_type, fct,
229 &fib_entry->fe_lb[fct],
235 if (level >= FIB_ENTRY_FORMAT_DETAIL2)
237 s = format(s, "\nchildren:");
238 s = fib_node_children_format(fib_entry->fe_node.fn_children, s);
241 /* adj = adj_get(fib_entry->fe_prefix.fp_proto, fib_entry->fe_adj_index); */
243 /* ip_multipath_next_hop_t * nhs, tmp_nhs[1]; */
244 /* u32 i, j, n_left, n_nhs; */
245 /* vlib_counter_t c, sum; */
246 /* ip_lookup_main_t *lm = fib_get_lookup_main(fib_entry->fe_prefix.fp_proto); */
248 /* if (adj->n_adj == 1) */
250 /* nhs = &tmp_nhs[0]; */
251 /* nhs[0].next_hop_adj_index = ~0; /\* not used *\/ */
252 /* nhs[0].weight = 1; */
257 /* ip_multipath_adjacency_t * madj; */
258 /* madj = vec_elt_at_index (lm->multipath_adjacencies, adj->heap_handle); */
259 /* nhs = heap_elt_at_index (lm->next_hop_heap, madj->normalized_next_hops.heap_offset); */
260 /* n_nhs = madj->normalized_next_hops.count; */
263 /* n_left = nhs[0].weight; */
264 /* vlib_counter_zero (&sum); */
265 /* for (i = j = 0; i < adj->n_adj; i++) */
268 /* vlib_get_combined_counter(&lm->adjacency_counters, */
269 /* fib_entry->fe_adj_index + i, */
271 /* /\* if (clear) *\/ */
272 /* /\* vlib_zero_combined_counter (&lm->adjacency_counters, *\/ */
273 /* /\* fib_entry->fe_adj_index + i); *\/ */
275 /* vlib_counter_add (&sum, &c); */
276 /* if (n_left == 0) */
278 /* s = format (s, "%16Ld%16Ld ", sum.packets, sum.bytes); */
279 /* s = format (s, "weight %d, index %d", */
280 /* nhs[j].weight, fib_entry->fe_adj_index + i); */
282 /* if (adj->n_adj > 1) */
283 /* s = format (s, ", multipath"); */
285 /* s = format (s, "\n%U", */
286 /* format_ip_adjacency, */
287 /* vnet_get_main(), lm, fib_entry->fe_adj_index + i); */
289 /* // vlib_cli_output (vm, "%v", msg); */
290 /* //vec_free (msg); */
297 /* n_left = nhs[j].weight; */
298 /* vlib_counter_zero (&sum); */
307 fib_entry_from_fib_node (fib_node_t *node)
310 ASSERT(FIB_NODE_TYPE_ENTRY == node->fn_type);
312 return ((fib_entry_t*)node);
316 fib_entry_last_lock_gone (fib_node_t *node)
318 fib_forward_chain_type_t fct;
319 fib_entry_t *fib_entry;
321 fib_entry = fib_entry_from_fib_node(node);
323 FOR_EACH_FIB_FORW_MPLS_CHAIN(fct)
325 dpo_reset(&fib_entry->fe_lb[fct]);
328 FIB_ENTRY_DBG(fib_entry, "last-lock");
330 fib_node_deinit(&fib_entry->fe_node);
331 // FIXME -RR Backwalk
332 pool_put(fib_entry_pool, fib_entry);
335 static fib_entry_src_t*
336 fib_entry_get_best_src_i (const fib_entry_t *fib_entry)
338 fib_entry_src_t *bsrc;
341 * the enum of sources is deliberately arranged in priority order
343 if (0 == vec_len(fib_entry->fe_srcs))
349 bsrc = vec_elt_at_index(fib_entry->fe_srcs, 0);
356 fib_entry_src_get_source (const fib_entry_src_t *esrc)
360 return (esrc->fes_src);
362 return (FIB_SOURCE_MAX);
365 static fib_entry_flag_t
366 fib_entry_src_get_flags (const fib_entry_src_t *esrc)
370 return (esrc->fes_entry_flags);
372 return (FIB_ENTRY_FLAG_NONE);
376 fib_entry_get_flags (fib_node_index_t fib_entry_index)
378 return (fib_entry_get_flags_i(fib_entry_get(fib_entry_index)));
382 * fib_entry_back_walk_notify
384 * A back walk has reach this entry.
386 static fib_node_back_walk_rc_t
387 fib_entry_back_walk_notify (fib_node_t *node,
388 fib_node_back_walk_ctx_t *ctx)
390 fib_entry_t *fib_entry;
392 fib_entry = fib_entry_from_fib_node(node);
394 if (FIB_NODE_BW_REASON_FLAG_EVALUATE & ctx->fnbw_reason ||
395 FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE & ctx->fnbw_reason ||
396 FIB_NODE_BW_REASON_FLAG_INTERFACE_UP & ctx->fnbw_reason ||
397 FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN & ctx->fnbw_reason ||
398 FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE & ctx->fnbw_reason)
400 fib_entry_src_action_reactivate(fib_entry,
401 fib_entry_get_best_source(
402 fib_entry_get_index(fib_entry)));
406 * all other walk types can be reclassifed to a re-evaluate to
407 * all recursive dependents.
408 * By reclassifying we ensure that should any of these walk types meet
409 * they can be merged.
411 ctx->fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
414 * propagate the backwalk further if we haven't already reached the
417 fib_walk_sync(FIB_NODE_TYPE_ENTRY,
418 fib_entry_get_index(fib_entry),
421 return (FIB_NODE_BACK_WALK_CONTINUE);
425 fib_entry_show_memory (void)
427 u32 n_srcs = 0, n_exts = 0;
428 fib_entry_src_t *esrc;
431 fib_show_memory_usage("Entry",
432 pool_elts(fib_entry_pool),
433 pool_len(fib_entry_pool),
434 sizeof(fib_entry_t));
436 pool_foreach(entry, fib_entry_pool,
438 n_srcs += vec_len(entry->fe_srcs);
439 vec_foreach(esrc, entry->fe_srcs)
441 n_exts += vec_len(esrc->fes_path_exts);
445 fib_show_memory_usage("Entry Source",
446 n_srcs, n_srcs, sizeof(fib_entry_src_t));
447 fib_show_memory_usage("Entry Path-Extensions",
449 sizeof(fib_path_ext_t));
453 * The FIB path-list's graph node virtual function table
455 static const fib_node_vft_t fib_entry_vft = {
456 .fnv_get = fib_entry_get_node,
457 .fnv_last_lock = fib_entry_last_lock_gone,
458 .fnv_back_walk = fib_entry_back_walk_notify,
459 .fnv_mem_show = fib_entry_show_memory,
463 * @brief Contribute the set of Adjacencies that this entry forwards with
464 * to build the uRPF list of its children
467 fib_entry_contribute_urpf (fib_node_index_t entry_index,
470 fib_entry_t *fib_entry;
472 fib_entry = fib_entry_get(entry_index);
474 return (fib_path_list_contribute_urpf(fib_entry->fe_parent, urpf));
478 * fib_entry_contribute_forwarding
480 * Get an lock the forwarding information (DPO) contributed by the FIB entry.
483 fib_entry_contribute_forwarding (fib_node_index_t fib_entry_index,
484 fib_forward_chain_type_t type,
487 fib_entry_t *fib_entry;
489 fib_entry = fib_entry_get(fib_entry_index);
492 * these are not the droids you are looking for...
494 type = fib_entry_chain_type_fixup(fib_entry, type);
496 if (!dpo_id_is_valid(&fib_entry->fe_lb[type]))
499 * on-demand create eos/non-eos.
500 * There is no on-demand delete because:
501 * - memory versus complexity & reliability:
502 * leaving unrequired [n]eos LB arounds wastes memory, cleaning
503 * then up on the right trigger is more code. i favour the latter.
505 fib_entry_src_mk_lb(fib_entry,
506 fib_entry_get_best_src_i(fib_entry),
508 &fib_entry->fe_lb[type]);
511 dpo_copy(dpo, &fib_entry->fe_lb[type]);
515 fib_entry_contribute_ip_forwarding (fib_node_index_t fib_entry_index)
517 fib_entry_t *fib_entry;
519 fib_entry = fib_entry_get(fib_entry_index);
521 return (&fib_entry->fe_lb[fib_entry_get_default_chain_type(fib_entry)]);
525 fib_entry_get_adj (fib_node_index_t fib_entry_index)
529 dpo = fib_entry_contribute_ip_forwarding(fib_entry_index);
530 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
534 return (dpo->dpoi_index);
536 return (ADJ_INDEX_INVALID);
540 fib_entry_get_path_list (fib_node_index_t fib_entry_index)
542 fib_entry_t *fib_entry;
544 fib_entry = fib_entry_get(fib_entry_index);
546 return (fib_entry->fe_parent);
550 fib_entry_child_add (fib_node_index_t fib_entry_index,
551 fib_node_type_t child_type,
552 fib_node_index_t child_index)
554 return (fib_node_child_add(FIB_NODE_TYPE_ENTRY,
561 fib_entry_child_remove (fib_node_index_t fib_entry_index,
564 fib_node_child_remove(FIB_NODE_TYPE_ENTRY,
570 fib_entry_alloc (u32 fib_index,
571 const fib_prefix_t *prefix,
572 fib_node_index_t *fib_entry_index)
574 fib_forward_chain_type_t fct;
575 fib_entry_t *fib_entry;
577 pool_get(fib_entry_pool, fib_entry);
578 memset(fib_entry, 0, sizeof(*fib_entry));
580 fib_node_init(&fib_entry->fe_node,
581 FIB_NODE_TYPE_ENTRY);
583 fib_entry->fe_fib_index = fib_index;
584 fib_entry->fe_prefix = *prefix;
585 if (FIB_PROTOCOL_MPLS == fib_entry->fe_prefix.fp_proto)
587 fib_entry->fe_prefix.fp_len = 21;
588 ASSERT(DPO_PROTO_NONE != fib_entry->fe_prefix.fp_payload_proto);
591 fib_entry->fe_export = FIB_NODE_INDEX_INVALID;
592 fib_entry->fe_import = FIB_NODE_INDEX_INVALID;
593 fib_entry->fe_covered = FIB_NODE_INDEX_INVALID;
594 FOR_EACH_FIB_FORW_MPLS_CHAIN(fct)
596 dpo_reset(&fib_entry->fe_lb[fct]);
599 *fib_entry_index = fib_entry_get_index(fib_entry);
601 FIB_ENTRY_DBG(fib_entry, "alloc");
607 fib_entry_post_flag_update_actions (fib_entry_t *fib_entry,
609 fib_entry_flag_t old_flags)
612 * handle changes to attached export for import entries
614 int is_import = (FIB_ENTRY_FLAG_IMPORT & fib_entry_get_flags_i(fib_entry));
615 int was_import = (FIB_ENTRY_FLAG_IMPORT & old_flags);
617 if (!was_import && is_import)
620 * transition from not exported to exported
624 * there is an assumption here that the entry resolves via only
625 * one interface and that it is the cross VRF interface.
627 u32 sw_if_index = fib_path_list_get_resolving_interface(fib_entry->fe_parent);
629 fib_attached_export_import(fib_entry,
630 fib_table_get_index_for_sw_if_index(
631 fib_entry_get_proto(fib_entry),
634 else if (was_import && !is_import)
637 * transition from exported to not exported
639 fib_attached_export_purge(fib_entry);
643 * no change. nothing to do.
647 * handle changes to attached export for export entries
649 int is_attached = (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(fib_entry));
650 int was_attached = (FIB_ENTRY_FLAG_ATTACHED & old_flags);
652 if (!was_attached && is_attached)
655 * transition to attached. time to export
663 fib_entry_post_install_actions (fib_entry_t *fib_entry,
665 fib_entry_flag_t old_flags)
667 fib_entry_post_flag_update_actions(fib_entry, source, old_flags);
668 fib_entry_src_action_installed(fib_entry, source);
672 fib_entry_create (u32 fib_index,
673 const fib_prefix_t *prefix,
675 fib_entry_flag_t flags,
676 const fib_route_path_t *paths)
678 fib_node_index_t fib_entry_index;
679 fib_entry_t *fib_entry;
681 ASSERT(0 < vec_len(paths));
683 fib_entry = fib_entry_alloc(fib_index, prefix, &fib_entry_index);
686 * since this is a new entry create, we don't need to check for winning
687 * sources - there is only one.
689 fib_entry = fib_entry_src_action_add(fib_entry, source, flags,
692 fib_entry_get_proto(fib_entry))));
693 fib_entry_src_action_path_swap(fib_entry,
698 * handle possible realloc's by refetching the pointer
700 fib_entry = fib_entry_get(fib_entry_index);
701 fib_entry_src_action_activate(fib_entry, source);
703 fib_entry_post_install_actions(fib_entry, source, FIB_ENTRY_FLAG_NONE);
705 return (fib_entry_index);
709 fib_entry_create_special (u32 fib_index,
710 const fib_prefix_t *prefix,
712 fib_entry_flag_t flags,
715 fib_node_index_t fib_entry_index;
716 fib_entry_t *fib_entry;
719 * create and initiliase the new enty
721 fib_entry = fib_entry_alloc(fib_index, prefix, &fib_entry_index);
724 * create the path-list
726 fib_entry = fib_entry_src_action_add(fib_entry, source, flags, dpo);
727 fib_entry_src_action_activate(fib_entry, source);
729 fib_entry_post_install_actions(fib_entry, source, FIB_ENTRY_FLAG_NONE);
731 return (fib_entry_index);
735 fib_entry_post_update_actions (fib_entry_t *fib_entry,
737 fib_entry_flag_t old_flags)
740 * backwalk to children to inform then of the change to forwarding.
742 fib_node_back_walk_ctx_t bw_ctx = {
743 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
746 fib_walk_sync(FIB_NODE_TYPE_ENTRY, fib_entry_get_index(fib_entry), &bw_ctx);
749 * then inform any covered prefixes
751 fib_entry_cover_update_notify(fib_entry);
753 fib_entry_post_install_actions(fib_entry, source, old_flags);
757 fib_entry_special_add (fib_node_index_t fib_entry_index,
759 fib_entry_flag_t flags,
762 fib_source_t best_source;
763 fib_entry_flag_t bflags;
764 fib_entry_t *fib_entry;
765 fib_entry_src_t *bsrc;
767 fib_entry = fib_entry_get(fib_entry_index);
769 bsrc = fib_entry_get_best_src_i(fib_entry);
770 best_source = fib_entry_src_get_source(bsrc);
771 bflags = fib_entry_src_get_flags(bsrc);
773 fib_entry = fib_entry_src_action_add(fib_entry, source, flags, dpo);
776 * if the path list for the source passed is invalid,
777 * then we need to create a new one. else we are updating
780 if (source < best_source)
783 * we have a new winning source.
785 fib_entry_src_action_deactivate(fib_entry, best_source);
786 fib_entry_src_action_activate(fib_entry, source);
788 else if (source > best_source)
791 * the new source loses. nothing to do here.
792 * the data from the source is saved in the path-list created
799 * the new source is one this entry already has.
800 * But the path-list was updated, which will contribute new forwarding,
803 fib_entry_src_action_deactivate(fib_entry, source);
804 fib_entry_src_action_activate(fib_entry, source);
807 fib_entry_post_update_actions(fib_entry, source, bflags);
811 fib_entry_path_add (fib_node_index_t fib_entry_index,
813 fib_entry_flag_t flags,
814 const fib_route_path_t *rpath)
816 fib_source_t best_source;
817 fib_entry_flag_t bflags;
818 fib_entry_t *fib_entry;
819 fib_entry_src_t *bsrc;
821 ASSERT(1 == vec_len(rpath));
823 fib_entry = fib_entry_get(fib_entry_index);
824 ASSERT(NULL != fib_entry);
826 bsrc = fib_entry_get_best_src_i(fib_entry);
827 best_source = fib_entry_src_get_source(bsrc);
828 bflags = fib_entry_src_get_flags(bsrc);
830 fib_entry = fib_entry_src_action_path_add(fib_entry, source, flags, rpath);
833 * if the path list for the source passed is invalid,
834 * then we need to create a new one. else we are updating
837 if (source < best_source)
840 * we have a new winning source.
842 fib_entry_src_action_deactivate(fib_entry, best_source);
843 fib_entry_src_action_activate(fib_entry, source);
845 else if (source > best_source)
848 * the new source loses. nothing to do here.
849 * the data from the source is saved in the path-list created
856 * the new source is one this entry already has.
857 * But the path-list was updated, which will contribute new forwarding,
860 fib_entry_src_action_deactivate(fib_entry, source);
861 fib_entry_src_action_activate(fib_entry, source);
864 fib_entry_post_update_actions(fib_entry, source, bflags);
868 * fib_entry_path_remove
870 * remove a path from the entry.
871 * return the fib_entry's index if it is still present, INVALID otherwise.
874 fib_entry_path_remove (fib_node_index_t fib_entry_index,
876 const fib_route_path_t *rpath)
878 fib_entry_src_flag_t sflag;
879 fib_source_t best_source;
880 fib_entry_flag_t bflags;
881 fib_entry_t *fib_entry;
882 fib_entry_src_t *bsrc;
884 ASSERT(1 == vec_len(rpath));
886 fib_entry = fib_entry_get(fib_entry_index);
887 ASSERT(NULL != fib_entry);
889 bsrc = fib_entry_get_best_src_i(fib_entry);
890 best_source = fib_entry_src_get_source(bsrc);
891 bflags = fib_entry_src_get_flags(bsrc);
893 sflag = fib_entry_src_action_path_remove(fib_entry, source, rpath);
896 * if the path list for the source passed is invalid,
897 * then we need to create a new one. else we are updating
900 if (source < best_source )
903 * Que! removing a path from a source that is better than the
904 * one this entry is using.
908 else if (source > best_source )
911 * the source is not the best. nothing to do.
913 return (FIB_ENTRY_SRC_FLAG_ADDED);
918 * removing a path from the path-list we were using.
920 if (!(FIB_ENTRY_SRC_FLAG_ADDED & sflag))
923 * the last path from the source was removed.
924 * fallback to lower source
926 bsrc = fib_entry_get_best_src_i(fib_entry);
927 best_source = fib_entry_src_get_source(bsrc);
929 if (FIB_SOURCE_MAX == best_source) {
931 * no more sources left. this entry is toast.
933 fib_entry_src_action_uninstall(fib_entry);
934 fib_entry_post_flag_update_actions(fib_entry, source, bflags);
936 return (FIB_ENTRY_SRC_FLAG_NONE);
940 fib_entry_src_action_activate(fib_entry, best_source);
941 source = best_source;
947 * re-install the new forwarding information
949 fib_entry_src_action_deactivate(fib_entry, source);
950 fib_entry_src_action_activate(fib_entry, source);
954 fib_entry_post_update_actions(fib_entry, source, bflags);
959 return (FIB_ENTRY_SRC_FLAG_ADDED);
963 * fib_entry_special_remove
965 * remove a special source from the entry.
966 * return the fib_entry's index if it is still present, INVALID otherwise.
969 fib_entry_special_remove (fib_node_index_t fib_entry_index,
972 fib_entry_src_flag_t sflag;
973 fib_source_t best_source;
974 fib_entry_flag_t bflags;
975 fib_entry_t *fib_entry;
976 fib_entry_src_t *bsrc;
978 fib_entry = fib_entry_get(fib_entry_index);
979 ASSERT(NULL != fib_entry);
981 bsrc = fib_entry_get_best_src_i(fib_entry);
982 best_source = fib_entry_src_get_source(bsrc);
983 bflags = fib_entry_src_get_flags(bsrc);
985 sflag = fib_entry_src_action_remove(fib_entry, source);
988 * if the path list for the source passed is invalid,
989 * then we need to create a new one. else we are updating
992 if (source < best_source )
995 * Que! removing a path from a source that is better than the
996 * one this entry is using. This can only mean it is a source
997 * this prefix does not have.
999 return (FIB_ENTRY_SRC_FLAG_ADDED);
1001 else if (source > best_source ) {
1003 * the source is not the best. nothing to do.
1005 return (FIB_ENTRY_SRC_FLAG_ADDED);
1009 if (!(FIB_ENTRY_SRC_FLAG_ADDED & sflag))
1012 * the source was removed. use the next best.
1014 bsrc = fib_entry_get_best_src_i(fib_entry);
1015 best_source = fib_entry_src_get_source(bsrc);
1017 if (FIB_SOURCE_MAX == best_source) {
1019 * no more sources left. this entry is toast.
1021 fib_entry_src_action_uninstall(fib_entry);
1022 fib_entry_post_flag_update_actions(fib_entry, source, bflags);
1024 return (FIB_ENTRY_SRC_FLAG_NONE);
1028 fib_entry_src_action_activate(fib_entry, best_source);
1029 source = best_source;
1035 * re-install the new forwarding information
1037 fib_entry_src_action_reactivate(fib_entry, source);
1041 fib_entry_post_update_actions(fib_entry, source, bflags);
1044 * still have sources
1046 return (FIB_ENTRY_SRC_FLAG_ADDED);
1052 * The source is withdrawing all the paths it provided
1054 fib_entry_src_flag_t
1055 fib_entry_delete (fib_node_index_t fib_entry_index,
1056 fib_source_t source)
1058 return (fib_entry_special_remove(fib_entry_index, source));
1064 * The source has provided a new set of paths that will replace the old.
1067 fib_entry_update (fib_node_index_t fib_entry_index,
1068 fib_source_t source,
1069 fib_entry_flag_t flags,
1070 const fib_route_path_t *paths)
1072 fib_source_t best_source;
1073 fib_entry_flag_t bflags;
1074 fib_entry_t *fib_entry;
1075 fib_entry_src_t *bsrc;
1077 fib_entry = fib_entry_get(fib_entry_index);
1078 ASSERT(NULL != fib_entry);
1080 bsrc = fib_entry_get_best_src_i(fib_entry);
1081 best_source = fib_entry_src_get_source(bsrc);
1082 bflags = fib_entry_src_get_flags(bsrc);
1084 fib_entry_src_action_path_swap(fib_entry,
1089 * handle possible realloc's by refetching the pointer
1091 fib_entry = fib_entry_get(fib_entry_index);
1094 * if the path list for the source passed is invalid,
1095 * then we need to create a new one. else we are updating
1098 if (source < best_source)
1101 * we have a new winning source.
1103 fib_entry_src_action_deactivate(fib_entry, best_source);
1104 fib_entry_src_action_activate(fib_entry, source);
1106 else if (source > best_source) {
1108 * the new source loses. nothing to do here.
1109 * the data from the source is saved in the path-list created
1116 * the new source is one this entry already has.
1117 * But the path-list was updated, which will contribute new forwarding,
1120 fib_entry_src_action_deactivate(fib_entry, source);
1121 fib_entry_src_action_activate(fib_entry, source);
1124 fib_entry_post_update_actions(fib_entry, source, bflags);
1129 * fib_entry_cover_changed
1131 * this entry is tracking its cover and that cover has changed.
1134 fib_entry_cover_changed (fib_node_index_t fib_entry_index)
1136 fib_entry_src_cover_res_t res = {
1138 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
1140 fib_source_t source, best_source;
1141 fib_entry_flag_t bflags;
1142 fib_entry_t *fib_entry;
1143 fib_entry_src_t *esrc;
1146 bflags = FIB_ENTRY_FLAG_NONE;
1147 best_source = FIB_SOURCE_FIRST;
1148 fib_entry = fib_entry_get(fib_entry_index);
1150 fib_attached_export_cover_change(fib_entry);
1153 * propagate the notificuation to each of the added sources
1156 FOR_EACH_SRC_ADDED(fib_entry, esrc, source,
1161 * only the best source gets to set the back walk flags
1163 res = fib_entry_src_action_cover_change(fib_entry, source);
1164 bflags = fib_entry_src_get_flags(esrc);
1165 best_source = fib_entry_src_get_source(esrc);
1169 fib_entry_src_action_cover_change(fib_entry, source);
1176 fib_entry_src_action_reactivate(fib_entry,
1177 fib_entry_src_get_source(
1178 fib_entry_get_best_src_i(fib_entry)));
1179 fib_entry_post_install_actions(fib_entry, best_source, bflags);
1183 fib_entry_src_action_uninstall(fib_entry);
1186 if (FIB_NODE_BW_REASON_FLAG_NONE != res.bw_reason)
1189 * time for walkies fido.
1191 fib_node_back_walk_ctx_t bw_ctx = {
1192 .fnbw_reason = res.bw_reason,
1195 fib_walk_sync(FIB_NODE_TYPE_ENTRY, fib_entry_index, &bw_ctx);
1200 * fib_entry_cover_updated
1202 * this entry is tracking its cover and that cover has been updated
1203 * (i.e. its forwarding information has changed).
1206 fib_entry_cover_updated (fib_node_index_t fib_entry_index)
1208 fib_entry_src_cover_res_t res = {
1210 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
1212 fib_source_t source, best_source;
1213 fib_entry_flag_t bflags;
1214 fib_entry_t *fib_entry;
1215 fib_entry_src_t *esrc;
1218 bflags = FIB_ENTRY_FLAG_NONE;
1219 best_source = FIB_SOURCE_FIRST;
1220 fib_entry = fib_entry_get(fib_entry_index);
1222 fib_attached_export_cover_update(fib_entry);
1225 * propagate the notificuation to each of the added sources
1228 FOR_EACH_SRC_ADDED(fib_entry, esrc, source,
1233 * only the best source gets to set the back walk flags
1235 res = fib_entry_src_action_cover_update(fib_entry, source);
1236 bflags = fib_entry_src_get_flags(esrc);
1237 best_source = fib_entry_src_get_source(esrc);
1241 fib_entry_src_action_cover_update(fib_entry, source);
1248 fib_entry_src_action_reactivate(fib_entry,
1249 fib_entry_src_get_source(
1250 fib_entry_get_best_src_i(fib_entry)));
1251 fib_entry_post_install_actions(fib_entry, best_source, bflags);
1255 fib_entry_src_action_uninstall(fib_entry);
1258 if (FIB_NODE_BW_REASON_FLAG_NONE != res.bw_reason)
1261 * time for walkies fido.
1263 fib_node_back_walk_ctx_t bw_ctx = {
1264 .fnbw_reason = res.bw_reason,
1267 fib_walk_sync(FIB_NODE_TYPE_ENTRY, fib_entry_index, &bw_ctx);
1272 fib_entry_recursive_loop_detect (fib_node_index_t entry_index,
1273 fib_node_index_t **entry_indicies)
1275 fib_entry_t *fib_entry;
1276 int was_looped, is_looped;
1278 fib_entry = fib_entry_get(entry_index);
1280 if (FIB_NODE_INDEX_INVALID != fib_entry->fe_parent)
1282 fib_node_index_t *entries = *entry_indicies;
1283 fib_forward_chain_type_t fct;
1285 vec_add1(entries, entry_index);
1286 was_looped = fib_path_list_is_looped(fib_entry->fe_parent);
1287 is_looped = fib_path_list_recursive_loop_detect(fib_entry->fe_parent,
1290 *entry_indicies = entries;
1292 if (!!was_looped != !!is_looped)
1295 * re-evaluate all the entry's forwarding
1296 * NOTE: this is an inplace modify
1298 FOR_EACH_FIB_FORW_MPLS_CHAIN(fct)
1300 if (dpo_id_is_valid(&fib_entry->fe_lb[fct]))
1302 fib_entry_src_mk_lb(fib_entry,
1303 fib_entry_get_best_src_i(fib_entry),
1305 &fib_entry->fe_lb[fct]);
1313 * the entry is currently not linked to a path-list. this happens
1314 * when it is this entry that is re-linking path-lists and has thus
1324 fib_entry_get_resolving_interface (fib_node_index_t entry_index)
1326 fib_entry_t *fib_entry;
1328 fib_entry = fib_entry_get(entry_index);
1330 return (fib_path_list_get_resolving_interface(fib_entry->fe_parent));
1334 fib_entry_get_best_source (fib_node_index_t entry_index)
1336 fib_entry_t *fib_entry;
1337 fib_entry_src_t *bsrc;
1339 fib_entry = fib_entry_get(entry_index);
1341 bsrc = fib_entry_get_best_src_i(fib_entry);
1342 return (fib_entry_src_get_source(bsrc));
1346 fib_ip4_address_compare (ip4_address_t * a1,
1350 * IP addresses are unsiged ints. the return value here needs to be signed
1351 * a simple subtraction won't cut it.
1352 * If the addresses are the same, the sort order is undefiend, so phoey.
1354 return ((clib_net_to_host_u32(a1->data_u32) >
1355 clib_net_to_host_u32(a2->data_u32) ) ?
1360 fib_ip6_address_compare (ip6_address_t * a1,
1364 for (i = 0; i < ARRAY_LEN (a1->as_u16); i++)
1366 int cmp = (clib_net_to_host_u16 (a1->as_u16[i]) -
1367 clib_net_to_host_u16 (a2->as_u16[i]));
1375 fib_entry_cmp (fib_node_index_t fib_entry_index1,
1376 fib_node_index_t fib_entry_index2)
1378 fib_entry_t *fib_entry1, *fib_entry2;
1381 fib_entry1 = fib_entry_get(fib_entry_index1);
1382 fib_entry2 = fib_entry_get(fib_entry_index2);
1384 switch (fib_entry1->fe_prefix.fp_proto)
1386 case FIB_PROTOCOL_IP4:
1387 cmp = fib_ip4_address_compare(&fib_entry1->fe_prefix.fp_addr.ip4,
1388 &fib_entry2->fe_prefix.fp_addr.ip4);
1390 case FIB_PROTOCOL_IP6:
1391 cmp = fib_ip6_address_compare(&fib_entry1->fe_prefix.fp_addr.ip6,
1392 &fib_entry2->fe_prefix.fp_addr.ip6);
1394 case FIB_PROTOCOL_MPLS:
1395 cmp = (fib_entry1->fe_prefix.fp_label - fib_entry2->fe_prefix.fp_label);
1399 cmp = (fib_entry1->fe_prefix.fp_eos - fib_entry2->fe_prefix.fp_eos);
1405 cmp = (fib_entry1->fe_prefix.fp_len - fib_entry2->fe_prefix.fp_len);
1411 fib_entry_cmp_for_sort (void *i1, void *i2)
1413 fib_node_index_t *fib_entry_index1 = i1, *fib_entry_index2 = i2;
1415 return (fib_entry_cmp(*fib_entry_index1,
1416 *fib_entry_index2));
1420 fib_entry_lock (fib_node_index_t fib_entry_index)
1422 fib_entry_t *fib_entry;
1424 fib_entry = fib_entry_get(fib_entry_index);
1426 fib_node_lock(&fib_entry->fe_node);
1430 fib_entry_unlock (fib_node_index_t fib_entry_index)
1432 fib_entry_t *fib_entry;
1434 fib_entry = fib_entry_get(fib_entry_index);
1436 fib_node_unlock(&fib_entry->fe_node);
1440 fib_entry_module_init (void)
1442 fib_node_register_type (FIB_NODE_TYPE_ENTRY, &fib_entry_vft);
1446 fib_entry_get_prefix (fib_node_index_t fib_entry_index,
1449 fib_entry_t *fib_entry;
1451 fib_entry = fib_entry_get(fib_entry_index);
1452 *pfx = fib_entry->fe_prefix;
1456 fib_entry_get_fib_index (fib_node_index_t fib_entry_index)
1458 fib_entry_t *fib_entry;
1460 fib_entry = fib_entry_get(fib_entry_index);
1462 return (fib_entry->fe_fib_index);
1466 fib_entry_pool_size (void)
1468 return (pool_elts(fib_entry_pool));
1471 static clib_error_t *
1472 show_fib_entry_command (vlib_main_t * vm,
1473 unformat_input_t * input,
1474 vlib_cli_command_t * cmd)
1476 fib_node_index_t fei;
1478 if (unformat (input, "%d", &fei))
1481 * show one in detail
1483 if (!pool_is_free_index(fib_entry_pool, fei))
1485 vlib_cli_output (vm, "%d@%U",
1487 format_fib_entry, fei,
1488 FIB_ENTRY_FORMAT_DETAIL2);
1492 vlib_cli_output (vm, "entry %d invalid", fei);
1500 vlib_cli_output (vm, "FIB Entries:");
1501 pool_foreach_index(fei, fib_entry_pool,
1503 vlib_cli_output (vm, "%d@%U",
1505 format_fib_entry, fei,
1506 FIB_ENTRY_FORMAT_BRIEF);
1513 VLIB_CLI_COMMAND (show_fib_entry, static) = {
1514 .path = "show fib entry",
1515 .function = show_fib_entry_command,
1516 .short_help = "show fib entry",