summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Stapp <mjs@voltanet.io>2018-10-23 16:57:01 +0200
committerMark Stapp <mjs@voltanet.io>2019-01-22 18:02:20 +0100
commit16c628de99517efe4c9f960ca7423bc86ac7d5c4 (patch)
tree9d742eaa01d9ebc35a7f78ac93547b04cbd22be7
parentzebra: add apis to add and delete NHLFEs (diff)
downloadfrr-16c628de99517efe4c9f960ca7423bc86ac7d5c4.tar.xz
frr-16c628de99517efe4c9f960ca7423bc86ac7d5c4.zip
zebra: infra for LSP updates using dplane
Adding infra to zebra dplane to support LSP updates. Add kernel api for LSP updates that uses a dataplane context; add stub apis for netlink, bsd, and 'null' kernel paths. Add version of netlink mpls update code that takes a dplane context struct instead of a zebra lsp struct. Signed-off-by: Mark Stapp <mjs@voltanet.io>
-rw-r--r--zebra/rt.h5
-rw-r--r--zebra/rt_netlink.c160
-rw-r--r--zebra/rt_netlink.h4
-rw-r--r--zebra/zebra_dplane.c346
-rw-r--r--zebra/zebra_dplane.h11
-rw-r--r--zebra/zebra_mpls_netlink.c13
-rw-r--r--zebra/zebra_mpls_null.c5
-rw-r--r--zebra/zebra_mpls_openbsd.c5
8 files changed, 503 insertions, 46 deletions
diff --git a/zebra/rt.h b/zebra/rt.h
index 0317dc85b..13a398dd0 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -32,12 +32,15 @@
#include "zebra/zebra_dplane.h"
/*
- * Update or delete a prefix from the kernel,
+ * Update or delete a route or LSP from the kernel,
* using info from a dataplane context.
*/
extern enum zebra_dplane_result kernel_route_update(
struct zebra_dplane_ctx *ctx);
+extern enum zebra_dplane_result kernel_lsp_update(
+ struct zebra_dplane_ctx *ctx);
+
extern int kernel_address_add_ipv4(struct interface *, struct connected *);
extern int kernel_address_delete_ipv4(struct interface *, struct connected *);
extern int kernel_address_add_ipv6(struct interface *, struct connected *);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index ae4bc5272..87c60453b 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -2765,4 +2765,164 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
0);
}
+
+/*
+ * MPLS label forwarding table change via netlink interface, using dataplane
+ * context information.
+ */
+int netlink_mpls_multipath_ctx(int cmd, struct zebra_dplane_ctx *ctx)
+{
+ mpls_lse_t lse;
+ zebra_nhlfe_t *nhlfe;
+ struct nexthop *nexthop = NULL;
+ unsigned int nexthop_num;
+ const char *routedesc;
+ int route_type;
+
+ struct {
+ struct nlmsghdr n;
+ struct rtmsg r;
+ char buf[NL_PKT_BUF_SIZE];
+ } req;
+
+ memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
+
+ /*
+ * Count # nexthops so we can decide whether to use singlepath
+ * or multipath case.
+ */
+ nexthop_num = 0;
+ for (nhlfe = dplane_ctx_get_nhlfe(ctx); nhlfe; nhlfe = nhlfe->next) {
+ nexthop = nhlfe->nexthop;
+ if (!nexthop)
+ continue;
+ if (cmd == RTM_NEWROUTE) {
+ /* Count all selected NHLFEs */
+ if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
+ && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ nexthop_num++;
+ } else { /* DEL */
+ /* Count all installed NHLFEs */
+ if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)
+ && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+ nexthop_num++;
+ }
+ }
+
+ if ((nexthop_num == 0) ||
+ (!dplane_ctx_get_best_nhlfe(ctx) && (cmd != RTM_DELROUTE)))
+ return 0;
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ req.n.nlmsg_type = cmd;
+ req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
+
+ req.r.rtm_family = AF_MPLS;
+ req.r.rtm_table = RT_TABLE_MAIN;
+ req.r.rtm_dst_len = MPLS_LABEL_LEN_BITS;
+ req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.r.rtm_type = RTN_UNICAST;
+
+ if (cmd == RTM_NEWROUTE) {
+ /* We do a replace to handle update. */
+ req.n.nlmsg_flags |= NLM_F_REPLACE;
+
+ /* set the protocol value if installing */
+ route_type = re_type_from_lsp_type(
+ dplane_ctx_get_best_nhlfe(ctx)->type);
+ req.r.rtm_protocol = zebra2proto(route_type);
+ }
+
+ /* Fill destination */
+ lse = mpls_lse_encode(dplane_ctx_get_in_label(ctx), 0, 0, 1);
+ addattr_l(&req.n, sizeof(req), RTA_DST, &lse, sizeof(mpls_lse_t));
+
+ /* Fill nexthops (paths) based on single-path or multipath. The paths
+ * chosen depend on the operation.
+ */
+ if (nexthop_num == 1 || multipath_num == 1) {
+ routedesc = "single-path";
+ _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
+ routedesc);
+
+ nexthop_num = 0;
+ for (nhlfe = dplane_ctx_get_nhlfe(ctx);
+ nhlfe; nhlfe = nhlfe->next) {
+ nexthop = nhlfe->nexthop;
+ if (!nexthop)
+ continue;
+
+ if ((cmd == RTM_NEWROUTE
+ && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
+ && CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_ACTIVE)))
+ || (cmd == RTM_DELROUTE
+ && (CHECK_FLAG(nhlfe->flags,
+ NHLFE_FLAG_INSTALLED)
+ && CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_FIB)))) {
+ /* Add the gateway */
+ _netlink_mpls_build_singlepath(
+ routedesc, nhlfe,
+ &req.n, &req.r,
+ sizeof(req), cmd);
+
+ nexthop_num++;
+ break;
+ }
+ }
+ } else { /* Multipath case */
+ char buf[NL_PKT_BUF_SIZE];
+ struct rtattr *rta = (void *)buf;
+ struct rtnexthop *rtnh;
+ union g_addr *src1 = NULL;
+
+ rta->rta_type = RTA_MULTIPATH;
+ rta->rta_len = RTA_LENGTH(0);
+ rtnh = RTA_DATA(rta);
+
+ routedesc = "multipath";
+ _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
+ routedesc);
+
+ nexthop_num = 0;
+ for (nhlfe = dplane_ctx_get_nhlfe(ctx);
+ nhlfe; nhlfe = nhlfe->next) {
+ nexthop = nhlfe->nexthop;
+ if (!nexthop)
+ continue;
+
+ if (nexthop_num >= multipath_num)
+ break;
+
+ if ((cmd == RTM_NEWROUTE
+ && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
+ && CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_ACTIVE)))
+ || (cmd == RTM_DELROUTE
+ && (CHECK_FLAG(nhlfe->flags,
+ NHLFE_FLAG_INSTALLED)
+ && CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_FIB)))) {
+ nexthop_num++;
+
+ /* Build the multipath */
+ _netlink_mpls_build_multipath(routedesc, nhlfe,
+ rta, rtnh, &req.r,
+ &src1);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+ }
+
+ /* Add the multipath */
+ if (rta->rta_len > RTA_LENGTH(0))
+ addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH,
+ RTA_DATA(rta), RTA_PAYLOAD(rta));
+ }
+
+ /* Talk to netlink socket. */
+ return netlink_talk_info(netlink_talk_filter, &req.n,
+ dplane_ctx_get_ns(ctx), 0);
+}
#endif /* HAVE_NETLINK */
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index cefd1996a..01f555647 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -24,6 +24,7 @@
#ifdef HAVE_NETLINK
#include "zebra/zebra_mpls.h"
+#include "zebra/zebra_dplane.h"
#define NL_DEFAULT_ROUTE_METRIC 20
@@ -60,6 +61,9 @@ void rt_netlink_init(void);
extern int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp);
+/* MPLS label forwarding table change, using dataplane context information. */
+extern int netlink_mpls_multipath_ctx(int cmd, struct zebra_dplane_ctx *ctx);
+
extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int netlink_route_read(struct zebra_ns *zns);
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index a2c803d18..fc316dbcb 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -131,6 +131,7 @@ struct zebra_dplane_ctx {
vrf_id_t zd_vrf_id;
uint32_t zd_table_id;
+ /* Support info for either route or LSP update */
union {
struct dplane_route_info rinfo;
zebra_lsp_t lsp;
@@ -232,6 +233,13 @@ static struct zebra_dplane_globals {
_Atomic uint32_t dg_routes_queued;
_Atomic uint32_t dg_routes_queued_max;
_Atomic uint32_t dg_route_errors;
+ _Atomic uint32_t dg_other_errors;
+
+ _Atomic uint32_t dg_lsps_in;
+ _Atomic uint32_t dg_lsps_queued;
+ _Atomic uint32_t dg_lsps_queued_max;
+ _Atomic uint32_t dg_lsp_errors;
+
_Atomic uint32_t dg_update_yields;
/* Dataplane pthread */
@@ -265,6 +273,8 @@ static struct zebra_dplane_globals {
static int dplane_thread_loop(struct thread *event);
static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
struct zebra_ns *zns);
+static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
+ enum dplane_op_e op);
/*
* Public APIs
@@ -296,27 +306,68 @@ static struct zebra_dplane_ctx *dplane_ctx_alloc(void)
*/
static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
{
- if (pctx) {
- DPLANE_CTX_VALID(*pctx);
+ if (pctx == NULL)
+ return;
- /* TODO -- just freeing memory, but would like to maintain
- * a pool
- */
+ DPLANE_CTX_VALID(*pctx);
+
+ /* TODO -- just freeing memory, but would like to maintain
+ * a pool
+ */
+
+ /* Some internal allocations may need to be freed, depending on
+ * the type of info captured in the ctx.
+ */
+ switch ((*pctx)->zd_op) {
+ case DPLANE_OP_ROUTE_INSTALL:
+ case DPLANE_OP_ROUTE_UPDATE:
+ case DPLANE_OP_ROUTE_DELETE:
- /* Free embedded nexthops */
+ /* Free allocated nexthops */
if ((*pctx)->u.rinfo.zd_ng.nexthop) {
/* This deals with recursive nexthops too */
nexthops_free((*pctx)->u.rinfo.zd_ng.nexthop);
+
+ (*pctx)->u.rinfo.zd_ng.nexthop = NULL;
}
if ((*pctx)->u.rinfo.zd_old_ng.nexthop) {
/* This deals with recursive nexthops too */
nexthops_free((*pctx)->u.rinfo.zd_old_ng.nexthop);
+
+ (*pctx)->u.rinfo.zd_old_ng.nexthop = NULL;
+ }
+
+ break;
+
+ case DPLANE_OP_LSP_INSTALL:
+ case DPLANE_OP_LSP_UPDATE:
+ case DPLANE_OP_LSP_DELETE:
+ {
+ zebra_nhlfe_t *nhlfe, *next;
+
+ /* Free allocated NHLFEs */
+ for (nhlfe = (*pctx)->u.lsp.nhlfe_list; nhlfe; nhlfe = next) {
+ next = nhlfe->next;
+
+ zebra_mpls_nhlfe_del(nhlfe);
}
- XFREE(MTYPE_DP_CTX, *pctx);
- *pctx = NULL;
+ /* Clear pointers in lsp struct, in case we're cacheing
+ * free context structs.
+ */
+ (*pctx)->u.lsp.nhlfe_list = NULL;
+ (*pctx)->u.lsp.best_nhlfe = NULL;
+
+ break;
+ }
+
+ case DPLANE_OP_NONE:
+ break;
}
+
+ XFREE(MTYPE_DP_CTX, *pctx);
+ *pctx = NULL;
}
/*
@@ -428,6 +479,16 @@ const char *dplane_op2str(enum dplane_op_e op)
ret = "ROUTE_DELETE";
break;
+ case DPLANE_OP_LSP_INSTALL:
+ ret = "LSP_INSTALL";
+ break;
+ case DPLANE_OP_LSP_UPDATE:
+ ret = "LSP_UPDATE";
+ break;
+ case DPLANE_OP_LSP_DELETE:
+ ret = "LSP_DELETE";
+ break;
+
};
return ret;
@@ -710,6 +771,28 @@ uint32_t dplane_get_in_queue_len(void)
}
/*
+ * Common dataplane context init with zebra namespace info.
+ */
+static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
+ struct zebra_ns *zns,
+ bool is_update)
+{
+ dplane_info_from_zns(&(ctx->zd_ns_info), zns);
+
+#if defined(HAVE_NETLINK)
+ /* Increment message counter after copying to context struct - may need
+ * two messages in some 'update' cases.
+ */
+ if (is_update)
+ zns->netlink_dplane.seq += 2;
+ else
+ zns->netlink_dplane.seq++;
+#endif /* HAVE_NETLINK */
+
+ return AOK;
+}
+
+/*
* Initialize a context block for a route update from zebra data structs.
*/
static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
@@ -766,18 +849,7 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
zvrf = vrf_info_lookup(re->vrf_id);
zns = zvrf->zns;
- /* Internal copy helper */
- dplane_info_from_zns(&(ctx->zd_ns_info), zns);
-
-#if defined(HAVE_NETLINK)
- /* Increment message counter after copying to context struct - may need
- * two messages in some 'update' cases.
- */
- if (op == DPLANE_OP_ROUTE_UPDATE)
- zns->netlink_dplane.seq += 2;
- else
- zns->netlink_dplane.seq++;
-#endif /* NETLINK*/
+ dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
/* Copy nexthops; recursive info is included too */
copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng.nexthop, NULL);
@@ -801,15 +873,79 @@ done:
}
/*
+ * Capture information for an LSP update in a dplane context.
+ */
+static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op,
+ zebra_lsp_t *lsp)
+{
+ int ret = AOK;
+ zebra_nhlfe_t *nhlfe, *new_nhlfe;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("init dplane ctx %s: in-label %u ecmp# %d",
+ dplane_op2str(op), lsp->ile.in_label,
+ lsp->num_ecmp);
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ /* Capture namespace info */
+ dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
+ (op == DPLANE_OP_LSP_UPDATE));
+
+ memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp));
+
+ ctx->u.lsp.ile = lsp->ile;
+ ctx->u.lsp.addr_family = lsp->addr_family;
+ ctx->u.lsp.num_ecmp = lsp->num_ecmp;
+ ctx->u.lsp.flags = lsp->flags;
+
+ /* Copy source LSP's nhlfes, and capture 'best' nhlfe */
+ for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
+ /* Not sure if this is meaningful... */
+ if (nhlfe->nexthop == NULL)
+ continue;
+
+ new_nhlfe =
+ zebra_mpls_lsp_add_nhlfe(
+ &(ctx->u.lsp),
+ nhlfe->type,
+ nhlfe->nexthop->type,
+ &(nhlfe->nexthop->gate),
+ nhlfe->nexthop->ifindex,
+ nhlfe->nexthop->nh_label->label[0]);
+
+ if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) {
+ ret = ENOMEM;
+ break;
+ }
+
+ /* Need to copy flags too */
+ new_nhlfe->flags = nhlfe->flags;
+ new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
+
+ if (nhlfe == lsp->best_nhlfe)
+ ctx->u.lsp.best_nhlfe = new_nhlfe;
+ }
+
+ /* On error the ctx will be cleaned-up, so we don't need to
+ * deal with any allocated nhlfe or nexthop structs here.
+ */
+
+ return ret;
+}
+
+/*
* Enqueue a new route update,
- * and ensure an event is active for the dataplane thread.
+ * and ensure an event is active for the dataplane pthread.
*/
static int dplane_route_enqueue(struct zebra_dplane_ctx *ctx)
{
int ret = EINVAL;
uint32_t high, curr;
- /* Enqueue for processing by the dataplane thread */
+ /* Enqueue for processing by the dataplane pthread */
DPLANE_LOCK();
{
TAILQ_INSERT_TAIL(&zdplane_info.dg_route_ctx_q, ctx,
@@ -905,10 +1041,11 @@ done:
if (ret == AOK)
result = ZEBRA_DPLANE_REQUEST_QUEUED;
- else if (ctx) {
+ else {
atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, 1,
memory_order_relaxed);
- dplane_ctx_free(&ctx);
+ if (ctx)
+ dplane_ctx_free(&ctx);
}
return result;
@@ -969,11 +1106,85 @@ done:
}
/*
+ * Enqueue LSP add for the dataplane.
+ */
+enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp)
+{
+ enum zebra_dplane_result ret =
+ lsp_update_internal(lsp, DPLANE_OP_LSP_INSTALL);
+
+ return ret;
+}
+
+/*
+ * Enqueue LSP update for the dataplane.
+ */
+enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp)
+{
+ enum zebra_dplane_result ret =
+ lsp_update_internal(lsp, DPLANE_OP_LSP_UPDATE);
+
+ return ret;
+}
+
+/*
+ * Enqueue LSP delete for the dataplane.
+ */
+enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp)
+{
+ enum zebra_dplane_result ret =
+ lsp_update_internal(lsp, DPLANE_OP_LSP_DELETE);
+
+ return ret;
+}
+
+/*
+ * Common internal LSP update utility
+ */
+static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
+ enum dplane_op_e op)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret = EINVAL;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ /* Obtain context block */
+ ctx = dplane_ctx_alloc();
+ if (ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = dplane_ctx_lsp_init(ctx, op, lsp);
+ if (ret != AOK)
+ goto done;
+
+ ret = dplane_route_enqueue(ctx);
+
+done:
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
+ memory_order_relaxed);
+ if (ctx)
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
+/*
* Handler for 'show dplane'
*/
int dplane_show_helper(struct vty *vty, bool detailed)
{
- uint64_t queued, queue_max, limit, errs, incoming, yields;
+ uint64_t queued, queue_max, limit, errs, incoming, yields,
+ other_errs;
/* Using atomics because counters are being changed in different
* pthread contexts.
@@ -990,14 +1201,17 @@ int dplane_show_helper(struct vty *vty, bool detailed)
memory_order_relaxed);
yields = atomic_load_explicit(&zdplane_info.dg_update_yields,
memory_order_relaxed);
+ other_errs = atomic_load_explicit(&zdplane_info.dg_other_errors,
+ memory_order_relaxed);
vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n",
incoming);
vty_out(vty, "Route update errors: %"PRIu64"\n", errs);
+ vty_out(vty, "Other errors : %"PRIu64"\n", other_errs);
vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit);
vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued);
vty_out(vty, "Route update queue max: %"PRIu64"\n", queue_max);
- vty_out(vty, "Route update yields: %"PRIu64"\n", yields);
+ vty_out(vty, "Dplane update yields: %"PRIu64"\n", yields);
return CMD_SUCCESS;
}
@@ -1277,6 +1491,55 @@ int dplane_provider_work_ready(void)
*/
/*
+ * Handler for kernel LSP updates
+ */
+static enum zebra_dplane_result
+kernel_dplane_lsp_update(struct zebra_dplane_ctx *ctx)
+{
+ enum zebra_dplane_result res;
+
+ /* Call into the synchronous kernel-facing code here */
+ res = kernel_lsp_update(ctx);
+
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(
+ &zdplane_info.dg_lsp_errors, 1,
+ memory_order_relaxed);
+
+ return res;
+}
+
+/*
+ * Handler for kernel route updates
+ */
+static enum zebra_dplane_result
+kernel_dplane_route_update(struct zebra_dplane_ctx *ctx)
+{
+ enum zebra_dplane_result res;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ char dest_str[PREFIX_STRLEN];
+
+ prefix2str(dplane_ctx_get_dest(ctx),
+ dest_str, sizeof(dest_str));
+
+ zlog_debug("%u:%s Dplane route update ctx %p op %s",
+ dplane_ctx_get_vrf(ctx), dest_str,
+ ctx, dplane_op2str(dplane_ctx_get_op(ctx)));
+ }
+
+ /* Call into the synchronous kernel-facing code here */
+ res = kernel_route_update(ctx);
+
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(
+ &zdplane_info.dg_route_errors, 1,
+ memory_order_relaxed);
+
+ return res;
+}
+
+/*
* Kernel provider callback
*/
static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
@@ -1297,25 +1560,30 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
if (ctx == NULL)
break;
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
- char dest_str[PREFIX_STRLEN];
+ /* Dispatch to appropriate kernel-facing apis */
+ switch (dplane_ctx_get_op(ctx)) {
- prefix2str(dplane_ctx_get_dest(ctx),
- dest_str, sizeof(dest_str));
-
- zlog_debug("%u:%s Dplane route update ctx %p op %s",
- dplane_ctx_get_vrf(ctx), dest_str,
- ctx, dplane_op2str(dplane_ctx_get_op(ctx)));
- }
+ case DPLANE_OP_ROUTE_INSTALL:
+ case DPLANE_OP_ROUTE_UPDATE:
+ case DPLANE_OP_ROUTE_DELETE:
+ res = kernel_dplane_route_update(ctx);
+ break;
- /* Call into the synchronous kernel-facing code here */
- res = kernel_route_update(ctx);
+ case DPLANE_OP_LSP_INSTALL:
+ case DPLANE_OP_LSP_UPDATE:
+ case DPLANE_OP_LSP_DELETE:
+ res = kernel_dplane_lsp_update(ctx);
+ break;
- if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ default:
atomic_fetch_add_explicit(
- &zdplane_info.dg_route_errors, 1,
+ &zdplane_info.dg_other_errors, 1,
memory_order_relaxed);
+ res = ZEBRA_DPLANE_REQUEST_FAILURE;
+ break;
+ }
+
dplane_ctx_set_status(ctx, res);
dplane_provider_enqueue_out_ctx(prov, ctx);
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 5486af727..562a8499a 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -102,6 +102,10 @@ enum dplane_op_e {
DPLANE_OP_ROUTE_UPDATE,
DPLANE_OP_ROUTE_DELETE,
+ /* LSP update */
+ DPLANE_OP_LSP_INSTALL,
+ DPLANE_OP_LSP_UPDATE,
+ DPLANE_OP_LSP_DELETE
};
/*
@@ -221,6 +225,13 @@ enum zebra_dplane_result dplane_route_update(struct route_node *rn,
enum zebra_dplane_result dplane_route_delete(struct route_node *rn,
struct route_entry *re);
+/*
+ * Enqueue LSP change operations for the dataplane.
+ */
+enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp);
+enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp);
+enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp);
+
/* Retrieve the limit on the number of pending, unprocessed updates. */
uint32_t dplane_get_in_queue_limit(void);
diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c
index c4ab316d0..2a21f8686 100644
--- a/zebra/zebra_mpls_netlink.c
+++ b/zebra/zebra_mpls_netlink.c
@@ -51,12 +51,8 @@ enum zebra_dplane_result kernel_add_lsp(zebra_lsp_t *lsp)
* Update Label Forwarding entry in the kernel. This means that the Label
* forwarding entry is already installed and needs an update - either a new
* path is to be added, an installed path has changed (e.g., outgoing label)
- * or an installed path (but not all paths) has to be removed.
- * TODO: Performs a DEL followed by ADD now, need to change to REPLACE. Note
- * that REPLACE was originally implemented for IPv4 nexthops but removed as
- * it was not functioning when moving from swap to PHP as that was signaled
- * through the metric field (before kernel-MPLS). This shouldn't be an issue
- * any longer, so REPLACE can be reintroduced.
+ * or an installed path (but not all paths) has to be removed. This performs
+ * a REPLACE operation, internally.
*/
enum zebra_dplane_result kernel_upd_lsp(zebra_lsp_t *lsp)
{
@@ -102,6 +98,11 @@ enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp)
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
+enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
+{
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
+}
+
int mpls_kernel_init(void)
{
struct stat st;
diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c
index 02ec506d8..eed0610b6 100644
--- a/zebra/zebra_mpls_null.c
+++ b/zebra/zebra_mpls_null.c
@@ -44,4 +44,9 @@ int mpls_kernel_init(void)
return -1;
};
+enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
+{
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
+}
+
#endif /* !defined(HAVE_NETLINK) && !defined(OPEN_BSD) */
diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c
index 60f944b84..2549ab947 100644
--- a/zebra/zebra_mpls_openbsd.c
+++ b/zebra/zebra_mpls_openbsd.c
@@ -343,6 +343,11 @@ enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp)
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
+enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
+{
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
+}
+
static int kmpw_install(struct zebra_pw *pw)
{
struct ifreq ifr;