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),
309 fib_table_entry_special_dpo_add (u32 fib_index,
310 const fib_prefix_t *prefix,
312 fib_entry_flag_t flags,
315 fib_node_index_t fib_entry_index;
316 fib_table_t *fib_table;
318 fib_table = fib_table_get(fib_index, prefix->fp_proto);
319 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
321 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
323 fib_entry_index = fib_entry_create_special(fib_index, prefix,
327 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
328 fib_table->ft_src_route_counts[source]++;
334 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
335 fib_entry_special_add(fib_entry_index, source, flags, dpo);
337 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
339 fib_table->ft_src_route_counts[source]++;
344 return (fib_entry_index);
348 fib_table_entry_special_dpo_update (u32 fib_index,
349 const fib_prefix_t *prefix,
351 fib_entry_flag_t flags,
354 fib_node_index_t fib_entry_index;
355 fib_table_t *fib_table;
357 fib_table = fib_table_get(fib_index, prefix->fp_proto);
358 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
360 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
362 fib_entry_index = fib_entry_create_special(fib_index, prefix,
366 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
367 fib_table->ft_src_route_counts[source]++;
373 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
376 fib_entry_special_update(fib_entry_index, source, flags, dpo);
378 fib_entry_special_add(fib_entry_index, source, flags, dpo);
380 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
382 fib_table->ft_src_route_counts[source]++;
386 return (fib_entry_index);
390 fib_table_entry_special_add (u32 fib_index,
391 const fib_prefix_t *prefix,
393 fib_entry_flag_t flags)
395 fib_node_index_t fib_entry_index;
396 dpo_id_t tmp_dpo = DPO_INVALID;
398 dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
400 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
403 dpo_unlock(&tmp_dpo);
405 return (fib_entry_index);
409 fib_table_entry_special_remove (u32 fib_index,
410 const fib_prefix_t *prefix,
415 * yes => remove source
416 * 2 - is it still sourced?
419 fib_node_index_t fib_entry_index;
420 fib_table_t *fib_table;
422 fib_table = fib_table_get(fib_index, prefix->fp_proto);
423 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
425 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
428 * removing an etry that does not exist. i'll allow it.
433 fib_entry_src_flag_t src_flag;
437 * don't nobody go nowhere
439 fib_entry_lock(fib_entry_index);
440 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
442 src_flag = fib_entry_special_remove(fib_entry_index, source);
444 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
447 * last source gone. remove from the table
449 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
452 * now the entry is no longer in the table, we can
453 * inform the entries that it covers to re-calculate their cover
455 fib_entry_cover_change_notify(fib_entry_index,
456 FIB_NODE_INDEX_INVALID);
460 * still has sources, leave it be.
462 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
464 fib_table->ft_src_route_counts[source]--;
467 fib_entry_unlock(fib_entry_index);
472 * fib_table_route_path_fixup
474 * Convert attached hosts to attached next-hops.
476 * This special case is required because an attached path will link to a
477 * glean, and the FIB entry will have the interface or API/CLI source. When
478 * the ARP/ND process is completes then that source (which will provide a
479 * complete adjacency) will be lower priority and so the FIB entry will
480 * remain linked to a glean and traffic will never reach the hosts. For
481 * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
485 fib_table_route_path_fixup (const fib_prefix_t *prefix,
486 fib_entry_flag_t *eflags,
487 fib_route_path_t *path)
490 * not all zeros next hop &&
491 * is recursive path &&
492 * nexthop is same as the route's address
494 if ((!ip46_address_is_zero(&path->frp_addr)) &&
495 (~0 == path->frp_sw_if_index) &&
496 (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
498 /* Prefix recurses via itse;f */
499 path->frp_flags |= FIB_ROUTE_PATH_DROP;
501 if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
502 fib_prefix_is_host(prefix) &&
503 ip46_address_is_zero(&path->frp_addr) &&
504 path->frp_sw_if_index != ~0 &&
505 path->frp_proto != DPO_PROTO_ETHERNET)
507 path->frp_addr = prefix->fp_addr;
508 path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
510 if (*eflags & FIB_ENTRY_FLAG_DROP)
512 path->frp_flags |= FIB_ROUTE_PATH_DROP;
514 if (*eflags & FIB_ENTRY_FLAG_LOCAL)
516 path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
518 if (*eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
520 path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
522 if (path->frp_flags & FIB_ROUTE_PATH_LOCAL)
524 *eflags |= FIB_ENTRY_FLAG_LOCAL;
526 if (path->frp_sw_if_index != ~0)
528 *eflags |= FIB_ENTRY_FLAG_CONNECTED;
534 fib_table_entry_path_add (u32 fib_index,
535 const fib_prefix_t *prefix,
537 fib_entry_flag_t flags,
538 dpo_proto_t next_hop_proto,
539 const ip46_address_t *next_hop,
540 u32 next_hop_sw_if_index,
541 u32 next_hop_fib_index,
543 fib_mpls_label_t *next_hop_labels,
544 fib_route_path_flags_t path_flags)
546 fib_route_path_t path = {
547 .frp_proto = next_hop_proto,
548 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
549 .frp_sw_if_index = next_hop_sw_if_index,
550 .frp_fib_index = next_hop_fib_index,
551 .frp_weight = next_hop_weight,
552 .frp_flags = path_flags,
553 .frp_rpf_id = INDEX_INVALID,
554 .frp_label_stack = next_hop_labels,
556 fib_node_index_t fib_entry_index;
557 fib_route_path_t *paths = NULL;
559 vec_add1(paths, path);
561 fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
562 source, flags, paths);
565 return (fib_entry_index);
569 fib_table_entry_path_add2 (u32 fib_index,
570 const fib_prefix_t *prefix,
572 fib_entry_flag_t flags,
573 fib_route_path_t *rpaths)
575 fib_node_index_t fib_entry_index;
576 fib_table_t *fib_table;
579 fib_table = fib_table_get(fib_index, prefix->fp_proto);
580 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
582 for (ii = 0; ii < vec_len(rpaths); ii++)
584 fib_table_route_path_fixup(prefix, &flags, &rpaths[ii]);
587 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
589 fib_entry_index = fib_entry_create(fib_index, prefix,
593 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
594 fib_table->ft_src_route_counts[source]++;
600 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
601 fib_entry_path_add(fib_entry_index, source, flags, rpaths);;
603 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
605 fib_table->ft_src_route_counts[source]++;
609 return (fib_entry_index);
613 fib_table_entry_path_remove2 (u32 fib_index,
614 const fib_prefix_t *prefix,
616 fib_route_path_t *rpaths)
620 * yes => remove source
621 * 2 - is it still sourced?
624 fib_node_index_t fib_entry_index;
625 fib_route_path_t *rpath;
626 fib_table_t *fib_table;
628 fib_table = fib_table_get(fib_index, prefix->fp_proto);
629 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
631 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
634 * removing an etry that does not exist. i'll allow it.
639 fib_entry_src_flag_t src_flag;
643 * if it's not sourced, then there's nowt to remove
645 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
652 * don't nobody go nowhere
654 fib_entry_lock(fib_entry_index);
656 vec_foreach(rpath, rpaths)
658 fib_entry_flag_t eflags;
660 eflags = fib_entry_get_flags_for_source(fib_entry_index,
662 fib_table_route_path_fixup(prefix, &eflags, rpath);
665 src_flag = fib_entry_path_remove(fib_entry_index, source, rpaths);
667 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
670 * last source gone. remove from the table
672 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
675 * now the entry is no longer in the table, we can
676 * inform the entries that it covers to re-calculate their cover
678 fib_entry_cover_change_notify(fib_entry_index,
679 FIB_NODE_INDEX_INVALID);
683 * still has sources, leave it be.
685 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
687 fib_table->ft_src_route_counts[source]--;
690 fib_entry_unlock(fib_entry_index);
695 fib_table_entry_path_remove (u32 fib_index,
696 const fib_prefix_t *prefix,
698 dpo_proto_t next_hop_proto,
699 const ip46_address_t *next_hop,
700 u32 next_hop_sw_if_index,
701 u32 next_hop_fib_index,
703 fib_route_path_flags_t path_flags)
707 * yes => remove source
708 * 2 - is it still sourced?
711 fib_route_path_t path = {
712 .frp_proto = next_hop_proto,
713 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
714 .frp_sw_if_index = next_hop_sw_if_index,
715 .frp_fib_index = next_hop_fib_index,
716 .frp_weight = next_hop_weight,
717 .frp_flags = path_flags,
719 fib_route_path_t *paths = NULL;
721 vec_add1(paths, path);
723 fib_table_entry_path_remove2(fib_index, prefix, source, paths);
729 fib_route_path_cmp_for_sort (void * v1,
732 return (fib_route_path_cmp(v1, v2));
736 fib_table_entry_update (u32 fib_index,
737 const fib_prefix_t *prefix,
739 fib_entry_flag_t flags,
740 fib_route_path_t *paths)
742 fib_node_index_t fib_entry_index;
743 fib_table_t *fib_table;
746 fib_table = fib_table_get(fib_index, prefix->fp_proto);
747 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
749 for (ii = 0; ii < vec_len(paths); ii++)
751 fib_table_route_path_fixup(prefix, &flags, &paths[ii]);
754 * sort the paths provided by the control plane. this means
755 * the paths and the extension on the entry will be sorted.
757 vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
759 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
761 fib_entry_index = fib_entry_create(fib_index, prefix,
765 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
766 fib_table->ft_src_route_counts[source]++;
772 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
773 fib_entry_update(fib_entry_index, source, flags, paths);
775 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
777 fib_table->ft_src_route_counts[source]++;
781 return (fib_entry_index);
785 fib_table_entry_update_one_path (u32 fib_index,
786 const fib_prefix_t *prefix,
788 fib_entry_flag_t flags,
789 dpo_proto_t next_hop_proto,
790 const ip46_address_t *next_hop,
791 u32 next_hop_sw_if_index,
792 u32 next_hop_fib_index,
794 fib_mpls_label_t *next_hop_labels,
795 fib_route_path_flags_t path_flags)
797 fib_node_index_t fib_entry_index;
798 fib_route_path_t path = {
799 .frp_proto = next_hop_proto,
800 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
801 .frp_sw_if_index = next_hop_sw_if_index,
802 .frp_fib_index = next_hop_fib_index,
803 .frp_weight = next_hop_weight,
804 .frp_flags = path_flags,
805 .frp_label_stack = next_hop_labels,
807 fib_route_path_t *paths = NULL;
809 vec_add1(paths, path);
812 fib_table_entry_update(fib_index, prefix, source, flags, paths);
816 return (fib_entry_index);
820 fib_table_entry_delete_i (u32 fib_index,
821 fib_node_index_t fib_entry_index,
822 const fib_prefix_t *prefix,
825 fib_entry_src_flag_t src_flag;
826 fib_table_t *fib_table;
829 fib_table = fib_table_get(fib_index, prefix->fp_proto);
830 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
833 * don't nobody go nowhere
835 fib_entry_lock(fib_entry_index);
837 src_flag = fib_entry_delete(fib_entry_index, source);
839 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
842 * last source gone. remove from the table
844 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
847 * now the entry is no longer in the table, we can
848 * inform the entries that it covers to re-calculate their cover
850 fib_entry_cover_change_notify(fib_entry_index,
851 FIB_NODE_INDEX_INVALID);
855 * still has sources, leave it be.
857 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
859 fib_table->ft_src_route_counts[source]--;
862 fib_entry_unlock(fib_entry_index);
866 fib_table_entry_delete (u32 fib_index,
867 const fib_prefix_t *prefix,
870 fib_node_index_t fib_entry_index;
872 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
874 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
877 * removing an etry that does not exist.
878 * i'll allow it, but i won't like it.
881 clib_warning("%U not in FIB", format_fib_prefix, prefix);
885 fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
890 fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
893 const fib_prefix_t *prefix;
895 prefix = fib_entry_get_prefix(fib_entry_index);
897 fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
898 fib_entry_index, prefix, source);
902 fib_table_entry_get_stats_index (u32 fib_index,
903 const fib_prefix_t *prefix)
905 return (fib_entry_get_stats_index(
906 fib_table_lookup_exact_match(fib_index, prefix)));
910 fib_table_entry_local_label_add (u32 fib_index,
911 const fib_prefix_t *prefix,
914 fib_node_index_t fib_entry_index;
916 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
918 if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
919 !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
922 * only source the prefix once. this allows the label change
925 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
931 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
933 return (fib_entry_index);
937 fib_table_entry_local_label_remove (u32 fib_index,
938 const fib_prefix_t *prefix,
941 fib_node_index_t fib_entry_index;
945 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
947 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
950 data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
955 pl = *(mpls_label_t*)data;
960 pl = MPLS_LABEL_INVALID;
962 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
963 fib_table_entry_special_remove(fib_index,
969 fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
974 case FIB_PROTOCOL_IP4:
975 return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
976 case FIB_PROTOCOL_IP6:
977 return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
978 case FIB_PROTOCOL_MPLS:
979 return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
985 fib_table_get_flow_hash_config (u32 fib_index,
986 fib_protocol_t proto)
990 fib = fib_table_get(fib_index, proto);
992 return (fib->ft_flow_hash_config);
996 fib_table_get_default_flow_hash_config (fib_protocol_t proto)
1000 case FIB_PROTOCOL_IP4:
1001 case FIB_PROTOCOL_IP6:
1002 return (IP_FLOW_HASH_DEFAULT);
1004 case FIB_PROTOCOL_MPLS:
1005 return (MPLS_FLOW_HASH_DEFAULT);
1009 return (IP_FLOW_HASH_DEFAULT);
1013 * @brief Table set flow hash config context.
1015 typedef struct fib_table_set_flow_hash_config_ctx_t_
1018 * the flow hash config to set
1020 flow_hash_config_t hash_config;
1021 } fib_table_set_flow_hash_config_ctx_t;
1023 static fib_table_walk_rc_t
1024 fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
1027 fib_table_set_flow_hash_config_ctx_t *ctx = arg;
1029 fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
1031 return (FIB_TABLE_WALK_CONTINUE);
1035 fib_table_set_flow_hash_config (u32 fib_index,
1036 fib_protocol_t proto,
1037 flow_hash_config_t hash_config)
1039 fib_table_set_flow_hash_config_ctx_t ctx = {
1040 .hash_config = hash_config,
1044 fib = fib_table_get(fib_index, proto);
1045 fib->ft_flow_hash_config = hash_config;
1047 fib_table_walk(fib_index, proto,
1048 fib_table_set_flow_hash_config_cb,
1053 fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
1056 fib_table_t *fib_table;
1058 fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
1059 proto, sw_if_index),
1062 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1066 fib_table_get_table_id (u32 fib_index,
1067 fib_protocol_t proto)
1069 fib_table_t *fib_table;
1071 fib_table = fib_table_get(fib_index, proto);
1073 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1077 fib_table_find (fib_protocol_t proto,
1082 case FIB_PROTOCOL_IP4:
1083 return (ip4_fib_index_from_table_id(table_id));
1084 case FIB_PROTOCOL_IP6:
1085 return (ip6_fib_index_from_table_id(table_id));
1086 case FIB_PROTOCOL_MPLS:
1087 return (mpls_fib_index_from_table_id(table_id));
1093 fib_table_find_or_create_and_lock_i (fib_protocol_t proto,
1098 fib_table_t *fib_table;
1099 fib_node_index_t fi;
1103 case FIB_PROTOCOL_IP4:
1104 fi = ip4_fib_table_find_or_create_and_lock(table_id, src);
1106 case FIB_PROTOCOL_IP6:
1107 fi = ip6_fib_table_find_or_create_and_lock(table_id, src);
1109 case FIB_PROTOCOL_MPLS:
1110 fi = mpls_fib_table_find_or_create_and_lock(table_id, src);
1116 fib_table = fib_table_get(fi, proto);
1118 if (NULL == fib_table->ft_desc)
1120 if (name && name[0])
1122 fib_table->ft_desc = format(NULL, "%s", name);
1126 fib_table->ft_desc = format(NULL, "%U-VRF:%d",
1127 format_fib_protocol, proto,
1136 fib_table_find_or_create_and_lock (fib_protocol_t proto,
1140 return (fib_table_find_or_create_and_lock_i(proto, table_id,
1145 fib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
1150 return (fib_table_find_or_create_and_lock_i(proto, table_id,
1155 fib_table_create_and_lock (fib_protocol_t proto,
1157 const char *const fmt,
1160 fib_table_t *fib_table;
1161 fib_node_index_t fi;
1167 case FIB_PROTOCOL_IP4:
1168 fi = ip4_fib_table_create_and_lock(src);
1170 case FIB_PROTOCOL_IP6:
1171 fi = ip6_fib_table_create_and_lock(src, FIB_TABLE_FLAG_NONE, NULL);
1173 case FIB_PROTOCOL_MPLS:
1174 fi = mpls_fib_table_create_and_lock(src);
1180 fib_table = fib_table_get(fi, proto);
1184 fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1191 fib_table_destroy (fib_table_t *fib_table)
1193 vec_free(fib_table->ft_desc);
1195 switch (fib_table->ft_proto)
1197 case FIB_PROTOCOL_IP4:
1198 ip4_fib_table_destroy(fib_table->ft_index);
1200 case FIB_PROTOCOL_IP6:
1201 ip6_fib_table_destroy(fib_table->ft_index);
1203 case FIB_PROTOCOL_MPLS:
1204 mpls_fib_table_destroy(fib_table->ft_index);
1210 fib_table_walk (u32 fib_index,
1211 fib_protocol_t proto,
1212 fib_table_walk_fn_t fn,
1217 case FIB_PROTOCOL_IP4:
1218 ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
1220 case FIB_PROTOCOL_IP6:
1221 ip6_fib_table_walk(fib_index, fn, ctx);
1223 case FIB_PROTOCOL_MPLS:
1224 mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
1230 fib_table_sub_tree_walk (u32 fib_index,
1231 fib_protocol_t proto,
1232 const fib_prefix_t *root,
1233 fib_table_walk_fn_t fn,
1238 case FIB_PROTOCOL_IP4:
1239 ip4_fib_table_sub_tree_walk(ip4_fib_get(fib_index), root, fn, ctx);
1241 case FIB_PROTOCOL_IP6:
1242 ip6_fib_table_sub_tree_walk(fib_index, root, fn, ctx);
1244 case FIB_PROTOCOL_MPLS:
1250 fib_table_unlock (u32 fib_index,
1251 fib_protocol_t proto,
1252 fib_source_t source)
1254 fib_table_t *fib_table;
1256 fib_table = fib_table_get(fib_index, proto);
1257 fib_table->ft_locks[source]--;
1258 fib_table->ft_locks[FIB_TABLE_TOTAL_LOCKS]--;
1260 if (0 == fib_table->ft_locks[FIB_TABLE_TOTAL_LOCKS])
1263 * no more locak from any source - kill it
1265 fib_table_destroy(fib_table);
1270 fib_table_lock (u32 fib_index,
1271 fib_protocol_t proto,
1272 fib_source_t source)
1274 fib_table_t *fib_table;
1276 fib_table = fib_table_get(fib_index, proto);
1278 ASSERT(fib_table->ft_locks[source] < (0xffff - 1));
1280 fib_table->ft_locks[source]++;
1281 fib_table->ft_locks[FIB_TABLE_TOTAL_LOCKS]++;
1285 fib_table_get_num_entries (u32 fib_index,
1286 fib_protocol_t proto,
1287 fib_source_t source)
1289 fib_table_t *fib_table;
1291 fib_table = fib_table_get(fib_index, proto);
1293 return (fib_table->ft_src_route_counts[source]);
1297 format_fib_table_name (u8* s, va_list* ap)
1299 fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
1300 fib_protocol_t proto = va_arg(*ap, int); // int promotion
1301 fib_table_t *fib_table;
1303 fib_table = fib_table_get(fib_index, proto);
1305 s = format(s, "%v", fib_table->ft_desc);
1311 format_fib_table_flags (u8 *s, va_list *args)
1313 fib_table_flags_t flags = va_arg(*args, int);
1314 fib_table_attribute_t attr;
1318 return format(s, "none");
1321 FOR_EACH_FIB_TABLE_ATTRIBUTE(attr) {
1322 if (1 << attr & flags) {
1323 s = format(s, "%s", fib_table_flags_strings[attr]);
1331 * @brief Table flush context. Store the indicies of matching FIB entries
1332 * that need to be removed.
1334 typedef struct fib_table_flush_ctx_t_
1337 * The list of entries to flush
1339 fib_node_index_t *ftf_entries;
1342 * The source we are flushing
1344 fib_source_t ftf_source;
1345 } fib_table_flush_ctx_t;
1347 static fib_table_walk_rc_t
1348 fib_table_flush_cb (fib_node_index_t fib_entry_index,
1351 fib_table_flush_ctx_t *ctx = arg;
1353 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1355 vec_add1(ctx->ftf_entries, fib_entry_index);
1357 return (FIB_TABLE_WALK_CONTINUE);
1361 fib_table_flush (u32 fib_index,
1362 fib_protocol_t proto,
1363 fib_source_t source)
1365 fib_node_index_t *fib_entry_index;
1366 fib_table_flush_ctx_t ctx = {
1367 .ftf_entries = NULL,
1368 .ftf_source = source,
1371 fib_table_walk(fib_index, proto,
1375 vec_foreach(fib_entry_index, ctx.ftf_entries)
1377 fib_table_entry_delete_index(*fib_entry_index, source);
1380 vec_free(ctx.ftf_entries);
1383 static fib_table_walk_rc_t
1384 fib_table_mark_cb (fib_node_index_t fib_entry_index,
1387 fib_table_flush_ctx_t *ctx = arg;
1389 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1391 fib_entry_mark(fib_entry_index, ctx->ftf_source);
1393 return (FIB_TABLE_WALK_CONTINUE);
1397 fib_table_mark (u32 fib_index,
1398 fib_protocol_t proto,
1399 fib_source_t source)
1401 fib_table_flush_ctx_t ctx = {
1402 .ftf_source = source,
1404 fib_table_t *fib_table;
1406 fib_table = fib_table_get(fib_index, proto);
1408 fib_table->ft_epoch++;
1409 fib_table->ft_flags |= FIB_TABLE_FLAG_RESYNC;
1411 fib_table_walk(fib_index, proto,
1416 static fib_table_walk_rc_t
1417 fib_table_sweep_cb (fib_node_index_t fib_entry_index,
1420 fib_table_flush_ctx_t *ctx = arg;
1422 if (fib_entry_is_marked(fib_entry_index, ctx->ftf_source))
1424 vec_add1(ctx->ftf_entries, fib_entry_index);
1426 return (FIB_TABLE_WALK_CONTINUE);
1430 fib_table_sweep (u32 fib_index,
1431 fib_protocol_t proto,
1432 fib_source_t source)
1434 fib_table_flush_ctx_t ctx = {
1435 .ftf_source = source,
1437 fib_node_index_t *fib_entry_index;
1438 fib_table_t *fib_table;
1440 fib_table = fib_table_get(fib_index, proto);
1442 fib_table->ft_flags &= ~FIB_TABLE_FLAG_RESYNC;
1444 fib_table_walk(fib_index, proto,
1448 vec_foreach(fib_entry_index, ctx.ftf_entries)
1450 fib_table_entry_delete_index(*fib_entry_index, source);
1453 vec_free(ctx.ftf_entries);
1457 format_fib_table_memory (u8 *s, va_list *args)
1459 s = format(s, "%U", format_ip4_fib_table_memory);
1460 s = format(s, "%U", format_ip6_fib_table_memory);
1461 s = format(s, "%U", format_mpls_fib_table_memory);