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/dpo/drop_dpo.h>
19 #include <vnet/fib/fib_table.h>
20 #include <vnet/fib/fib_entry_cover.h>
21 #include <vnet/fib/fib_internal.h>
22 #include <vnet/fib/ip4_fib.h>
23 #include <vnet/fib/ip6_fib.h>
24 #include <vnet/fib/mpls_fib.h>
26 const static char * fib_table_flags_strings[] = FIB_TABLE_ATTRIBUTES;
29 * Default names for IP4, IP6, and MPLS FIB table index 0.
30 * Nominally like "ipv6-VRF:0", but this will override that name if set
31 * in a config section of the startup.conf file.
33 char *fib_table_default_names[FIB_PROTOCOL_MAX];
36 fib_table_get (fib_node_index_t index,
41 case FIB_PROTOCOL_IP4:
42 return (pool_elt_at_index(ip4_main.fibs, index));
43 case FIB_PROTOCOL_IP6:
44 return (pool_elt_at_index(ip6_main.fibs, index));
45 case FIB_PROTOCOL_MPLS:
46 return (pool_elt_at_index(mpls_main.fibs, index));
52 static inline fib_node_index_t
53 fib_table_lookup_i (fib_table_t *fib_table,
54 const fib_prefix_t *prefix)
56 switch (prefix->fp_proto)
58 case FIB_PROTOCOL_IP4:
59 return (ip4_fib_table_lookup(ip4_fib_get(fib_table->ft_index),
62 case FIB_PROTOCOL_IP6:
63 return (ip6_fib_table_lookup(fib_table->ft_index,
66 case FIB_PROTOCOL_MPLS:
67 return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
71 return (FIB_NODE_INDEX_INVALID);
75 fib_table_lookup (u32 fib_index,
76 const fib_prefix_t *prefix)
78 return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
81 static inline fib_node_index_t
82 fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
83 const fib_prefix_t *prefix)
85 switch (prefix->fp_proto)
87 case FIB_PROTOCOL_IP4:
88 return (ip4_fib_table_lookup_exact_match(ip4_fib_get(fib_table->ft_index),
91 case FIB_PROTOCOL_IP6:
92 return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
95 case FIB_PROTOCOL_MPLS:
96 return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
100 return (FIB_NODE_INDEX_INVALID);
104 fib_table_lookup_exact_match (u32 fib_index,
105 const fib_prefix_t *prefix)
107 return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
112 static fib_node_index_t
113 fib_table_get_less_specific_i (fib_table_t *fib_table,
114 const fib_prefix_t *prefix)
120 if (FIB_PROTOCOL_MPLS == pfx.fp_proto)
122 return (FIB_NODE_INDEX_INVALID);
126 * in the absence of a tree structure for the table that allows for an O(1)
127 * parent get, a cheeky way to find the cover is to LPM for the prefix with
129 * there should always be a cover, though it may be the default route. the
130 * default route's cover is the default route.
132 if (pfx.fp_len != 0) {
136 return (fib_table_lookup_i(fib_table, &pfx));
140 fib_table_get_less_specific (u32 fib_index,
141 const fib_prefix_t *prefix)
143 return (fib_table_get_less_specific_i(fib_table_get(fib_index,
149 fib_table_entry_remove (fib_table_t *fib_table,
150 const fib_prefix_t *prefix,
151 fib_node_index_t fib_entry_index)
153 vlib_smp_unsafe_warning();
155 fib_table->ft_total_route_counts--;
157 switch (prefix->fp_proto)
159 case FIB_PROTOCOL_IP4:
160 ip4_fib_table_entry_remove(ip4_fib_get(fib_table->ft_index),
161 &prefix->fp_addr.ip4,
164 case FIB_PROTOCOL_IP6:
165 ip6_fib_table_entry_remove(fib_table->ft_index,
166 &prefix->fp_addr.ip6,
169 case FIB_PROTOCOL_MPLS:
170 mpls_fib_table_entry_remove(mpls_fib_get(fib_table->ft_index),
176 fib_entry_unlock(fib_entry_index);
180 fib_table_post_insert_actions (fib_table_t *fib_table,
181 const fib_prefix_t *prefix,
182 fib_node_index_t fib_entry_index)
184 fib_node_index_t fib_entry_cover_index;
187 * no cover relationships in the MPLS FIB
189 if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
193 * find the covering entry
195 fib_entry_cover_index = fib_table_get_less_specific_i(fib_table, prefix);
197 * the indicies are the same when the default route is first added
199 if (fib_entry_cover_index != fib_entry_index)
202 * push any inherting sources from the cover onto the covered
204 fib_entry_inherit(fib_entry_cover_index,
208 * inform the covering entry that a new more specific
209 * has been inserted beneath it.
210 * If the prefix that has been inserted is a host route
211 * then it is not possible that it will be the cover for any
212 * other entry, so we can elide the walk. This is particularly
213 * beneficial since there are often many host entries sharing the
214 * same cover (i.e. ADJ or RR sourced entries).
216 if (!fib_entry_is_host(fib_entry_index))
218 fib_entry_cover_change_notify(fib_entry_cover_index,
225 fib_table_entry_insert (fib_table_t *fib_table,
226 const fib_prefix_t *prefix,
227 fib_node_index_t fib_entry_index)
229 vlib_smp_unsafe_warning();
231 fib_entry_lock(fib_entry_index);
232 fib_table->ft_total_route_counts++;
234 switch (prefix->fp_proto)
236 case FIB_PROTOCOL_IP4:
237 ip4_fib_table_entry_insert(ip4_fib_get(fib_table->ft_index),
238 &prefix->fp_addr.ip4,
242 case FIB_PROTOCOL_IP6:
243 ip6_fib_table_entry_insert(fib_table->ft_index,
244 &prefix->fp_addr.ip6,
248 case FIB_PROTOCOL_MPLS:
249 mpls_fib_table_entry_insert(mpls_fib_get(fib_table->ft_index),
256 fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
260 fib_table_fwding_dpo_update (u32 fib_index,
261 const fib_prefix_t *prefix,
264 vlib_smp_unsafe_warning();
266 switch (prefix->fp_proto)
268 case FIB_PROTOCOL_IP4:
269 return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
270 &prefix->fp_addr.ip4,
273 case FIB_PROTOCOL_IP6:
274 return (ip6_fib_table_fwding_dpo_update(fib_index,
275 &prefix->fp_addr.ip6,
278 case FIB_PROTOCOL_MPLS:
279 return (mpls_fib_forwarding_table_update(mpls_fib_get(fib_index),
287 fib_table_fwding_dpo_remove (u32 fib_index,
288 const fib_prefix_t *prefix,
291 vlib_smp_unsafe_warning();
293 switch (prefix->fp_proto)
295 case FIB_PROTOCOL_IP4:
296 return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
297 &prefix->fp_addr.ip4,
300 fib_table_get_less_specific(fib_index,
302 case FIB_PROTOCOL_IP6:
303 return (ip6_fib_table_fwding_dpo_remove(fib_index,
304 &prefix->fp_addr.ip6,
307 case FIB_PROTOCOL_MPLS:
308 return (mpls_fib_forwarding_table_reset(mpls_fib_get(fib_index),
315 fib_table_source_count_inc (fib_table_t *fib_table,
318 vec_validate (fib_table->ft_src_route_counts, source);
319 fib_table->ft_src_route_counts[source]++;
323 fib_table_source_count_dec (fib_table_t *fib_table,
326 vec_validate (fib_table->ft_src_route_counts, source);
327 fib_table->ft_src_route_counts[source]--;
331 fib_table_entry_special_dpo_add (u32 fib_index,
332 const fib_prefix_t *prefix,
334 fib_entry_flag_t flags,
337 fib_node_index_t fib_entry_index;
338 fib_table_t *fib_table;
340 fib_table = fib_table_get(fib_index, prefix->fp_proto);
341 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
343 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
345 fib_entry_index = fib_entry_create_special(fib_index, prefix,
349 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
350 fib_table_source_count_inc(fib_table, source);
356 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
357 fib_entry_special_add(fib_entry_index, source, flags, dpo);
359 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
361 fib_table_source_count_inc(fib_table, source);
366 return (fib_entry_index);
370 fib_table_entry_special_dpo_update (u32 fib_index,
371 const fib_prefix_t *prefix,
373 fib_entry_flag_t flags,
376 fib_node_index_t fib_entry_index;
377 fib_table_t *fib_table;
379 fib_table = fib_table_get(fib_index, prefix->fp_proto);
380 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
382 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
384 fib_entry_index = fib_entry_create_special(fib_index, prefix,
388 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
389 fib_table_source_count_inc(fib_table, source);
395 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
398 fib_entry_special_update(fib_entry_index, source, flags, dpo);
400 fib_entry_special_add(fib_entry_index, source, flags, dpo);
402 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
404 fib_table_source_count_inc(fib_table, source);
408 return (fib_entry_index);
412 fib_table_entry_special_add (u32 fib_index,
413 const fib_prefix_t *prefix,
415 fib_entry_flag_t flags)
417 fib_node_index_t fib_entry_index;
418 dpo_id_t tmp_dpo = DPO_INVALID;
420 dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
422 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
425 dpo_unlock(&tmp_dpo);
427 return (fib_entry_index);
431 fib_table_entry_special_remove (u32 fib_index,
432 const fib_prefix_t *prefix,
437 * yes => remove source
438 * 2 - is it still sourced?
441 fib_node_index_t fib_entry_index;
442 fib_table_t *fib_table;
444 fib_table = fib_table_get(fib_index, prefix->fp_proto);
445 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
447 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
450 * removing an etry that does not exist. i'll allow it.
455 fib_entry_src_flag_t src_flag;
459 * don't nobody go nowhere
461 fib_entry_lock(fib_entry_index);
462 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
464 src_flag = fib_entry_special_remove(fib_entry_index, source);
466 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
469 * last source gone. remove from the table
471 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
474 * now the entry is no longer in the table, we can
475 * inform the entries that it covers to re-calculate their cover
477 fib_entry_cover_change_notify(fib_entry_index,
478 FIB_NODE_INDEX_INVALID);
482 * still has sources, leave it be.
484 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
486 fib_table_source_count_dec(fib_table, source);
489 fib_entry_unlock(fib_entry_index);
494 * fib_table_route_path_fixup
496 * Convert attached hosts to attached next-hops.
498 * This special case is required because an attached path will link to a
499 * glean, and the FIB entry will have the interface or API/CLI source. When
500 * the ARP/ND process is completes then that source (which will provide a
501 * complete adjacency) will be lower priority and so the FIB entry will
502 * remain linked to a glean and traffic will never reach the hosts. For
503 * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
507 fib_table_route_path_fixup (const fib_prefix_t *prefix,
508 fib_entry_flag_t *eflags,
509 fib_route_path_t *path)
512 * not all zeros next hop &&
513 * is recursive path &&
514 * nexthop is same as the route's address
516 if ((!ip46_address_is_zero(&path->frp_addr)) &&
517 (~0 == path->frp_sw_if_index) &&
518 (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
520 /* Prefix recurses via itself */
521 path->frp_flags |= FIB_ROUTE_PATH_DROP;
523 if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
524 fib_prefix_is_host(prefix) &&
525 ip46_address_is_zero(&path->frp_addr) &&
526 path->frp_sw_if_index != ~0 &&
527 path->frp_proto != DPO_PROTO_ETHERNET)
529 path->frp_addr = prefix->fp_addr;
530 path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
532 else if ((*eflags & FIB_ENTRY_FLAG_CONNECTED) &&
533 !(*eflags & FIB_ENTRY_FLAG_LOCAL))
535 if (ip46_address_is_zero(&path->frp_addr))
537 path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
538 fib_prefix_normalize(prefix, &path->frp_connected);
541 else if (fib_route_path_is_attached(path))
543 path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
545 * attached prefixes are not suitable as the source of ARP requests
546 * so don't save the prefix in the glean adj
548 clib_memset(&path->frp_connected, 0, sizeof(path->frp_connected));
550 if (*eflags & FIB_ENTRY_FLAG_DROP)
552 path->frp_flags |= FIB_ROUTE_PATH_DROP;
554 if (*eflags & FIB_ENTRY_FLAG_LOCAL)
556 path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
558 if (*eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
560 path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
562 if (path->frp_flags & FIB_ROUTE_PATH_LOCAL)
564 *eflags |= FIB_ENTRY_FLAG_LOCAL;
566 if (path->frp_sw_if_index != ~0)
568 *eflags |= FIB_ENTRY_FLAG_CONNECTED;
574 fib_table_entry_path_add (u32 fib_index,
575 const fib_prefix_t *prefix,
577 fib_entry_flag_t flags,
578 dpo_proto_t next_hop_proto,
579 const ip46_address_t *next_hop,
580 u32 next_hop_sw_if_index,
581 u32 next_hop_fib_index,
583 fib_mpls_label_t *next_hop_labels,
584 fib_route_path_flags_t path_flags)
586 fib_route_path_t path = {
587 .frp_proto = next_hop_proto,
588 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
589 .frp_sw_if_index = next_hop_sw_if_index,
590 .frp_fib_index = next_hop_fib_index,
591 .frp_weight = next_hop_weight,
592 .frp_flags = path_flags,
593 .frp_rpf_id = INDEX_INVALID,
594 .frp_label_stack = next_hop_labels,
596 fib_node_index_t fib_entry_index;
597 fib_route_path_t *paths = NULL;
599 vec_add1(paths, path);
601 fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
602 source, flags, paths);
605 return (fib_entry_index);
609 fib_route_path_cmp_for_sort (void * v1,
612 return (fib_route_path_cmp(v1, v2));
616 fib_table_entry_path_add2 (u32 fib_index,
617 const fib_prefix_t *prefix,
619 fib_entry_flag_t flags,
620 fib_route_path_t *rpaths)
622 fib_node_index_t fib_entry_index;
623 fib_table_t *fib_table;
626 fib_table = fib_table_get(fib_index, prefix->fp_proto);
627 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
629 for (ii = 0; ii < vec_len(rpaths); ii++)
631 fib_table_route_path_fixup(prefix, &flags, &rpaths[ii]);
634 * sort the paths provided by the control plane. this means
635 * the paths and the extension on the entry will be sorted.
637 vec_sort_with_function(rpaths, fib_route_path_cmp_for_sort);
639 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
641 fib_entry_index = fib_entry_create(fib_index, prefix,
645 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
646 fib_table_source_count_inc(fib_table, source);
652 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
653 fib_entry_path_add(fib_entry_index, source, flags, rpaths);;
655 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
657 fib_table_source_count_inc(fib_table, source);
661 return (fib_entry_index);
665 fib_table_entry_path_remove2 (u32 fib_index,
666 const fib_prefix_t *prefix,
668 fib_route_path_t *rpaths)
672 * yes => remove source
673 * 2 - is it still sourced?
676 fib_node_index_t fib_entry_index;
677 fib_route_path_t *rpath;
678 fib_table_t *fib_table;
680 fib_table = fib_table_get(fib_index, prefix->fp_proto);
681 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
683 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
686 * removing an etry that does not exist. i'll allow it.
691 fib_entry_src_flag_t src_flag;
695 * if it's not sourced, then there's nowt to remove
697 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
704 * don't nobody go nowhere
706 fib_entry_lock(fib_entry_index);
708 vec_foreach(rpath, rpaths)
710 fib_entry_flag_t eflags;
712 eflags = fib_entry_get_flags_for_source(fib_entry_index,
714 fib_table_route_path_fixup(prefix, &eflags, rpath);
717 src_flag = fib_entry_path_remove(fib_entry_index, source, rpaths);
719 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
722 * last source gone. remove from the table
724 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
727 * now the entry is no longer in the table, we can
728 * inform the entries that it covers to re-calculate their cover
730 fib_entry_cover_change_notify(fib_entry_index,
731 FIB_NODE_INDEX_INVALID);
735 * still has sources, leave it be.
737 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
739 fib_table_source_count_dec(fib_table, source);
742 fib_entry_unlock(fib_entry_index);
747 fib_table_entry_path_remove (u32 fib_index,
748 const fib_prefix_t *prefix,
750 dpo_proto_t next_hop_proto,
751 const ip46_address_t *next_hop,
752 u32 next_hop_sw_if_index,
753 u32 next_hop_fib_index,
755 fib_route_path_flags_t path_flags)
759 * yes => remove source
760 * 2 - is it still sourced?
763 fib_route_path_t path = {
764 .frp_proto = next_hop_proto,
765 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
766 .frp_sw_if_index = next_hop_sw_if_index,
767 .frp_fib_index = next_hop_fib_index,
768 .frp_weight = next_hop_weight,
769 .frp_flags = path_flags,
771 fib_route_path_t *paths = NULL;
773 vec_add1(paths, path);
775 fib_table_entry_path_remove2(fib_index, prefix, source, paths);
781 fib_table_entry_update (u32 fib_index,
782 const fib_prefix_t *prefix,
784 fib_entry_flag_t flags,
785 fib_route_path_t *paths)
787 fib_node_index_t fib_entry_index;
788 fib_table_t *fib_table;
791 fib_table = fib_table_get(fib_index, prefix->fp_proto);
792 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
794 for (ii = 0; ii < vec_len(paths); ii++)
796 fib_table_route_path_fixup(prefix, &flags, &paths[ii]);
799 * sort the paths provided by the control plane. this means
800 * the paths and the extension on the entry will be sorted.
802 vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
804 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
806 fib_entry_index = fib_entry_create(fib_index, prefix,
810 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
811 fib_table_source_count_inc(fib_table, source);
817 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
818 fib_entry_update(fib_entry_index, source, flags, paths);
820 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
822 fib_table_source_count_inc(fib_table, source);
826 return (fib_entry_index);
830 fib_table_entry_update_one_path (u32 fib_index,
831 const fib_prefix_t *prefix,
833 fib_entry_flag_t flags,
834 dpo_proto_t next_hop_proto,
835 const ip46_address_t *next_hop,
836 u32 next_hop_sw_if_index,
837 u32 next_hop_fib_index,
839 fib_mpls_label_t *next_hop_labels,
840 fib_route_path_flags_t path_flags)
842 fib_node_index_t fib_entry_index;
843 fib_route_path_t path = {
844 .frp_proto = next_hop_proto,
845 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
846 .frp_sw_if_index = next_hop_sw_if_index,
847 .frp_fib_index = next_hop_fib_index,
848 .frp_weight = next_hop_weight,
849 .frp_flags = path_flags,
850 .frp_label_stack = next_hop_labels,
852 fib_route_path_t *paths = NULL;
854 vec_add1(paths, path);
857 fib_table_entry_update(fib_index, prefix, source, flags, paths);
861 return (fib_entry_index);
865 fib_table_entry_delete_i (u32 fib_index,
866 fib_node_index_t fib_entry_index,
867 const fib_prefix_t *prefix,
870 fib_entry_src_flag_t src_flag;
871 fib_table_t *fib_table;
874 fib_table = fib_table_get(fib_index, prefix->fp_proto);
875 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
878 * don't nobody go nowhere
880 fib_entry_lock(fib_entry_index);
882 src_flag = fib_entry_delete(fib_entry_index, source);
884 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
887 * last source gone. remove from the table
889 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
892 * now the entry is no longer in the table, we can
893 * inform the entries that it covers to re-calculate their cover
895 fib_entry_cover_change_notify(fib_entry_index,
896 FIB_NODE_INDEX_INVALID);
900 * still has sources, leave it be.
902 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
904 fib_table_source_count_dec(fib_table, source);
907 fib_entry_unlock(fib_entry_index);
911 fib_table_entry_delete (u32 fib_index,
912 const fib_prefix_t *prefix,
915 fib_node_index_t fib_entry_index;
917 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
919 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
922 * removing an etry that does not exist.
923 * i'll allow it, but i won't like it.
926 clib_warning("%U not in FIB", format_fib_prefix, prefix);
930 fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
935 fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
938 const fib_prefix_t *prefix;
940 prefix = fib_entry_get_prefix(fib_entry_index);
942 fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
943 fib_entry_index, prefix, source);
947 fib_table_entry_get_stats_index (u32 fib_index,
948 const fib_prefix_t *prefix)
950 return (fib_entry_get_stats_index(
951 fib_table_lookup_exact_match(fib_index, prefix)));
955 fib_table_entry_local_label_add (u32 fib_index,
956 const fib_prefix_t *prefix,
959 fib_node_index_t fib_entry_index;
961 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
963 if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
964 !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
967 * only source the prefix once. this allows the label change
970 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
976 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
978 return (fib_entry_index);
982 fib_table_entry_local_label_remove (u32 fib_index,
983 const fib_prefix_t *prefix,
986 fib_node_index_t fib_entry_index;
990 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
992 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
995 data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
1000 pl = *(mpls_label_t*)data;
1005 pl = MPLS_LABEL_INVALID;
1007 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
1008 fib_table_entry_special_remove(fib_index,
1014 fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
1019 case FIB_PROTOCOL_IP4:
1020 return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
1021 case FIB_PROTOCOL_IP6:
1022 return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
1023 case FIB_PROTOCOL_MPLS:
1024 return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
1030 fib_table_get_flow_hash_config (u32 fib_index,
1031 fib_protocol_t proto)
1035 fib = fib_table_get(fib_index, proto);
1037 return (fib->ft_flow_hash_config);
1041 fib_table_get_default_flow_hash_config (fib_protocol_t proto)
1045 case FIB_PROTOCOL_IP4:
1046 case FIB_PROTOCOL_IP6:
1047 return (IP_FLOW_HASH_DEFAULT);
1049 case FIB_PROTOCOL_MPLS:
1050 return (MPLS_FLOW_HASH_DEFAULT);
1054 return (IP_FLOW_HASH_DEFAULT);
1058 * @brief Table set flow hash config context.
1060 typedef struct fib_table_set_flow_hash_config_ctx_t_
1063 * the flow hash config to set
1065 flow_hash_config_t hash_config;
1066 } fib_table_set_flow_hash_config_ctx_t;
1068 static fib_table_walk_rc_t
1069 fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
1072 fib_table_set_flow_hash_config_ctx_t *ctx = arg;
1074 fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
1076 return (FIB_TABLE_WALK_CONTINUE);
1080 fib_table_set_flow_hash_config (u32 fib_index,
1081 fib_protocol_t proto,
1082 flow_hash_config_t hash_config)
1084 fib_table_set_flow_hash_config_ctx_t ctx = {
1085 .hash_config = hash_config,
1089 fib = fib_table_get(fib_index, proto);
1090 fib->ft_flow_hash_config = hash_config;
1092 fib_table_walk(fib_index, proto,
1093 fib_table_set_flow_hash_config_cb,
1098 fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
1101 fib_table_t *fib_table;
1103 fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
1104 proto, sw_if_index),
1107 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1111 fib_table_get_table_id (u32 fib_index,
1112 fib_protocol_t proto)
1114 fib_table_t *fib_table;
1116 fib_table = fib_table_get(fib_index, proto);
1118 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1122 fib_table_find (fib_protocol_t proto,
1127 case FIB_PROTOCOL_IP4:
1128 return (ip4_fib_index_from_table_id(table_id));
1129 case FIB_PROTOCOL_IP6:
1130 return (ip6_fib_index_from_table_id(table_id));
1131 case FIB_PROTOCOL_MPLS:
1132 return (mpls_fib_index_from_table_id(table_id));
1138 fib_table_find_or_create_and_lock_i (fib_protocol_t proto,
1143 fib_table_t *fib_table;
1144 fib_node_index_t fi;
1148 case FIB_PROTOCOL_IP4:
1149 fi = ip4_fib_table_find_or_create_and_lock(table_id, src);
1151 case FIB_PROTOCOL_IP6:
1152 fi = ip6_fib_table_find_or_create_and_lock(table_id, src);
1154 case FIB_PROTOCOL_MPLS:
1155 fi = mpls_fib_table_find_or_create_and_lock(table_id, src);
1161 fib_table = fib_table_get(fi, proto);
1163 if (fib_table->ft_desc)
1166 if (name && name[0])
1168 fib_table->ft_desc = format(NULL, "%s", name);
1174 char *default_name = fib_table_default_names[proto];
1175 if (default_name && default_name[0])
1177 fib_table->ft_desc = format(NULL, "%s", default_name);
1182 fib_table->ft_desc = format(NULL, "%U-VRF:%d",
1183 format_fib_protocol, proto,
1189 fib_table_find_or_create_and_lock (fib_protocol_t proto,
1193 return (fib_table_find_or_create_and_lock_i(proto, table_id,
1198 fib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
1203 return (fib_table_find_or_create_and_lock_i(proto, table_id,
1208 fib_table_create_and_lock (fib_protocol_t proto,
1210 const char *const fmt,
1213 fib_table_t *fib_table;
1214 fib_node_index_t fi;
1220 case FIB_PROTOCOL_IP4:
1221 fi = ip4_fib_table_create_and_lock(src);
1223 case FIB_PROTOCOL_IP6:
1224 fi = ip6_fib_table_create_and_lock(src, FIB_TABLE_FLAG_NONE, NULL);
1226 case FIB_PROTOCOL_MPLS:
1227 fi = mpls_fib_table_create_and_lock(src);
1233 fib_table = fib_table_get(fi, proto);
1237 fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1244 fib_table_destroy (fib_table_t *fib_table)
1246 vec_free(fib_table->ft_desc);
1248 switch (fib_table->ft_proto)
1250 case FIB_PROTOCOL_IP4:
1251 ip4_fib_table_destroy(fib_table->ft_index);
1253 case FIB_PROTOCOL_IP6:
1254 ip6_fib_table_destroy(fib_table->ft_index);
1256 case FIB_PROTOCOL_MPLS:
1257 mpls_fib_table_destroy(fib_table->ft_index);
1263 fib_table_walk (u32 fib_index,
1264 fib_protocol_t proto,
1265 fib_table_walk_fn_t fn,
1270 case FIB_PROTOCOL_IP4:
1271 ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
1273 case FIB_PROTOCOL_IP6:
1274 ip6_fib_table_walk(fib_index, fn, ctx);
1276 case FIB_PROTOCOL_MPLS:
1277 mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
1282 typedef struct fib_table_walk_w_src_ctx_t_
1284 fib_table_walk_fn_t fn;
1287 } fib_table_walk_w_src_cxt_t;
1289 static fib_table_walk_rc_t
1290 fib_table_walk_w_src_cb (fib_node_index_t fei,
1293 fib_table_walk_w_src_cxt_t *ctx = arg;
1295 if (ctx->src == fib_entry_get_best_source(fei))
1297 return (ctx->fn(fei, ctx->data));
1299 return (FIB_TABLE_WALK_CONTINUE);
1303 fib_table_walk_w_src (u32 fib_index,
1304 fib_protocol_t proto,
1306 fib_table_walk_fn_t fn,
1309 fib_table_walk_w_src_cxt_t ctx = {
1315 fib_table_walk(fib_index, proto, fib_table_walk_w_src_cb, &ctx);
1319 fib_table_sub_tree_walk (u32 fib_index,
1320 fib_protocol_t proto,
1321 const fib_prefix_t *root,
1322 fib_table_walk_fn_t fn,
1327 case FIB_PROTOCOL_IP4:
1328 ip4_fib_table_sub_tree_walk(ip4_fib_get(fib_index), root, fn, ctx);
1330 case FIB_PROTOCOL_IP6:
1331 ip6_fib_table_sub_tree_walk(fib_index, root, fn, ctx);
1333 case FIB_PROTOCOL_MPLS:
1339 fib_table_lock_dec (fib_table_t *fib_table,
1340 fib_source_t source)
1342 vec_validate(fib_table->ft_locks, source);
1344 ASSERT(fib_table->ft_locks[source] > 0);
1345 fib_table->ft_locks[source]--;
1346 fib_table->ft_total_locks--;
1350 fib_table_lock_inc (fib_table_t *fib_table,
1351 fib_source_t source)
1353 vec_validate(fib_table->ft_locks, source);
1355 ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
1356 fib_table->ft_locks[source]++;
1357 fib_table->ft_total_locks++;
1362 fib_table_lock_clear (fib_table_t *fib_table,
1363 fib_source_t source)
1365 vec_validate(fib_table->ft_locks, source);
1367 ASSERT(fib_table->ft_locks[source] <= 1);
1368 if (fib_table->ft_locks[source])
1370 fib_table->ft_locks[source]--;
1371 fib_table->ft_total_locks--;
1376 fib_table_lock_set (fib_table_t *fib_table,
1377 fib_source_t source)
1379 vec_validate(fib_table->ft_locks, source);
1381 ASSERT(fib_table->ft_locks[source] <= 1);
1382 ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
1383 if (!fib_table->ft_locks[source])
1385 fib_table->ft_locks[source]++;
1386 fib_table->ft_total_locks++;
1391 fib_table_unlock (u32 fib_index,
1392 fib_protocol_t proto,
1393 fib_source_t source)
1395 fib_table_t *fib_table;
1397 fib_table = fib_table_get(fib_index, proto);
1399 if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1400 fib_table_lock_clear(fib_table, source);
1402 fib_table_lock_dec(fib_table, source);
1404 if (0 == fib_table->ft_total_locks)
1407 * no more lock from any source - kill it
1409 fib_table_destroy(fib_table);
1414 fib_table_lock (u32 fib_index,
1415 fib_protocol_t proto,
1416 fib_source_t source)
1418 fib_table_t *fib_table;
1420 fib_table = fib_table_get(fib_index, proto);
1422 if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1423 fib_table_lock_set(fib_table, source);
1425 fib_table_lock_inc(fib_table, source);
1429 fib_table_get_num_entries (u32 fib_index,
1430 fib_protocol_t proto,
1431 fib_source_t source)
1433 fib_table_t *fib_table;
1435 fib_table = fib_table_get(fib_index, proto);
1437 return (fib_table->ft_src_route_counts[source]);
1441 format_fib_table_name (u8* s, va_list* ap)
1443 fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
1444 fib_protocol_t proto = va_arg(*ap, int); // int promotion
1445 fib_table_t *fib_table;
1447 fib_table = fib_table_get(fib_index, proto);
1449 s = format(s, "%v", fib_table->ft_desc);
1455 format_fib_table_flags (u8 *s, va_list *args)
1457 fib_table_flags_t flags = va_arg(*args, int);
1458 fib_table_attribute_t attr;
1462 return format(s, "none");
1465 FOR_EACH_FIB_TABLE_ATTRIBUTE(attr) {
1466 if (1 << attr & flags) {
1467 s = format(s, "%s", fib_table_flags_strings[attr]);
1475 * @brief Table flush context. Store the indicies of matching FIB entries
1476 * that need to be removed.
1478 typedef struct fib_table_flush_ctx_t_
1481 * The list of entries to flush
1483 fib_node_index_t *ftf_entries;
1486 * The source we are flushing
1488 fib_source_t ftf_source;
1489 } fib_table_flush_ctx_t;
1491 static fib_table_walk_rc_t
1492 fib_table_flush_cb (fib_node_index_t fib_entry_index,
1495 fib_table_flush_ctx_t *ctx = arg;
1497 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1499 vec_add1(ctx->ftf_entries, fib_entry_index);
1501 return (FIB_TABLE_WALK_CONTINUE);
1505 fib_table_flush (u32 fib_index,
1506 fib_protocol_t proto,
1507 fib_source_t source)
1509 fib_node_index_t *fib_entry_index;
1510 fib_table_flush_ctx_t ctx = {
1511 .ftf_entries = NULL,
1512 .ftf_source = source,
1515 fib_table_walk(fib_index, proto,
1519 vec_foreach(fib_entry_index, ctx.ftf_entries)
1521 fib_table_entry_delete_index(*fib_entry_index, source);
1524 vec_free(ctx.ftf_entries);
1527 static fib_table_walk_rc_t
1528 fib_table_mark_cb (fib_node_index_t fib_entry_index,
1531 fib_table_flush_ctx_t *ctx = arg;
1533 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1535 fib_entry_mark(fib_entry_index, ctx->ftf_source);
1537 return (FIB_TABLE_WALK_CONTINUE);
1541 fib_table_mark (u32 fib_index,
1542 fib_protocol_t proto,
1543 fib_source_t source)
1545 fib_table_flush_ctx_t ctx = {
1546 .ftf_source = source,
1548 fib_table_t *fib_table;
1550 fib_table = fib_table_get(fib_index, proto);
1552 fib_table->ft_epoch++;
1553 fib_table->ft_flags |= FIB_TABLE_FLAG_RESYNC;
1555 fib_table_walk(fib_index, proto,
1560 static fib_table_walk_rc_t
1561 fib_table_sweep_cb (fib_node_index_t fib_entry_index,
1564 fib_table_flush_ctx_t *ctx = arg;
1566 if (fib_entry_is_marked(fib_entry_index, ctx->ftf_source))
1568 vec_add1(ctx->ftf_entries, fib_entry_index);
1570 return (FIB_TABLE_WALK_CONTINUE);
1574 fib_table_sweep (u32 fib_index,
1575 fib_protocol_t proto,
1576 fib_source_t source)
1578 fib_table_flush_ctx_t ctx = {
1579 .ftf_source = source,
1581 fib_node_index_t *fib_entry_index;
1582 fib_table_t *fib_table;
1584 fib_table = fib_table_get(fib_index, proto);
1586 fib_table->ft_flags &= ~FIB_TABLE_FLAG_RESYNC;
1588 fib_table_walk(fib_index, proto,
1592 vec_foreach(fib_entry_index, ctx.ftf_entries)
1594 fib_table_entry_delete_index(*fib_entry_index, source);
1597 vec_free(ctx.ftf_entries);
1601 format_fib_table_memory (u8 *s, va_list *args)
1603 s = format(s, "%U", format_ip4_fib_table_memory);
1604 s = format(s, "%U", format_ip6_fib_table_memory);
1605 s = format(s, "%U", format_mpls_fib_table_memory);