ip-neighbor: Replace feature for the ip-neighbor data-base
Type: feature
DB replace is implemented with a mark and sweep algorithm (just the the
FIB)
Signed-off-by: Neale Ranns <nranns@cisco.com>
Change-Id: I54ab06e11552219e2a18e1b4a87d531321cf3829
diff --git a/src/vnet/ip-neighbor/ip_neighbor.api b/src/vnet/ip-neighbor/ip_neighbor.api
index b820360..fc8f822 100644
--- a/src/vnet/ip-neighbor/ip_neighbor.api
+++ b/src/vnet/ip-neighbor/ip_neighbor.api
@@ -126,6 +126,43 @@
bool recycle;
};
+/** \brief IP neighbour replace begin
+
+ The use-case is that, for some unspecified reason, the control plane
+ has a different set of neighbours it than VPP
+ currently has. The CP would thus like to 'replace' VPP's set
+ only by specifying what the new set shall be, i.e. it is not
+ going to delete anything that already eixts, rather, is wants any
+ unspecified neighbors deleted implicitly.
+ The CP declares the start of this procedure with this replace_begin
+ API Call, and when it has populated all neighbours it wants, it calls
+ the below replace_end API. From this point on it is of course free
+ to add and delete neighbours as usual.
+ The underlying mechanism by which VPP implements this replace is
+ intentionally left unspecified.
+
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+autoreply define ip_neighbor_replace_begin
+{
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief IP neighbour replace end
+
+ see ip_neighbor_replace_begin description.
+
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+autoreply define ip_neighbor_replace_end
+{
+ u32 client_index;
+ u32 context;
+};
+
/** \brief Register for IP4 ARP resolution event on receing ARP reply or
MAC/IP info from ARP requests in L2 BDs
@param client_index - opaque cookie to identify the sender
diff --git a/src/vnet/ip-neighbor/ip_neighbor.c b/src/vnet/ip-neighbor/ip_neighbor.c
index 960da12..5b18473 100644
--- a/src/vnet/ip-neighbor/ip_neighbor.c
+++ b/src/vnet/ip-neighbor/ip_neighbor.c
@@ -99,6 +99,12 @@
return (ipn - ip_neighbor_pool);
}
+static void
+ip_neighbor_touch (ip_neighbor_t * ipn)
+{
+ ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_STALE;
+}
+
static bool
ip_neighbor_is_dynamic (const ip_neighbor_t * ipn)
{
@@ -145,6 +151,7 @@
* list is time sorted, newest first */
ip_neighbor_elt_t *elt, *head;
+ ip_neighbor_touch (ipn);
ipn->ipn_time_last_updated = vlib_time_now (vlib_get_main ());
ipn->ipn_n_probes = 0;
@@ -473,6 +480,8 @@
format_ip_neighbor_flags, flags, format_mac_address_t,
mac);
+ ip_neighbor_touch (ipn);
+
/* Refuse to over-write static neighbor entry. */
if (!(flags & IP_NEIGHBOR_FLAG_STATIC) &&
(ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
@@ -1177,6 +1186,60 @@
vec_free (ipnis);
}
+static walk_rc_t
+ip_neighbor_mark_one (index_t ipni, void *ctx)
+{
+ ip_neighbor_t *ipn;
+
+ ipn = ip_neighbor_get (ipni);
+
+ ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STALE;
+
+ return (WALK_CONTINUE);
+}
+
+void
+ip_neighbor_mark (ip46_type_t type)
+{
+ ip_neighbor_walk (type, ~0, ip_neighbor_mark_one, NULL);
+}
+
+typedef struct ip_neighbor_sweep_ctx_t_
+{
+ index_t *ipnsc_stale;
+} ip_neighbor_sweep_ctx_t;
+
+static walk_rc_t
+ip_neighbor_sweep_one (index_t ipni, void *arg)
+{
+ ip_neighbor_sweep_ctx_t *ctx = arg;
+ ip_neighbor_t *ipn;
+
+ ipn = ip_neighbor_get (ipni);
+
+ if (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STALE)
+ {
+ vec_add1 (ctx->ipnsc_stale, ipni);
+ }
+
+ return (WALK_CONTINUE);
+}
+
+void
+ip_neighbor_sweep (ip46_type_t type)
+{
+ ip_neighbor_sweep_ctx_t ctx = { };
+ index_t *ipni;
+
+ ip_neighbor_walk (type, ~0, ip_neighbor_sweep_one, &ctx);
+
+ vec_foreach (ipni, ctx.ipnsc_stale)
+ {
+ ip_neighbor_free (ip_neighbor_get (*ipni));
+ }
+ vec_free (ctx.ipnsc_stale);
+}
+
/*
* Remove any arp entries associated with the specified interface
*/
diff --git a/src/vnet/ip-neighbor/ip_neighbor.h b/src/vnet/ip-neighbor/ip_neighbor.h
index cb384c5..8769fd5 100644
--- a/src/vnet/ip-neighbor/ip_neighbor.h
+++ b/src/vnet/ip-neighbor/ip_neighbor.h
@@ -62,6 +62,9 @@
extern void ip_neighbor_probe_dst (const ip_adjacency_t * adj,
const ip46_address_t * ip);
+extern void ip_neighbor_mark (ip46_type_t type);
+extern void ip_neighbor_sweep (ip46_type_t type);
+
/**
* From the watcher to the API to publish a new neighbor
*/
diff --git a/src/vnet/ip-neighbor/ip_neighbor_api.c b/src/vnet/ip-neighbor/ip_neighbor_api.c
index ec1e493..86587fa 100644
--- a/src/vnet/ip-neighbor/ip_neighbor_api.c
+++ b/src/vnet/ip-neighbor/ip_neighbor_api.c
@@ -275,6 +275,32 @@
REPLY_MACRO (VL_API_IP_NEIGHBOR_CONFIG_REPLY);
}
+static void
+vl_api_ip_neighbor_replace_begin_t_handler (vl_api_ip_neighbor_replace_begin_t
+ * mp)
+{
+ vl_api_ip_neighbor_replace_begin_reply_t *rmp;
+ int rv = 0;
+
+ ip_neighbor_mark (IP46_TYPE_IP4);
+ ip_neighbor_mark (IP46_TYPE_IP6);
+
+ REPLY_MACRO (VL_API_IP_NEIGHBOR_REPLACE_BEGIN_REPLY);
+}
+
+static void
+vl_api_ip_neighbor_replace_end_t_handler (vl_api_ip_neighbor_replace_end_t *
+ mp)
+{
+ vl_api_ip_neighbor_replace_end_reply_t *rmp;
+ int rv = 0;
+
+ ip_neighbor_sweep (IP46_TYPE_IP4);
+ ip_neighbor_sweep (IP46_TYPE_IP6);
+
+ REPLY_MACRO (VL_API_IP_NEIGHBOR_REPLACE_END_REPLY);
+}
+
#define vl_msg_name_crc_list
#include <vnet/ip-neighbor/ip_neighbor.api.h>
#undef vl_msg_name_crc_list
diff --git a/src/vnet/ip-neighbor/ip_neighbor_types.c b/src/vnet/ip-neighbor/ip_neighbor_types.c
index 27262a5..32c674d 100644
--- a/src/vnet/ip-neighbor/ip_neighbor_types.c
+++ b/src/vnet/ip-neighbor/ip_neighbor_types.c
@@ -22,19 +22,14 @@
{
ip_neighbor_flags_t flags = va_arg (*args, int);
- if (flags & IP_NEIGHBOR_FLAG_STATIC)
- s = format (s, "S");
-
- if (flags & IP_NEIGHBOR_FLAG_DYNAMIC)
- s = format (s, "D");
-
- if (flags & IP_NEIGHBOR_FLAG_NO_FIB_ENTRY)
- s = format (s, "N");
-
- return s;
+#define _(a,b,c,d) \
+ if (flags & IP_NEIGHBOR_FLAG_##a) \
+ s = format (s, "%s", d);
+ foreach_ip_neighbor_flag
+#undef _
+ return s;
}
-
u8 *
format_ip_neighbor_key (u8 * s, va_list * va)
{
diff --git a/src/vnet/ip-neighbor/ip_neighbor_types.h b/src/vnet/ip-neighbor/ip_neighbor_types.h
index c6d4e10..82c5417 100644
--- a/src/vnet/ip-neighbor/ip_neighbor_types.h
+++ b/src/vnet/ip-neighbor/ip_neighbor_types.h
@@ -37,13 +37,19 @@
u8 stale_threshold; /* Threshold in minutes to delete nei entry */
} ip_neighbor_scan_arg_t;
+#define foreach_ip_neighbor_flag \
+ _(STATIC, 1 << 0, "static", "S") \
+ _(DYNAMIC, 1 << 1, "dynamic", "D") \
+ _(NO_FIB_ENTRY, 1 << 2, "no-fib-entry", "N") \
+ _(PENDING, 1 << 3, "pending", "P") \
+ _(STALE, 1 << 4, "stale", "A") \
+
typedef enum ip_neighbor_flags_t_
{
IP_NEIGHBOR_FLAG_NONE = 0,
- IP_NEIGHBOR_FLAG_STATIC = (1 << 0),
- IP_NEIGHBOR_FLAG_DYNAMIC = (1 << 1),
- IP_NEIGHBOR_FLAG_NO_FIB_ENTRY = (1 << 2),
- IP_NEIGHBOR_FLAG_PENDING = (1 << 3),
+#define _(a,b,c,d) IP_NEIGHBOR_FLAG_##a = b,
+ foreach_ip_neighbor_flag
+#undef _
} __attribute__ ((packed)) ip_neighbor_flags_t;
typedef struct ip_neighbor_watcher_t_