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 fib_table_get (fib_node_index_t index,
34 case FIB_PROTOCOL_IP4:
35 return (pool_elt_at_index(ip4_main.fibs, index));
36 case FIB_PROTOCOL_IP6:
37 return (pool_elt_at_index(ip6_main.fibs, index));
38 case FIB_PROTOCOL_MPLS:
39 return (pool_elt_at_index(mpls_main.fibs, index));
45 static inline fib_node_index_t
46 fib_table_lookup_i (fib_table_t *fib_table,
47 const fib_prefix_t *prefix)
49 switch (prefix->fp_proto)
51 case FIB_PROTOCOL_IP4:
52 return (ip4_fib_table_lookup(ip4_fib_get(fib_table->ft_index),
55 case FIB_PROTOCOL_IP6:
56 return (ip6_fib_table_lookup(fib_table->ft_index,
59 case FIB_PROTOCOL_MPLS:
60 return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
64 return (FIB_NODE_INDEX_INVALID);
68 fib_table_lookup (u32 fib_index,
69 const fib_prefix_t *prefix)
71 return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
74 static inline fib_node_index_t
75 fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
76 const fib_prefix_t *prefix)
78 switch (prefix->fp_proto)
80 case FIB_PROTOCOL_IP4:
81 return (ip4_fib_table_lookup_exact_match(ip4_fib_get(fib_table->ft_index),
84 case FIB_PROTOCOL_IP6:
85 return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
88 case FIB_PROTOCOL_MPLS:
89 return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
93 return (FIB_NODE_INDEX_INVALID);
97 fib_table_lookup_exact_match (u32 fib_index,
98 const fib_prefix_t *prefix)
100 return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
105 static fib_node_index_t
106 fib_table_get_less_specific_i (fib_table_t *fib_table,
107 const fib_prefix_t *prefix)
113 if (FIB_PROTOCOL_MPLS == pfx.fp_proto)
115 return (FIB_NODE_INDEX_INVALID);
119 * in the absence of a tree structure for the table that allows for an O(1)
120 * parent get, a cheeky way to find the cover is to LPM for the prefix with
122 * there should always be a cover, though it may be the default route. the
123 * default route's cover is the default route.
125 if (pfx.fp_len != 0) {
129 return (fib_table_lookup_i(fib_table, &pfx));
133 fib_table_get_less_specific (u32 fib_index,
134 const fib_prefix_t *prefix)
136 return (fib_table_get_less_specific_i(fib_table_get(fib_index,
142 fib_table_entry_remove (fib_table_t *fib_table,
143 const fib_prefix_t *prefix,
144 fib_node_index_t fib_entry_index)
146 vlib_smp_unsafe_warning();
148 fib_table->ft_total_route_counts--;
150 switch (prefix->fp_proto)
152 case FIB_PROTOCOL_IP4:
153 ip4_fib_table_entry_remove(ip4_fib_get(fib_table->ft_index),
154 &prefix->fp_addr.ip4,
157 case FIB_PROTOCOL_IP6:
158 ip6_fib_table_entry_remove(fib_table->ft_index,
159 &prefix->fp_addr.ip6,
162 case FIB_PROTOCOL_MPLS:
163 mpls_fib_table_entry_remove(mpls_fib_get(fib_table->ft_index),
169 fib_entry_unlock(fib_entry_index);
173 fib_table_post_insert_actions (fib_table_t *fib_table,
174 const fib_prefix_t *prefix,
175 fib_node_index_t fib_entry_index)
177 fib_node_index_t fib_entry_cover_index;
180 * no cover relationships in the MPLS FIB
182 if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
186 * find the covering entry
188 fib_entry_cover_index = fib_table_get_less_specific_i(fib_table, prefix);
190 * the indicies are the same when the default route is first added
192 if (fib_entry_cover_index != fib_entry_index)
195 * push any inherting sources from the cover onto the covered
197 fib_entry_inherit(fib_entry_cover_index,
201 * inform the covering entry that a new more specific
202 * has been inserted beneath it.
203 * If the prefix that has been inserted is a host route
204 * then it is not possible that it will be the cover for any
205 * other entry, so we can elide the walk. This is particularly
206 * beneficial since there are often many host entries sharing the
207 * same cover (i.e. ADJ or RR sourced entries).
209 if (!fib_entry_is_host(fib_entry_index))
211 fib_entry_cover_change_notify(fib_entry_cover_index,
218 fib_table_entry_insert (fib_table_t *fib_table,
219 const fib_prefix_t *prefix,
220 fib_node_index_t fib_entry_index)
222 vlib_smp_unsafe_warning();
224 fib_entry_lock(fib_entry_index);
225 fib_table->ft_total_route_counts++;
227 switch (prefix->fp_proto)
229 case FIB_PROTOCOL_IP4:
230 ip4_fib_table_entry_insert(ip4_fib_get(fib_table->ft_index),
231 &prefix->fp_addr.ip4,
235 case FIB_PROTOCOL_IP6:
236 ip6_fib_table_entry_insert(fib_table->ft_index,
237 &prefix->fp_addr.ip6,
241 case FIB_PROTOCOL_MPLS:
242 mpls_fib_table_entry_insert(mpls_fib_get(fib_table->ft_index),
249 fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
253 fib_table_fwding_dpo_update (u32 fib_index,
254 const fib_prefix_t *prefix,
257 vlib_smp_unsafe_warning();
259 switch (prefix->fp_proto)
261 case FIB_PROTOCOL_IP4:
262 return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
263 &prefix->fp_addr.ip4,
266 case FIB_PROTOCOL_IP6:
267 return (ip6_fib_table_fwding_dpo_update(fib_index,
268 &prefix->fp_addr.ip6,
271 case FIB_PROTOCOL_MPLS:
272 return (mpls_fib_forwarding_table_update(mpls_fib_get(fib_index),
280 fib_table_fwding_dpo_remove (u32 fib_index,
281 const fib_prefix_t *prefix,
284 vlib_smp_unsafe_warning();
286 switch (prefix->fp_proto)
288 case FIB_PROTOCOL_IP4:
289 return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
290 &prefix->fp_addr.ip4,
293 fib_table_get_less_specific(fib_index,
295 case FIB_PROTOCOL_IP6:
296 return (ip6_fib_table_fwding_dpo_remove(fib_index,
297 &prefix->fp_addr.ip6,
300 case FIB_PROTOCOL_MPLS:
301 return (mpls_fib_forwarding_table_reset(mpls_fib_get(fib_index),
308 fib_table_source_count_inc (fib_table_t *fib_table,
311 vec_validate (fib_table->ft_src_route_counts, source);
312 fib_table->ft_src_route_counts[source]++;
316 fib_table_source_count_dec (fib_table_t *fib_table,
319 vec_validate (fib_table->ft_src_route_counts, source);
320 fib_table->ft_src_route_counts[source]--;
324 fib_table_entry_special_dpo_add (u32 fib_index,
325 const fib_prefix_t *prefix,
327 fib_entry_flag_t flags,
330 fib_node_index_t fib_entry_index;
331 fib_table_t *fib_table;
333 fib_table = fib_table_get(fib_index, prefix->fp_proto);
334 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
336 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
338 fib_entry_index = fib_entry_create_special(fib_index, prefix,
342 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
343 fib_table_source_count_inc(fib_table, source);
349 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
350 fib_entry_special_add(fib_entry_index, source, flags, dpo);
352 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
354 fib_table_source_count_inc(fib_table, source);
359 return (fib_entry_index);
363 fib_table_entry_special_dpo_update (u32 fib_index,
364 const fib_prefix_t *prefix,
366 fib_entry_flag_t flags,
369 fib_node_index_t fib_entry_index;
370 fib_table_t *fib_table;
372 fib_table = fib_table_get(fib_index, prefix->fp_proto);
373 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
375 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
377 fib_entry_index = fib_entry_create_special(fib_index, prefix,
381 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
382 fib_table_source_count_inc(fib_table, source);
388 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
391 fib_entry_special_update(fib_entry_index, source, flags, dpo);
393 fib_entry_special_add(fib_entry_index, source, flags, dpo);
395 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
397 fib_table_source_count_inc(fib_table, source);
401 return (fib_entry_index);
405 fib_table_entry_special_add (u32 fib_index,
406 const fib_prefix_t *prefix,
408 fib_entry_flag_t flags)
410 fib_node_index_t fib_entry_index;
411 dpo_id_t tmp_dpo = DPO_INVALID;
413 dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
415 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
418 dpo_unlock(&tmp_dpo);
420 return (fib_entry_index);
424 fib_table_entry_special_remove (u32 fib_index,
425 const fib_prefix_t *prefix,
430 * yes => remove source
431 * 2 - is it still sourced?
434 fib_node_index_t fib_entry_index;
435 fib_table_t *fib_table;
437 fib_table = fib_table_get(fib_index, prefix->fp_proto);
438 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
440 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
443 * removing an etry that does not exist. i'll allow it.
448 fib_entry_src_flag_t src_flag;
452 * don't nobody go nowhere
454 fib_entry_lock(fib_entry_index);
455 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
457 src_flag = fib_entry_special_remove(fib_entry_index, source);
459 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
462 * last source gone. remove from the table
464 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
467 * now the entry is no longer in the table, we can
468 * inform the entries that it covers to re-calculate their cover
470 fib_entry_cover_change_notify(fib_entry_index,
471 FIB_NODE_INDEX_INVALID);
475 * still has sources, leave it be.
477 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
479 fib_table_source_count_dec(fib_table, source);
482 fib_entry_unlock(fib_entry_index);
487 * fib_table_route_path_fixup
489 * Convert attached hosts to attached next-hops.
491 * This special case is required because an attached path will link to a
492 * glean, and the FIB entry will have the interface or API/CLI source. When
493 * the ARP/ND process is completes then that source (which will provide a
494 * complete adjacency) will be lower priority and so the FIB entry will
495 * remain linked to a glean and traffic will never reach the hosts. For
496 * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
500 fib_table_route_path_fixup (const fib_prefix_t *prefix,
501 fib_entry_flag_t *eflags,
502 fib_route_path_t *path)
505 * not all zeros next hop &&
506 * is recursive path &&
507 * nexthop is same as the route's address
509 if ((!ip46_address_is_zero(&path->frp_addr)) &&
510 (~0 == path->frp_sw_if_index) &&
511 (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
513 /* Prefix recurses via itself */
514 path->frp_flags |= FIB_ROUTE_PATH_DROP;
516 if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
517 fib_prefix_is_host(prefix) &&
518 ip46_address_is_zero(&path->frp_addr) &&
519 path->frp_sw_if_index != ~0 &&
520 path->frp_proto != DPO_PROTO_ETHERNET)
522 path->frp_addr = prefix->fp_addr;
523 path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
525 else if ((*eflags & FIB_ENTRY_FLAG_CONNECTED) &&
526 !(*eflags & FIB_ENTRY_FLAG_LOCAL))
528 if (ip46_address_is_zero(&path->frp_addr))
530 path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
531 fib_prefix_normalize(prefix, &path->frp_connected);
534 else if (fib_route_path_is_attached(path))
536 path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
538 * attached prefixes are not suitable as the source of ARP requests
539 * so don't save the prefix in the glean adj
541 clib_memset(&path->frp_connected, 0, sizeof(path->frp_connected));
543 if (*eflags & FIB_ENTRY_FLAG_DROP)
545 path->frp_flags |= FIB_ROUTE_PATH_DROP;
547 if (*eflags & FIB_ENTRY_FLAG_LOCAL)
549 path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
551 if (*eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
553 path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
555 if (path->frp_flags & FIB_ROUTE_PATH_LOCAL)
557 *eflags |= FIB_ENTRY_FLAG_LOCAL;
559 if (path->frp_sw_if_index != ~0)
561 *eflags |= FIB_ENTRY_FLAG_CONNECTED;
567 fib_table_entry_path_add (u32 fib_index,
568 const fib_prefix_t *prefix,
570 fib_entry_flag_t flags,
571 dpo_proto_t next_hop_proto,
572 const ip46_address_t *next_hop,
573 u32 next_hop_sw_if_index,
574 u32 next_hop_fib_index,
576 fib_mpls_label_t *next_hop_labels,
577 fib_route_path_flags_t path_flags)
579 fib_route_path_t path = {
580 .frp_proto = next_hop_proto,
581 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
582 .frp_sw_if_index = next_hop_sw_if_index,
583 .frp_fib_index = next_hop_fib_index,
584 .frp_weight = next_hop_weight,
585 .frp_flags = path_flags,
586 .frp_rpf_id = INDEX_INVALID,
587 .frp_label_stack = next_hop_labels,
589 fib_node_index_t fib_entry_index;
590 fib_route_path_t *paths = NULL;
592 vec_add1(paths, path);
594 fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
595 source, flags, paths);
598 return (fib_entry_index);
602 fib_route_path_cmp_for_sort (void * v1,
605 return (fib_route_path_cmp(v1, v2));
609 fib_table_entry_path_add2 (u32 fib_index,
610 const fib_prefix_t *prefix,
612 fib_entry_flag_t flags,
613 fib_route_path_t *rpaths)
615 fib_node_index_t fib_entry_index;
616 fib_table_t *fib_table;
619 fib_table = fib_table_get(fib_index, prefix->fp_proto);
620 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
622 for (ii = 0; ii < vec_len(rpaths); ii++)
624 fib_table_route_path_fixup(prefix, &flags, &rpaths[ii]);
627 * sort the paths provided by the control plane. this means
628 * the paths and the extension on the entry will be sorted.
630 vec_sort_with_function(rpaths, fib_route_path_cmp_for_sort);
632 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
634 fib_entry_index = fib_entry_create(fib_index, prefix,
638 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
639 fib_table_source_count_inc(fib_table, source);
645 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
646 fib_entry_path_add(fib_entry_index, source, flags, rpaths);;
648 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
650 fib_table_source_count_inc(fib_table, source);
654 return (fib_entry_index);
658 fib_table_entry_path_remove2 (u32 fib_index,
659 const fib_prefix_t *prefix,
661 fib_route_path_t *rpaths)
665 * yes => remove source
666 * 2 - is it still sourced?
669 fib_node_index_t fib_entry_index;
670 fib_route_path_t *rpath;
671 fib_table_t *fib_table;
673 fib_table = fib_table_get(fib_index, prefix->fp_proto);
674 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
676 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
679 * removing an etry that does not exist. i'll allow it.
684 fib_entry_src_flag_t src_flag;
688 * if it's not sourced, then there's nowt to remove
690 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
697 * don't nobody go nowhere
699 fib_entry_lock(fib_entry_index);
701 vec_foreach(rpath, rpaths)
703 fib_entry_flag_t eflags;
705 eflags = fib_entry_get_flags_for_source(fib_entry_index,
707 fib_table_route_path_fixup(prefix, &eflags, rpath);
710 src_flag = fib_entry_path_remove(fib_entry_index, source, rpaths);
712 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
715 * last source gone. remove from the table
717 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
720 * now the entry is no longer in the table, we can
721 * inform the entries that it covers to re-calculate their cover
723 fib_entry_cover_change_notify(fib_entry_index,
724 FIB_NODE_INDEX_INVALID);
728 * still has sources, leave it be.
730 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
732 fib_table_source_count_dec(fib_table, source);
735 fib_entry_unlock(fib_entry_index);
740 fib_table_entry_path_remove (u32 fib_index,
741 const fib_prefix_t *prefix,
743 dpo_proto_t next_hop_proto,
744 const ip46_address_t *next_hop,
745 u32 next_hop_sw_if_index,
746 u32 next_hop_fib_index,
748 fib_route_path_flags_t path_flags)
752 * yes => remove source
753 * 2 - is it still sourced?
756 fib_route_path_t path = {
757 .frp_proto = next_hop_proto,
758 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
759 .frp_sw_if_index = next_hop_sw_if_index,
760 .frp_fib_index = next_hop_fib_index,
761 .frp_weight = next_hop_weight,
762 .frp_flags = path_flags,
764 fib_route_path_t *paths = NULL;
766 vec_add1(paths, path);
768 fib_table_entry_path_remove2(fib_index, prefix, source, paths);
774 fib_table_entry_update (u32 fib_index,
775 const fib_prefix_t *prefix,
777 fib_entry_flag_t flags,
778 fib_route_path_t *paths)
780 fib_node_index_t fib_entry_index;
781 fib_table_t *fib_table;
784 fib_table = fib_table_get(fib_index, prefix->fp_proto);
785 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
787 for (ii = 0; ii < vec_len(paths); ii++)
789 fib_table_route_path_fixup(prefix, &flags, &paths[ii]);
792 * sort the paths provided by the control plane. this means
793 * the paths and the extension on the entry will be sorted.
795 vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
797 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
799 fib_entry_index = fib_entry_create(fib_index, prefix,
803 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
804 fib_table_source_count_inc(fib_table, source);
810 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
811 fib_entry_update(fib_entry_index, source, flags, paths);
813 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
815 fib_table_source_count_inc(fib_table, source);
819 return (fib_entry_index);
823 fib_table_entry_update_one_path (u32 fib_index,
824 const fib_prefix_t *prefix,
826 fib_entry_flag_t flags,
827 dpo_proto_t next_hop_proto,
828 const ip46_address_t *next_hop,
829 u32 next_hop_sw_if_index,
830 u32 next_hop_fib_index,
832 fib_mpls_label_t *next_hop_labels,
833 fib_route_path_flags_t path_flags)
835 fib_node_index_t fib_entry_index;
836 fib_route_path_t path = {
837 .frp_proto = next_hop_proto,
838 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
839 .frp_sw_if_index = next_hop_sw_if_index,
840 .frp_fib_index = next_hop_fib_index,
841 .frp_weight = next_hop_weight,
842 .frp_flags = path_flags,
843 .frp_label_stack = next_hop_labels,
845 fib_route_path_t *paths = NULL;
847 vec_add1(paths, path);
850 fib_table_entry_update(fib_index, prefix, source, flags, paths);
854 return (fib_entry_index);
858 fib_table_entry_delete_i (u32 fib_index,
859 fib_node_index_t fib_entry_index,
860 const fib_prefix_t *prefix,
863 fib_entry_src_flag_t src_flag;
864 fib_table_t *fib_table;
867 fib_table = fib_table_get(fib_index, prefix->fp_proto);
868 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
871 * don't nobody go nowhere
873 fib_entry_lock(fib_entry_index);
875 src_flag = fib_entry_delete(fib_entry_index, source);
877 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
880 * last source gone. remove from the table
882 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
885 * now the entry is no longer in the table, we can
886 * inform the entries that it covers to re-calculate their cover
888 fib_entry_cover_change_notify(fib_entry_index,
889 FIB_NODE_INDEX_INVALID);
893 * still has sources, leave it be.
895 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
897 fib_table_source_count_dec(fib_table, source);
900 fib_entry_unlock(fib_entry_index);
904 fib_table_entry_delete (u32 fib_index,
905 const fib_prefix_t *prefix,
908 fib_node_index_t fib_entry_index;
910 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
912 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
915 * removing an etry that does not exist.
916 * i'll allow it, but i won't like it.
919 clib_warning("%U not in FIB", format_fib_prefix, prefix);
923 fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
928 fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
931 const fib_prefix_t *prefix;
933 prefix = fib_entry_get_prefix(fib_entry_index);
935 fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
936 fib_entry_index, prefix, source);
940 fib_table_entry_get_stats_index (u32 fib_index,
941 const fib_prefix_t *prefix)
943 return (fib_entry_get_stats_index(
944 fib_table_lookup_exact_match(fib_index, prefix)));
948 fib_table_entry_local_label_add (u32 fib_index,
949 const fib_prefix_t *prefix,
952 fib_node_index_t fib_entry_index;
954 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
956 if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
957 !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
960 * only source the prefix once. this allows the label change
963 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
969 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
971 return (fib_entry_index);
975 fib_table_entry_local_label_remove (u32 fib_index,
976 const fib_prefix_t *prefix,
979 fib_node_index_t fib_entry_index;
983 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
985 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
988 data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
993 pl = *(mpls_label_t*)data;
998 pl = MPLS_LABEL_INVALID;
1000 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
1001 fib_table_entry_special_remove(fib_index,
1007 fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
1012 case FIB_PROTOCOL_IP4:
1013 return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
1014 case FIB_PROTOCOL_IP6:
1015 return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
1016 case FIB_PROTOCOL_MPLS:
1017 return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
1023 fib_table_get_flow_hash_config (u32 fib_index,
1024 fib_protocol_t proto)
1028 fib = fib_table_get(fib_index, proto);
1030 return (fib->ft_flow_hash_config);
1034 fib_table_get_default_flow_hash_config (fib_protocol_t proto)
1038 case FIB_PROTOCOL_IP4:
1039 case FIB_PROTOCOL_IP6:
1040 return (IP_FLOW_HASH_DEFAULT);
1042 case FIB_PROTOCOL_MPLS:
1043 return (MPLS_FLOW_HASH_DEFAULT);
1047 return (IP_FLOW_HASH_DEFAULT);
1051 * @brief Table set flow hash config context.
1053 typedef struct fib_table_set_flow_hash_config_ctx_t_
1056 * the flow hash config to set
1058 flow_hash_config_t hash_config;
1059 } fib_table_set_flow_hash_config_ctx_t;
1061 static fib_table_walk_rc_t
1062 fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
1065 fib_table_set_flow_hash_config_ctx_t *ctx = arg;
1067 fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
1069 return (FIB_TABLE_WALK_CONTINUE);
1073 fib_table_set_flow_hash_config (u32 fib_index,
1074 fib_protocol_t proto,
1075 flow_hash_config_t hash_config)
1077 fib_table_set_flow_hash_config_ctx_t ctx = {
1078 .hash_config = hash_config,
1082 fib = fib_table_get(fib_index, proto);
1083 fib->ft_flow_hash_config = hash_config;
1085 fib_table_walk(fib_index, proto,
1086 fib_table_set_flow_hash_config_cb,
1091 fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
1094 fib_table_t *fib_table;
1096 fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
1097 proto, sw_if_index),
1100 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1104 fib_table_get_table_id (u32 fib_index,
1105 fib_protocol_t proto)
1107 fib_table_t *fib_table;
1109 fib_table = fib_table_get(fib_index, proto);
1111 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1115 fib_table_find (fib_protocol_t proto,
1120 case FIB_PROTOCOL_IP4:
1121 return (ip4_fib_index_from_table_id(table_id));
1122 case FIB_PROTOCOL_IP6:
1123 return (ip6_fib_index_from_table_id(table_id));
1124 case FIB_PROTOCOL_MPLS:
1125 return (mpls_fib_index_from_table_id(table_id));
1131 fib_table_find_or_create_and_lock_i (fib_protocol_t proto,
1136 fib_table_t *fib_table;
1137 fib_node_index_t fi;
1141 case FIB_PROTOCOL_IP4:
1142 fi = ip4_fib_table_find_or_create_and_lock(table_id, src);
1144 case FIB_PROTOCOL_IP6:
1145 fi = ip6_fib_table_find_or_create_and_lock(table_id, src);
1147 case FIB_PROTOCOL_MPLS:
1148 fi = mpls_fib_table_find_or_create_and_lock(table_id, src);
1154 fib_table = fib_table_get(fi, proto);
1156 if (NULL == fib_table->ft_desc)
1158 if (name && name[0])
1160 fib_table->ft_desc = format(NULL, "%s", name);
1164 fib_table->ft_desc = format(NULL, "%U-VRF:%d",
1165 format_fib_protocol, proto,
1174 fib_table_find_or_create_and_lock (fib_protocol_t proto,
1178 return (fib_table_find_or_create_and_lock_i(proto, table_id,
1183 fib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
1188 return (fib_table_find_or_create_and_lock_i(proto, table_id,
1193 fib_table_create_and_lock (fib_protocol_t proto,
1195 const char *const fmt,
1198 fib_table_t *fib_table;
1199 fib_node_index_t fi;
1205 case FIB_PROTOCOL_IP4:
1206 fi = ip4_fib_table_create_and_lock(src);
1208 case FIB_PROTOCOL_IP6:
1209 fi = ip6_fib_table_create_and_lock(src, FIB_TABLE_FLAG_NONE, NULL);
1211 case FIB_PROTOCOL_MPLS:
1212 fi = mpls_fib_table_create_and_lock(src);
1218 fib_table = fib_table_get(fi, proto);
1222 fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1229 fib_table_destroy (fib_table_t *fib_table)
1231 vec_free(fib_table->ft_desc);
1233 switch (fib_table->ft_proto)
1235 case FIB_PROTOCOL_IP4:
1236 ip4_fib_table_destroy(fib_table->ft_index);
1238 case FIB_PROTOCOL_IP6:
1239 ip6_fib_table_destroy(fib_table->ft_index);
1241 case FIB_PROTOCOL_MPLS:
1242 mpls_fib_table_destroy(fib_table->ft_index);
1248 fib_table_walk (u32 fib_index,
1249 fib_protocol_t proto,
1250 fib_table_walk_fn_t fn,
1255 case FIB_PROTOCOL_IP4:
1256 ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
1258 case FIB_PROTOCOL_IP6:
1259 ip6_fib_table_walk(fib_index, fn, ctx);
1261 case FIB_PROTOCOL_MPLS:
1262 mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
1267 typedef struct fib_table_walk_w_src_ctx_t_
1269 fib_table_walk_fn_t fn;
1272 } fib_table_walk_w_src_cxt_t;
1274 static fib_table_walk_rc_t
1275 fib_table_walk_w_src_cb (fib_node_index_t fei,
1278 fib_table_walk_w_src_cxt_t *ctx = arg;
1280 if (ctx->src == fib_entry_get_best_source(fei))
1282 return (ctx->fn(fei, ctx->data));
1284 return (FIB_TABLE_WALK_CONTINUE);
1288 fib_table_walk_w_src (u32 fib_index,
1289 fib_protocol_t proto,
1291 fib_table_walk_fn_t fn,
1294 fib_table_walk_w_src_cxt_t ctx = {
1300 fib_table_walk(fib_index, proto, fib_table_walk_w_src_cb, &ctx);
1304 fib_table_sub_tree_walk (u32 fib_index,
1305 fib_protocol_t proto,
1306 const fib_prefix_t *root,
1307 fib_table_walk_fn_t fn,
1312 case FIB_PROTOCOL_IP4:
1313 ip4_fib_table_sub_tree_walk(ip4_fib_get(fib_index), root, fn, ctx);
1315 case FIB_PROTOCOL_IP6:
1316 ip6_fib_table_sub_tree_walk(fib_index, root, fn, ctx);
1318 case FIB_PROTOCOL_MPLS:
1324 fib_table_lock_dec (fib_table_t *fib_table,
1325 fib_source_t source)
1327 vec_validate(fib_table->ft_locks, source);
1329 ASSERT(fib_table->ft_locks[source] > 0);
1330 fib_table->ft_locks[source]--;
1331 fib_table->ft_total_locks--;
1335 fib_table_lock_inc (fib_table_t *fib_table,
1336 fib_source_t source)
1338 vec_validate(fib_table->ft_locks, source);
1340 ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
1341 fib_table->ft_locks[source]++;
1342 fib_table->ft_total_locks++;
1347 fib_table_lock_clear (fib_table_t *fib_table,
1348 fib_source_t source)
1350 vec_validate(fib_table->ft_locks, source);
1352 ASSERT(fib_table->ft_locks[source] <= 1);
1353 if (fib_table->ft_locks[source])
1355 fib_table->ft_locks[source]--;
1356 fib_table->ft_total_locks--;
1361 fib_table_lock_set (fib_table_t *fib_table,
1362 fib_source_t source)
1364 vec_validate(fib_table->ft_locks, source);
1366 ASSERT(fib_table->ft_locks[source] <= 1);
1367 ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
1368 if (!fib_table->ft_locks[source])
1370 fib_table->ft_locks[source]++;
1371 fib_table->ft_total_locks++;
1376 fib_table_unlock (u32 fib_index,
1377 fib_protocol_t proto,
1378 fib_source_t source)
1380 fib_table_t *fib_table;
1382 fib_table = fib_table_get(fib_index, proto);
1384 if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1385 fib_table_lock_clear(fib_table, source);
1387 fib_table_lock_dec(fib_table, source);
1389 if (0 == fib_table->ft_total_locks)
1392 * no more lock from any source - kill it
1394 fib_table_destroy(fib_table);
1399 fib_table_lock (u32 fib_index,
1400 fib_protocol_t proto,
1401 fib_source_t source)
1403 fib_table_t *fib_table;
1405 fib_table = fib_table_get(fib_index, proto);
1407 if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1408 fib_table_lock_set(fib_table, source);
1410 fib_table_lock_inc(fib_table, source);
1414 fib_table_get_num_entries (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 return (fib_table->ft_src_route_counts[source]);
1426 format_fib_table_name (u8* s, va_list* ap)
1428 fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
1429 fib_protocol_t proto = va_arg(*ap, int); // int promotion
1430 fib_table_t *fib_table;
1432 fib_table = fib_table_get(fib_index, proto);
1434 s = format(s, "%v", fib_table->ft_desc);
1440 format_fib_table_flags (u8 *s, va_list *args)
1442 fib_table_flags_t flags = va_arg(*args, int);
1443 fib_table_attribute_t attr;
1447 return format(s, "none");
1450 FOR_EACH_FIB_TABLE_ATTRIBUTE(attr) {
1451 if (1 << attr & flags) {
1452 s = format(s, "%s", fib_table_flags_strings[attr]);
1460 * @brief Table flush context. Store the indicies of matching FIB entries
1461 * that need to be removed.
1463 typedef struct fib_table_flush_ctx_t_
1466 * The list of entries to flush
1468 fib_node_index_t *ftf_entries;
1471 * The source we are flushing
1473 fib_source_t ftf_source;
1474 } fib_table_flush_ctx_t;
1476 static fib_table_walk_rc_t
1477 fib_table_flush_cb (fib_node_index_t fib_entry_index,
1480 fib_table_flush_ctx_t *ctx = arg;
1482 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1484 vec_add1(ctx->ftf_entries, fib_entry_index);
1486 return (FIB_TABLE_WALK_CONTINUE);
1490 fib_table_flush (u32 fib_index,
1491 fib_protocol_t proto,
1492 fib_source_t source)
1494 fib_node_index_t *fib_entry_index;
1495 fib_table_flush_ctx_t ctx = {
1496 .ftf_entries = NULL,
1497 .ftf_source = source,
1500 fib_table_walk(fib_index, proto,
1504 vec_foreach(fib_entry_index, ctx.ftf_entries)
1506 fib_table_entry_delete_index(*fib_entry_index, source);
1509 vec_free(ctx.ftf_entries);
1512 static fib_table_walk_rc_t
1513 fib_table_mark_cb (fib_node_index_t fib_entry_index,
1516 fib_table_flush_ctx_t *ctx = arg;
1518 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1520 fib_entry_mark(fib_entry_index, ctx->ftf_source);
1522 return (FIB_TABLE_WALK_CONTINUE);
1526 fib_table_mark (u32 fib_index,
1527 fib_protocol_t proto,
1528 fib_source_t source)
1530 fib_table_flush_ctx_t ctx = {
1531 .ftf_source = source,
1533 fib_table_t *fib_table;
1535 fib_table = fib_table_get(fib_index, proto);
1537 fib_table->ft_epoch++;
1538 fib_table->ft_flags |= FIB_TABLE_FLAG_RESYNC;
1540 fib_table_walk(fib_index, proto,
1545 static fib_table_walk_rc_t
1546 fib_table_sweep_cb (fib_node_index_t fib_entry_index,
1549 fib_table_flush_ctx_t *ctx = arg;
1551 if (fib_entry_is_marked(fib_entry_index, ctx->ftf_source))
1553 vec_add1(ctx->ftf_entries, fib_entry_index);
1555 return (FIB_TABLE_WALK_CONTINUE);
1559 fib_table_sweep (u32 fib_index,
1560 fib_protocol_t proto,
1561 fib_source_t source)
1563 fib_table_flush_ctx_t ctx = {
1564 .ftf_source = source,
1566 fib_node_index_t *fib_entry_index;
1567 fib_table_t *fib_table;
1569 fib_table = fib_table_get(fib_index, proto);
1571 fib_table->ft_flags &= ~FIB_TABLE_FLAG_RESYNC;
1573 fib_table_walk(fib_index, proto,
1577 vec_foreach(fib_entry_index, ctx.ftf_entries)
1579 fib_table_entry_delete_index(*fib_entry_index, source);
1582 vec_free(ctx.ftf_entries);
1586 format_fib_table_memory (u8 *s, va_list *args)
1588 s = format(s, "%U", format_ip4_fib_table_memory);
1589 s = format(s, "%U", format_ip6_fib_table_memory);
1590 s = format(s, "%U", format_mpls_fib_table_memory);