aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthew Smith <mgsmith@netgate.com>2023-09-26 13:08:26 +0000
committerDave Wallace <dwallacelf@gmail.com>2023-12-01 19:28:40 +0000
commit0d7d22cf677c9b88139d907b9c079a7c81afe136 (patch)
tree99d6cf402d442185ac7c9ee63e059b71367702e7 /src
parent6cc757eff7b8c0d2bfaf6a8061c370d880fa89ca (diff)
fib: only update glean for interface if necessary
Type: improvement If an interface address is added, the glean adjacency for it's covering prefix is updated with that address. In the case of multiple addresses within the same prefix being added, the most recently added one will end up being used as the sender protocol address for ARP requests. Similar behavior occurs when an interface address is deleted. The glean adjacency is updated to some appropriate entry under it's covering prefix. If there were multiple interface addresses configured, we may update the address on the adjacency even though the address currently in use is not the one being deleted. Add a new value PROVIDES_GLEAN to fib_entry_src_flag_t. The flag identifies whether a source interface entry is being used as the address for the glean adjacency for the covering prefix. Update logic so that the glean is only updated on adding an interface address if there is not already a sibling entry in use which has the flag set. Also, only update the glean on deleting an interface address if the address being deleted has the flag set. Also update unit test which validates expected behavior in the case where multiple addresses within a prefix are configured on an interface. Signed-off-by: Matthew Smith <mgsmith@netgate.com> Change-Id: I7d918b8dd703735b20ec76e0a60af6d7e571b766 (cherry picked from commit 9e5694b405e0200725a993f0c17d452fab508435)
Diffstat (limited to 'src')
-rw-r--r--src/vnet/fib/fib_entry.h8
-rw-r--r--src/vnet/fib/fib_entry_src_interface.c81
2 files changed, 81 insertions, 8 deletions
diff --git a/src/vnet/fib/fib_entry.h b/src/vnet/fib/fib_entry.h
index 223928354b7..7331f803ec4 100644
--- a/src/vnet/fib/fib_entry.h
+++ b/src/vnet/fib/fib_entry.h
@@ -154,9 +154,13 @@ typedef enum fib_entry_src_attribute_t_ {
*/
FIB_ENTRY_SRC_ATTRIBUTE_INHERITED,
/**
+ * the source is currently used as glean src address
+ */
+ FIB_ENTRY_SRC_ATTRIBUTE_PROVIDES_GLEAN,
+ /**
* Marker. add new entries before this one.
*/
- FIB_ENTRY_SRC_ATTRIBUTE_LAST = FIB_ENTRY_SRC_ATTRIBUTE_INHERITED,
+ FIB_ENTRY_SRC_ATTRIBUTE_LAST = FIB_ENTRY_SRC_ATTRIBUTE_PROVIDES_GLEAN,
} fib_entry_src_attribute_t;
@@ -166,6 +170,7 @@ typedef enum fib_entry_src_attribute_t_ {
[FIB_ENTRY_SRC_ATTRIBUTE_ACTIVE] = "active", \
[FIB_ENTRY_SRC_ATTRIBUTE_STALE] = "stale", \
[FIB_ENTRY_SRC_ATTRIBUTE_INHERITED] = "inherited", \
+ [FIB_ENTRY_SRC_ATTRIBUTE_PROVIDES_GLEAN] = "provides-glean", \
}
#define FOR_EACH_FIB_SRC_ATTRIBUTE(_item) \
@@ -180,6 +185,7 @@ typedef enum fib_entry_src_flag_t_ {
FIB_ENTRY_SRC_FLAG_ACTIVE = (1 << FIB_ENTRY_SRC_ATTRIBUTE_ACTIVE),
FIB_ENTRY_SRC_FLAG_STALE = (1 << FIB_ENTRY_SRC_ATTRIBUTE_STALE),
FIB_ENTRY_SRC_FLAG_INHERITED = (1 << FIB_ENTRY_SRC_ATTRIBUTE_INHERITED),
+ FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN = (1 << FIB_ENTRY_SRC_ATTRIBUTE_PROVIDES_GLEAN),
} __attribute__ ((packed)) fib_entry_src_flag_t;
extern u8 * format_fib_entry_src_flags(u8 *s, va_list *args);
diff --git a/src/vnet/fib/fib_entry_src_interface.c b/src/vnet/fib/fib_entry_src_interface.c
index 402369d1dfc..c5028dc8798 100644
--- a/src/vnet/fib/fib_entry_src_interface.c
+++ b/src/vnet/fib/fib_entry_src_interface.c
@@ -87,8 +87,16 @@ fib_entry_src_interface_update_glean (fib_entry_t *cover,
if (fib_prefix_is_cover(&adj->sub_type.glean.rx_pfx,
&local->fe_prefix))
{
- adj->sub_type.glean.rx_pfx.fp_addr = local->fe_prefix.fp_addr;
- return (1);
+ fib_entry_src_t *local_src;
+
+ local_src = fib_entry_src_find (local, FIB_SOURCE_INTERFACE);
+ if (local_src != NULL)
+ {
+ adj->sub_type.glean.rx_pfx.fp_addr =
+ local->fe_prefix.fp_addr;
+ local_src->fes_flags |= FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN;
+ return (1);
+ }
}
}
}
@@ -116,6 +124,52 @@ fib_entry_src_interface_path_swap (fib_entry_src_t *src,
src->fes_pl = fib_path_list_create(pl_flags, paths);
}
+typedef struct fesi_find_glean_ctx_t_ {
+ fib_node_index_t glean_node_index;
+} fesi_find_glean_ctx_t;
+
+static walk_rc_t
+fib_entry_src_interface_find_glean_walk (fib_entry_t *cover,
+ fib_node_index_t covered,
+ void *ctx)
+{
+ fesi_find_glean_ctx_t *find_glean_ctx = ctx;
+ fib_entry_t *covered_entry;
+ fib_entry_src_t *covered_src;
+
+ covered_entry = fib_entry_get (covered);
+ covered_src = fib_entry_src_find (covered_entry, FIB_SOURCE_INTERFACE);
+ if ((covered_src != NULL) &&
+ (covered_src->fes_flags & FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN))
+ {
+ find_glean_ctx->glean_node_index = covered;
+ return WALK_STOP;
+ }
+
+ return WALK_CONTINUE;
+}
+
+static fib_entry_t *
+fib_entry_src_interface_find_glean (fib_entry_t *cover)
+{
+ fib_entry_src_t *src;
+
+ src = fib_entry_src_find (cover, FIB_SOURCE_INTERFACE);
+ if (src == NULL)
+ /* the cover is not an interface source */
+ return NULL;
+
+ fesi_find_glean_ctx_t ctx = {
+ .glean_node_index = ~0,
+ };
+
+ fib_entry_cover_walk (cover, fib_entry_src_interface_find_glean_walk,
+ &ctx);
+
+ return (ctx.glean_node_index == ~0) ? NULL :
+ fib_entry_get (ctx.glean_node_index);
+}
+
/*
* Source activate.
* Called when the source is teh new longer best source on the entry
@@ -128,6 +182,8 @@ fib_entry_src_interface_activate (fib_entry_src_t *src,
if (FIB_ENTRY_FLAG_LOCAL & src->fes_entry_flags)
{
+ u8 update_glean;
+
/*
* Track the covering attached/connected cover. This is so that
* during an attached export of the cover, this local prefix is
@@ -141,10 +197,17 @@ fib_entry_src_interface_activate (fib_entry_src_t *src,
cover = fib_entry_get(src->u.interface.fesi_cover);
+ /*
+ * Before adding as a child of the cover, check whether an existing
+ * child has already been used to populate the glean adjacency. If so,
+ * we don't need to update the adjacency.
+ */
+ update_glean = (fib_entry_src_interface_find_glean (cover) == NULL);
src->u.interface.fesi_sibling =
fib_entry_cover_track(cover, fib_entry_get_index(fib_entry));
- fib_entry_src_interface_update_glean(cover, fib_entry);
+ if (update_glean)
+ fib_entry_src_interface_update_glean(cover, fib_entry);
}
return (!0);
@@ -167,15 +230,19 @@ fib_entry_src_interface_deactivate (fib_entry_src_t *src,
if (FIB_NODE_INDEX_INVALID != src->u.interface.fesi_cover)
{
cover = fib_entry_get(src->u.interface.fesi_cover);
-
fib_entry_cover_untrack(cover, src->u.interface.fesi_sibling);
src->u.interface.fesi_cover = FIB_NODE_INDEX_INVALID;
src->u.interface.fesi_sibling = ~0;
- fib_entry_cover_walk(cover,
- fib_entry_src_interface_update_glean_walk,
- NULL);
+ /* If this was the glean address, find a new one */
+ if (src->fes_flags & FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN)
+ {
+ fib_entry_cover_walk(cover,
+ fib_entry_src_interface_update_glean_walk,
+ NULL);
+ src->fes_flags &= ~FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN;
+ }
}
}