#include <vnet/fib/ip6_fib.h>
#include <vnet/fib/mpls_fib.h>
+const static char * fib_table_flags_strings[] = FIB_TABLE_ATTRIBUTES;
+
+/*
+ * Default names for IP4, IP6, and MPLS FIB table index 0.
+ * Nominally like "ipv6-VRF:0", but this will override that name if set
+ * in a config section of the startup.conf file.
+ */
+char *fib_table_default_names[FIB_PROTOCOL_MAX];
+
fib_table_t *
fib_table_get (fib_node_index_t index,
fib_protocol_t proto)
}
}
+static void
+fib_table_source_count_inc (fib_table_t *fib_table,
+ fib_source_t source)
+{
+ vec_validate (fib_table->ft_src_route_counts, source);
+ fib_table->ft_src_route_counts[source]++;
+}
+
+static void
+fib_table_source_count_dec (fib_table_t *fib_table,
+ fib_source_t source)
+{
+ vec_validate (fib_table->ft_src_route_counts, source);
+ fib_table->ft_src_route_counts[source]--;
+}
fib_node_index_t
fib_table_entry_special_dpo_add (u32 fib_index,
dpo);
fib_table_entry_insert(fib_table, prefix, fib_entry_index);
- fib_table->ft_src_route_counts[source]++;
+ fib_table_source_count_inc(fib_table, source);
}
else
{
if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
{
- fib_table->ft_src_route_counts[source]++;
+ fib_table_source_count_inc(fib_table, source);
}
}
dpo);
fib_table_entry_insert(fib_table, prefix, fib_entry_index);
- fib_table->ft_src_route_counts[source]++;
+ fib_table_source_count_inc(fib_table, source);
}
else
{
if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
{
- fib_table->ft_src_route_counts[source]++;
+ fib_table_source_count_inc(fib_table, source);
}
}
*/
if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
{
- fib_table->ft_src_route_counts[source]--;
+ fib_table_source_count_dec(fib_table, source);
}
fib_entry_unlock(fib_entry_index);
*/
static void
fib_table_route_path_fixup (const fib_prefix_t *prefix,
- fib_entry_flag_t eflags,
+ fib_entry_flag_t *eflags,
fib_route_path_t *path)
{
/*
(~0 == path->frp_sw_if_index) &&
(0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
{
- /* Prefix recurses via itse;f */
+ /* Prefix recurses via itself */
path->frp_flags |= FIB_ROUTE_PATH_DROP;
}
- if (fib_prefix_is_host(prefix) &&
+ if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
+ fib_prefix_is_host(prefix) &&
ip46_address_is_zero(&path->frp_addr) &&
path->frp_sw_if_index != ~0 &&
path->frp_proto != DPO_PROTO_ETHERNET)
path->frp_addr = prefix->fp_addr;
path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
}
- if (eflags & FIB_ENTRY_FLAG_DROP)
+ else if ((*eflags & FIB_ENTRY_FLAG_CONNECTED) &&
+ !(*eflags & FIB_ENTRY_FLAG_LOCAL))
+ {
+ if (ip46_address_is_zero(&path->frp_addr))
+ {
+ path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
+ fib_prefix_normalize(prefix, &path->frp_connected);
+ }
+ }
+ else if (fib_route_path_is_attached(path))
+ {
+ path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
+ /*
+ * attached prefixes are not suitable as the source of ARP requests
+ * so don't save the prefix in the glean adj
+ */
+ clib_memset(&path->frp_connected, 0, sizeof(path->frp_connected));
+ }
+ if (*eflags & FIB_ENTRY_FLAG_DROP)
{
path->frp_flags |= FIB_ROUTE_PATH_DROP;
}
- if (eflags & FIB_ENTRY_FLAG_LOCAL)
+ if (*eflags & FIB_ENTRY_FLAG_LOCAL)
{
path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
}
- if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
+ if (*eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
{
path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
}
+ if (path->frp_flags & FIB_ROUTE_PATH_LOCAL)
+ {
+ *eflags |= FIB_ENTRY_FLAG_LOCAL;
+
+ if (path->frp_sw_if_index != ~0)
+ {
+ *eflags |= FIB_ENTRY_FLAG_CONNECTED;
+ }
+ }
}
fib_node_index_t
.frp_fib_index = next_hop_fib_index,
.frp_weight = next_hop_weight,
.frp_flags = path_flags,
+ .frp_rpf_id = INDEX_INVALID,
.frp_label_stack = next_hop_labels,
};
fib_node_index_t fib_entry_index;
return (fib_entry_index);
}
+static int
+fib_route_path_cmp_for_sort (void * v1,
+ void * v2)
+{
+ return (fib_route_path_cmp(v1, v2));
+}
+
fib_node_index_t
fib_table_entry_path_add2 (u32 fib_index,
const fib_prefix_t *prefix,
fib_source_t source,
fib_entry_flag_t flags,
- fib_route_path_t *rpath)
+ fib_route_path_t *rpaths)
{
fib_node_index_t fib_entry_index;
fib_table_t *fib_table;
fib_table = fib_table_get(fib_index, prefix->fp_proto);
fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
- for (ii = 0; ii < vec_len(rpath); ii++)
+ for (ii = 0; ii < vec_len(rpaths); ii++)
{
- fib_table_route_path_fixup(prefix, flags, &rpath[ii]);
+ fib_table_route_path_fixup(prefix, &flags, &rpaths[ii]);
}
+ /*
+ * sort the paths provided by the control plane. this means
+ * the paths and the extension on the entry will be sorted.
+ */
+ vec_sort_with_function(rpaths, fib_route_path_cmp_for_sort);
if (FIB_NODE_INDEX_INVALID == fib_entry_index)
{
fib_entry_index = fib_entry_create(fib_index, prefix,
source, flags,
- rpath);
+ rpaths);
fib_table_entry_insert(fib_table, prefix, fib_entry_index);
- fib_table->ft_src_route_counts[source]++;
+ fib_table_source_count_inc(fib_table, source);
}
else
{
int was_sourced;
was_sourced = fib_entry_is_sourced(fib_entry_index, source);
- fib_entry_path_add(fib_entry_index, source, flags, rpath);;
+ fib_entry_path_add(fib_entry_index, source, flags, rpaths);;
if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
{
- fib_table->ft_src_route_counts[source]++;
+ fib_table_source_count_inc(fib_table, source);
}
}
fib_table_entry_path_remove2 (u32 fib_index,
const fib_prefix_t *prefix,
fib_source_t source,
- fib_route_path_t *rpath)
+ fib_route_path_t *rpaths)
{
/*
* 1 is it present
* no => cover walk
*/
fib_node_index_t fib_entry_index;
+ fib_route_path_t *rpath;
fib_table_t *fib_table;
- u32 ii;
fib_table = fib_table_get(fib_index, prefix->fp_proto);
fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
*/
fib_entry_lock(fib_entry_index);
- for (ii = 0; ii < vec_len(rpath); ii++)
+ vec_foreach(rpath, rpaths)
{
- fib_table_route_path_fixup(
- prefix,
- fib_entry_get_flags_for_source(fib_entry_index,
- source),
- &rpath[ii]);
+ fib_entry_flag_t eflags;
+
+ eflags = fib_entry_get_flags_for_source(fib_entry_index,
+ source);
+ fib_table_route_path_fixup(prefix, &eflags, rpath);
}
- src_flag = fib_entry_path_remove(fib_entry_index, source, rpath);
+ src_flag = fib_entry_path_remove(fib_entry_index, source, rpaths);
if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
{
*/
if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
{
- fib_table->ft_src_route_counts[source]--;
+ fib_table_source_count_dec(fib_table, source);
}
fib_entry_unlock(fib_entry_index);
vec_free(paths);
}
-static int
-fib_route_path_cmp_for_sort (void * v1,
- void * v2)
-{
- return (fib_route_path_cmp(v1, v2));
-}
-
fib_node_index_t
fib_table_entry_update (u32 fib_index,
const fib_prefix_t *prefix,
for (ii = 0; ii < vec_len(paths); ii++)
{
- fib_table_route_path_fixup(prefix, flags, &paths[ii]);
+ fib_table_route_path_fixup(prefix, &flags, &paths[ii]);
}
/*
* sort the paths provided by the control plane. this means
paths);
fib_table_entry_insert(fib_table, prefix, fib_entry_index);
- fib_table->ft_src_route_counts[source]++;
+ fib_table_source_count_inc(fib_table, source);
}
else
{
if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
{
- fib_table->ft_src_route_counts[source]++;
+ fib_table_source_count_inc(fib_table, source);
}
}
*/
if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
{
- fib_table->ft_src_route_counts[source]--;
+ fib_table_source_count_dec(fib_table, source);
}
fib_entry_unlock(fib_entry_index);
}
u32
-fib_table_entry_get_stats_index(u32 fib_index,
- const fib_prefix_t *prefix)
+fib_table_entry_get_stats_index (u32 fib_index,
+ const fib_prefix_t *prefix)
{
return (fib_entry_get_stats_index(
fib_table_lookup_exact_match(fib_index, prefix)));
fib_table = fib_table_get(fi, proto);
- if (NULL == fib_table->ft_desc)
+ if (fib_table->ft_desc)
+ return fi;
+
+ if (name && name[0])
{
- if (name && name[0])
- {
- fib_table->ft_desc = format(NULL, "%s", name);
- }
- else
- {
- fib_table->ft_desc = format(NULL, "%U-VRF:%d",
- format_fib_protocol, proto,
- table_id);
- }
+ fib_table->ft_desc = format(NULL, "%s", name);
+ return fi;
}
- return (fi);
+ if (table_id == 0)
+ {
+ char *default_name = fib_table_default_names[proto];
+ if (default_name && default_name[0])
+ {
+ fib_table->ft_desc = format(NULL, "%s", default_name);
+ return fi;
+ }
+ }
+
+ fib_table->ft_desc = format(NULL, "%U-VRF:%d",
+ format_fib_protocol, proto,
+ table_id);
+ return fi;
}
u32
fib_node_index_t fi;
va_list ap;
- va_start(ap, fmt);
switch (proto)
{
fib_table = fib_table_get(fi, proto);
+ va_start(ap, fmt);
+
fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
va_end(ap);
}
}
+typedef struct fib_table_walk_w_src_ctx_t_
+{
+ fib_table_walk_fn_t fn;
+ void *data;
+ fib_source_t src;
+} fib_table_walk_w_src_cxt_t;
+
+static fib_table_walk_rc_t
+fib_table_walk_w_src_cb (fib_node_index_t fei,
+ void *arg)
+{
+ fib_table_walk_w_src_cxt_t *ctx = arg;
+
+ if (ctx->src == fib_entry_get_best_source(fei))
+ {
+ return (ctx->fn(fei, ctx->data));
+ }
+ return (FIB_TABLE_WALK_CONTINUE);
+}
+
+void
+fib_table_walk_w_src (u32 fib_index,
+ fib_protocol_t proto,
+ fib_source_t src,
+ fib_table_walk_fn_t fn,
+ void *data)
+{
+ fib_table_walk_w_src_cxt_t ctx = {
+ .fn = fn,
+ .src = src,
+ .data = data,
+ };
+
+ fib_table_walk(fib_index, proto, fib_table_walk_w_src_cb, &ctx);
+}
+
void
fib_table_sub_tree_walk (u32 fib_index,
fib_protocol_t proto,
}
}
+static void
+fib_table_lock_dec (fib_table_t *fib_table,
+ fib_source_t source)
+{
+ vec_validate(fib_table->ft_locks, source);
+
+ ASSERT(fib_table->ft_locks[source] > 0);
+ fib_table->ft_locks[source]--;
+ fib_table->ft_total_locks--;
+}
+
+static void
+fib_table_lock_inc (fib_table_t *fib_table,
+ fib_source_t source)
+{
+ vec_validate(fib_table->ft_locks, source);
+
+ ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
+ fib_table->ft_locks[source]++;
+ fib_table->ft_total_locks++;
+}
+
+
+static void
+fib_table_lock_clear (fib_table_t *fib_table,
+ fib_source_t source)
+{
+ vec_validate(fib_table->ft_locks, source);
+
+ ASSERT(fib_table->ft_locks[source] <= 1);
+ if (fib_table->ft_locks[source])
+ {
+ fib_table->ft_locks[source]--;
+ fib_table->ft_total_locks--;
+ }
+}
+
+static void
+fib_table_lock_set (fib_table_t *fib_table,
+ fib_source_t source)
+{
+ vec_validate(fib_table->ft_locks, source);
+
+ ASSERT(fib_table->ft_locks[source] <= 1);
+ ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
+ if (!fib_table->ft_locks[source])
+ {
+ fib_table->ft_locks[source]++;
+ fib_table->ft_total_locks++;
+ }
+}
+
void
fib_table_unlock (u32 fib_index,
fib_protocol_t proto,
fib_table_t *fib_table;
fib_table = fib_table_get(fib_index, proto);
- fib_table->ft_locks[source]--;
- fib_table->ft_locks[FIB_TABLE_TOTAL_LOCKS]--;
- if (0 == fib_table->ft_locks[source])
- {
- /*
- * The source no longer needs the table. flush any routes
- * from it just in case
- */
- fib_table_flush(fib_index, proto, source);
- }
+ if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
+ fib_table_lock_clear(fib_table, source);
+ else
+ fib_table_lock_dec(fib_table, source);
- if (0 == fib_table->ft_locks[FIB_TABLE_TOTAL_LOCKS])
+ if (0 == fib_table->ft_total_locks)
{
/*
- * no more locak from any source - kill it
+ * no more lock from any source - kill it
*/
fib_table_destroy(fib_table);
}
fib_table_t *fib_table;
fib_table = fib_table_get(fib_index, proto);
- fib_table->ft_locks[source]++;
- fib_table->ft_locks[FIB_TABLE_TOTAL_LOCKS]++;
+
+ if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
+ fib_table_lock_set(fib_table, source);
+ else
+ fib_table_lock_inc(fib_table, source);
}
u32
return (s);
}
+u8*
+format_fib_table_flags (u8 *s, va_list *args)
+{
+ fib_table_flags_t flags = va_arg(*args, int);
+ fib_table_attribute_t attr;
+
+ if (!flags)
+ {
+ return format(s, "none");
+ }
+
+ FOR_EACH_FIB_TABLE_ATTRIBUTE(attr) {
+ if (1 << attr & flags) {
+ s = format(s, "%s", fib_table_flags_strings[attr]);
+ }
+ }
+
+ return (s);
+}
+
/**
* @brief Table flush context. Store the indicies of matching FIB entries
* that need to be removed.
return (FIB_TABLE_WALK_CONTINUE);
}
-
void
fib_table_flush (u32 fib_index,
fib_protocol_t proto,
vec_free(ctx.ftf_entries);
}
+static fib_table_walk_rc_t
+fib_table_mark_cb (fib_node_index_t fib_entry_index,
+ void *arg)
+{
+ fib_table_flush_ctx_t *ctx = arg;
+
+ if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
+ {
+ fib_entry_mark(fib_entry_index, ctx->ftf_source);
+ }
+ return (FIB_TABLE_WALK_CONTINUE);
+}
+
+void
+fib_table_mark (u32 fib_index,
+ fib_protocol_t proto,
+ fib_source_t source)
+{
+ fib_table_flush_ctx_t ctx = {
+ .ftf_source = source,
+ };
+ fib_table_t *fib_table;
+
+ fib_table = fib_table_get(fib_index, proto);
+
+ fib_table->ft_epoch++;
+ fib_table->ft_flags |= FIB_TABLE_FLAG_RESYNC;
+
+ fib_table_walk(fib_index, proto,
+ fib_table_mark_cb,
+ &ctx);
+}
+
+static fib_table_walk_rc_t
+fib_table_sweep_cb (fib_node_index_t fib_entry_index,
+ void *arg)
+{
+ fib_table_flush_ctx_t *ctx = arg;
+
+ if (fib_entry_is_marked(fib_entry_index, ctx->ftf_source))
+ {
+ vec_add1(ctx->ftf_entries, fib_entry_index);
+ }
+ return (FIB_TABLE_WALK_CONTINUE);
+}
+
+void
+fib_table_sweep (u32 fib_index,
+ fib_protocol_t proto,
+ fib_source_t source)
+{
+ fib_table_flush_ctx_t ctx = {
+ .ftf_source = source,
+ };
+ fib_node_index_t *fib_entry_index;
+ fib_table_t *fib_table;
+
+ fib_table = fib_table_get(fib_index, proto);
+
+ fib_table->ft_flags &= ~FIB_TABLE_FLAG_RESYNC;
+
+ fib_table_walk(fib_index, proto,
+ fib_table_sweep_cb,
+ &ctx);
+
+ vec_foreach(fib_entry_index, ctx.ftf_entries)
+ {
+ fib_table_entry_delete_index(*fib_entry_index, source);
+ }
+
+ vec_free(ctx.ftf_entries);
+}
+
u8 *
format_fib_table_memory (u8 *s, va_list *args)
{