summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Zalamena <rzalamena@opensourcerouting.org>2019-12-04 15:07:11 -0300
committerRafael Zalamena <rzalamena@opensourcerouting.org>2020-04-14 11:44:39 -0300
commit018e77bcb55e299a7da7bf5435c32040ec362e46 (patch)
tree4846a18d0df62666bd7824fbf5999b8dfe759bc6
parentd35f447d67a59c8916378662a55eb368990d4706 (diff)
zebra: data plane FPM RIB walk code
Implement the code that walks the RIB to send routes that are already inside the RIB. Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
-rw-r--r--zebra/dplane_fpm_nl.c113
-rw-r--r--zebra/zebra_dplane.c6
-rw-r--r--zebra/zebra_dplane.h3
3 files changed, 118 insertions, 4 deletions
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index d859834fc8..2cd2cb58e2 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -35,6 +35,7 @@
#include "lib/ns.h"
#include "lib/frr_pthread.h"
#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_router.h"
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
#include "zebra/debug.h"
@@ -48,6 +49,7 @@ struct fpm_nl_ctx {
/* data plane connection. */
int socket;
bool connecting;
+ bool rib_complete;
struct sockaddr_storage addr;
/* data plane buffers. */
@@ -60,9 +62,20 @@ struct fpm_nl_ctx {
struct thread *t_connect;
struct thread *t_read;
struct thread *t_write;
+
+ /* zebra events. */
+ struct thread *t_ribreset;
+ struct thread *t_ribwalk;
};
/*
+ * Prototypes.
+ */
+static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx);
+static int fpm_rib_send(struct thread *t);
+static int fpm_rib_reset(struct thread *t);
+
+/*
* FPM functions.
*/
static int fpm_connect(struct thread *t);
@@ -78,6 +91,12 @@ static void fpm_reconnect(struct fpm_nl_ctx *fnc)
stream_reset(fnc->obuf);
THREAD_OFF(fnc->t_read);
THREAD_OFF(fnc->t_write);
+
+ if (fnc->t_ribreset)
+ thread_cancel_async(zrouter.master, &fnc->t_ribreset, NULL);
+ if (fnc->t_ribwalk)
+ thread_cancel_async(zrouter.master, &fnc->t_ribwalk, NULL);
+
thread_add_timer(fnc->fthread->master, fpm_connect, fnc, 3,
&fnc->t_connect);
}
@@ -140,6 +159,10 @@ static int fpm_write(struct thread *t)
}
fnc->connecting = false;
+
+ /* Ask zebra main thread to start walking the RIB table. */
+ thread_add_timer(zrouter.master, fpm_rib_send, fnc, 0,
+ &fnc->t_ribwalk);
}
frr_mutex_lock_autounlock(&fnc->obuf_mutex);
@@ -231,6 +254,10 @@ static int fpm_connect(struct thread *t)
thread_add_write(fnc->fthread->master, fpm_write, fnc, sock,
&fnc->t_write);
+ /* Mark all routes as unsent. */
+ thread_add_timer(zrouter.master, fpm_rib_reset, fnc, 0,
+ &fnc->t_ribreset);
+
return 0;
}
@@ -353,6 +380,92 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
return 0;
}
+/**
+ * Send all RIB installed routes to the connected data plane.
+ */
+static int fpm_rib_send(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ rib_dest_t *dest;
+ struct route_node *rn;
+ struct route_table *rt;
+ struct zebra_dplane_ctx *ctx;
+ rib_tables_iter_t rt_iter;
+
+ /* Allocate temporary context for all transactions. */
+ ctx = dplane_ctx_alloc();
+
+ rt_iter.state = RIB_TABLES_ITER_S_INIT;
+ while ((rt = rib_tables_iter_next(&rt_iter))) {
+ for (rn = route_top(rt); rn; rn = srcdest_route_next(rn)) {
+ dest = rib_dest_from_rnode(rn);
+ /* Skip bad route entries. */
+ if (dest == NULL || dest->selected_fib == NULL) {
+ continue;
+ }
+
+ /* Check for already sent routes. */
+ if (CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_FPM)) {
+ continue;
+ }
+
+ /* Enqueue route install. */
+ dplane_ctx_reset(ctx);
+ dplane_ctx_route_init(ctx, DPLANE_OP_ROUTE_INSTALL, rn,
+ dest->selected_fib);
+ if (fpm_nl_enqueue(fnc, ctx) == -1) {
+ /* Free the temporary allocated context. */
+ dplane_ctx_fini(&ctx);
+
+ zlog_debug("%s: buffer full, come back later",
+ __func__);
+ thread_add_timer(zrouter.master, fpm_rib_send,
+ fnc, 1, &fnc->t_ribwalk);
+ return 0;
+ }
+
+ /* Mark as sent. */
+ SET_FLAG(dest->flags, RIB_DEST_UPDATE_FPM);
+ }
+ }
+
+ /* Free the temporary allocated context. */
+ dplane_ctx_fini(&ctx);
+
+ /* All RIB routes sent! */
+ fnc->rib_complete = true;
+
+ return 0;
+}
+
+/**
+ * Resets the RIB FPM flags so we send all routes again.
+ */
+static int fpm_rib_reset(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ rib_dest_t *dest;
+ struct route_node *rn;
+ struct route_table *rt;
+ rib_tables_iter_t rt_iter;
+
+ fnc->rib_complete = false;
+
+ rt_iter.state = RIB_TABLES_ITER_S_INIT;
+ while ((rt = rib_tables_iter_next(&rt_iter))) {
+ for (rn = route_top(rt); rn; rn = srcdest_route_next(rn)) {
+ dest = rib_dest_from_rnode(rn);
+ /* Skip bad route entries. */
+ if (dest == NULL)
+ continue;
+
+ UNSET_FLAG(dest->flags, RIB_DEST_UPDATE_FPM);
+ }
+ }
+
+ return 0;
+}
+
/*
* Data plane functions.
*/
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index dde572df93..e3eeecefc4 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -1525,10 +1525,8 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
/*
* Initialize a context block for a route update from zebra data structs.
*/
-static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
- enum dplane_op_e op,
- struct route_node *rn,
- struct route_entry *re)
+int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ struct route_node *rn, struct route_entry *re)
{
int ret = EINVAL;
const struct route_table *table = NULL;
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 9fe8b3b513..8302758d3f 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -489,6 +489,9 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
const struct in_addr *ip,
vni_t vni);
+/* Encode route information into data plane context. */
+int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ struct route_node *rn, struct route_entry *re);
/* Retrieve the limit on the number of pending, unprocessed updates. */
uint32_t dplane_get_in_queue_limit(void);