From 16c628de99517efe4c9f960ca7423bc86ac7d5c4 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Tue, 23 Oct 2018 10:57:01 -0400 Subject: [PATCH] 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 --- zebra/rt.h | 5 +- zebra/rt_netlink.c | 160 +++++++++++++++++ zebra/rt_netlink.h | 4 + zebra/zebra_dplane.c | 346 ++++++++++++++++++++++++++++++++----- zebra/zebra_dplane.h | 11 ++ zebra/zebra_mpls_netlink.c | 13 +- zebra/zebra_mpls_null.c | 5 + zebra/zebra_mpls_openbsd.c | 5 + 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; @@ -709,6 +770,28 @@ uint32_t dplane_get_in_queue_len(void) memory_order_seq_cst); } +/* + * 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. */ @@ -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); @@ -800,16 +872,80 @@ done: return ret; } +/* + * 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; @@ -968,12 +1105,86 @@ done: return ret; } +/* + * 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; } @@ -1276,6 +1490,55 @@ int dplane_provider_work_ready(void) * Kernel dataplane provider */ +/* + * 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 */ @@ -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; -- 2.39.2