summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
authorRafael Zalamena <rzalamena@users.noreply.github.com>2019-01-22 22:38:24 +0100
committerGitHub <noreply@github.com>2019-01-22 22:38:24 +0100
commited98b97622d1d3967f34d527ed3a09335eda5c96 (patch)
treed115d69574b129fc7e3081a0677363c04718c7f9 /zebra
parentMerge pull request #3559 from opensourcerouting/zapi-sanity-checks (diff)
parentzebra: openbsd LSP update code (diff)
downloadfrr-ed98b97622d1d3967f34d527ed3a09335eda5c96.tar.xz
frr-ed98b97622d1d3967f34d527ed3a09335eda5c96.zip
Merge pull request #3416 from mjstapp/dplane_mpls
Async dataplane: support mpls lsps
Diffstat (limited to 'zebra')
-rw-r--r--zebra/rt.h20
-rw-r--r--zebra/rt_netlink.c52
-rw-r--r--zebra/rt_netlink.h4
-rw-r--r--zebra/rt_socket.c13
-rw-r--r--zebra/zebra_dplane.c562
-rw-r--r--zebra/zebra_dplane.h23
-rw-r--r--zebra/zebra_mpls.c167
-rw-r--r--zebra/zebra_mpls.h19
-rw-r--r--zebra/zebra_mpls_netlink.c89
-rw-r--r--zebra/zebra_mpls_null.c20
-rw-r--r--zebra/zebra_mpls_openbsd.c87
-rw-r--r--zebra/zebra_rib.c32
-rw-r--r--zebra/zebra_vrf.h4
13 files changed, 742 insertions, 350 deletions
diff --git a/zebra/rt.h b/zebra/rt.h
index 0317dc85b..f2b531400 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 *);
@@ -47,21 +50,6 @@ extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
extern int kernel_interface_set_master(struct interface *master,
struct interface *slave);
-extern enum zebra_dplane_result kernel_add_lsp(zebra_lsp_t *lsp);
-extern enum zebra_dplane_result kernel_upd_lsp(zebra_lsp_t *lsp);
-extern enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp);
-
-/*
- * Add the ability to pass back up the lsp install/delete
- * success/failure.
- *
- * This functions goal is similiar to kernel_route_rib_pass_fail
- * in that we are separating out the mechanics for
- * the install/failure to set/unset flags and to notify
- * as needed.
- */
-extern void kernel_lsp_pass_fail(zebra_lsp_t *lsp, enum zebra_dplane_status res);
-
extern int mpls_kernel_init(void);
extern uint32_t kernel_get_speed(struct interface *ifp);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index ae4bc5272..45bc3b3ba 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -2616,16 +2616,16 @@ int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip)
}
/*
- * MPLS label forwarding table change via netlink interface.
+ * MPLS label forwarding table change via netlink interface, using dataplane
+ * context information.
*/
-int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
+int netlink_mpls_multipath(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;
- struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
int route_type;
struct {
@@ -2634,14 +2634,14 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
char buf[NL_PKT_BUF_SIZE];
} req;
- memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE);
+ 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 = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
+ for (nhlfe = dplane_ctx_get_nhlfe(ctx); nhlfe; nhlfe = nhlfe->next) {
nexthop = nhlfe->nexthop;
if (!nexthop)
continue;
@@ -2650,8 +2650,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
nexthop_num++;
- } else /* DEL */
- {
+ } else { /* DEL */
/* Count all installed NHLFEs */
if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
@@ -2659,13 +2658,14 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
}
}
- if ((nexthop_num == 0) || (!lsp->best_nhlfe && (cmd != RTM_DELROUTE)))
+ 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 = zns->netlink_cmd.snl.nl_pid;
+ 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;
@@ -2678,23 +2678,26 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
req.n.nlmsg_flags |= NLM_F_REPLACE;
/* set the protocol value if installing */
- route_type = re_type_from_lsp_type(lsp->best_nhlfe->type);
+ 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(lsp->ile.in_label, 0, 0, 1);
- addattr_l(&req.n, sizeof req, RTA_DST, &lse, sizeof(mpls_lse_t));
+ 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) {
routedesc = "single-path";
- _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc);
+ _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
+ routedesc);
nexthop_num = 0;
- for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
+ for (nhlfe = dplane_ctx_get_nhlfe(ctx);
+ nhlfe; nhlfe = nhlfe->next) {
nexthop = nhlfe->nexthop;
if (!nexthop)
continue;
@@ -2709,15 +2712,16 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
&& CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_FIB)))) {
/* Add the gateway */
- _netlink_mpls_build_singlepath(routedesc, nhlfe,
- &req.n, &req.r,
- sizeof req, cmd);
+ _netlink_mpls_build_singlepath(
+ routedesc, nhlfe,
+ &req.n, &req.r,
+ sizeof(req), cmd);
+
nexthop_num++;
break;
}
}
- } else /* Multipath case */
- {
+ } else { /* Multipath case */
char buf[NL_PKT_BUF_SIZE];
struct rtattr *rta = (void *)buf;
struct rtnexthop *rtnh;
@@ -2728,10 +2732,12 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
rtnh = RTA_DATA(rta);
routedesc = "multipath";
- _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc);
+ _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
+ routedesc);
nexthop_num = 0;
- for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
+ for (nhlfe = dplane_ctx_get_nhlfe(ctx);
+ nhlfe; nhlfe = nhlfe->next) {
nexthop = nhlfe->nexthop;
if (!nexthop)
continue;
@@ -2762,7 +2768,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
}
/* Talk to netlink socket. */
- return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
- 0);
+ 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..914a0b5d7 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
@@ -58,7 +59,8 @@
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(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/rt_socket.c b/zebra/rt_socket.c
index 7dc5ef8b6..abcff22b6 100644
--- a/zebra/rt_socket.c
+++ b/zebra/rt_socket.c
@@ -84,8 +84,7 @@ static int kernel_rtm(int cmd, const struct prefix *p,
char prefix_buf[PREFIX_STRLEN];
enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
- if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_KERNEL)
- prefix2str(p, prefix_buf, sizeof(prefix_buf));
+ prefix2str(p, prefix_buf, sizeof(prefix_buf));
/*
* We only have the ability to ADD or DELETE at this point
@@ -214,10 +213,12 @@ static int kernel_rtm(int cmd, const struct prefix *p,
}
#ifdef __OpenBSD__
- if (nexthop->nh_label
- && !kernel_rtm_add_labels(nexthop->nh_label, &smpls))
- continue;
- smplsp = (union sockunion *)&smpls;
+ if (nexthop->nh_label) {
+ if (kernel_rtm_add_labels(nexthop->nh_label,
+ &smpls) != 0)
+ continue;
+ smplsp = (union sockunion *)&smpls;
+ }
#endif
error = rtm_write(cmd, &sin_dest, &sin_mask,
gate ? &sin_gate : NULL, smplsp,
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index feede21cd..fc316dbcb 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -62,49 +62,25 @@ const uint32_t DPLANE_DEFAULT_NEW_WORK = 100;
#endif /* DPLANE_DEBUG */
/*
- * The context block used to exchange info about route updates across
- * the boundary between the zebra main context (and pthread) and the
- * dataplane layer (and pthread).
+ * Route information captured for route updates.
*/
-struct zebra_dplane_ctx {
-
- /* Operation code */
- enum dplane_op_e zd_op;
-
- /* Status on return */
- enum zebra_dplane_result zd_status;
-
- /* Dplane provider id */
- uint32_t zd_provider;
-
- /* Flags - used by providers, e.g. */
- int zd_flags;
-
- /* TODO -- internal/sub-operation status? */
- enum zebra_dplane_result zd_remote_status;
- enum zebra_dplane_result zd_kernel_status;
+struct dplane_route_info {
/* Dest and (optional) source prefixes */
struct prefix zd_dest;
struct prefix zd_src;
- bool zd_is_update;
-
- uint32_t zd_seq;
- uint32_t zd_old_seq;
- vrf_id_t zd_vrf_id;
- uint32_t zd_table_id;
+ afi_t zd_afi;
+ safi_t zd_safi;
int zd_type;
int zd_old_type;
- afi_t zd_afi;
- safi_t zd_safi;
-
route_tag_t zd_tag;
route_tag_t zd_old_tag;
uint32_t zd_metric;
uint32_t zd_old_metric;
+
uint16_t zd_instance;
uint16_t zd_old_instance;
@@ -114,9 +90,6 @@ struct zebra_dplane_ctx {
uint32_t zd_mtu;
uint32_t zd_nexthop_mtu;
- /* Namespace info */
- struct zebra_dplane_info zd_ns_info;
-
/* Nexthops */
struct nexthop_group zd_ng;
@@ -125,6 +98,48 @@ struct zebra_dplane_ctx {
/* TODO -- use fixed array of nexthops, to avoid mallocs? */
+};
+
+/*
+ * The context block used to exchange info about route updates across
+ * the boundary between the zebra main context (and pthread) and the
+ * dataplane layer (and pthread).
+ */
+struct zebra_dplane_ctx {
+
+ /* Operation code */
+ enum dplane_op_e zd_op;
+
+ /* Status on return */
+ enum zebra_dplane_result zd_status;
+
+ /* Dplane provider id */
+ uint32_t zd_provider;
+
+ /* Flags - used by providers, e.g. */
+ int zd_flags;
+
+ bool zd_is_update;
+
+ uint32_t zd_seq;
+ uint32_t zd_old_seq;
+
+ /* TODO -- internal/sub-operation status? */
+ enum zebra_dplane_result zd_remote_status;
+ enum zebra_dplane_result zd_kernel_status;
+
+ 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;
+ } u;
+
+ /* Namespace info, used especially for netlink kernel communication */
+ struct zebra_dplane_info zd_ns_info;
+
/* Embedded list linkage */
TAILQ_ENTRY(zebra_dplane_ctx) zd_q_entries;
};
@@ -218,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 */
@@ -251,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
@@ -282,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);
- /* Free embedded nexthops */
- if ((*pctx)->zd_ng.nexthop) {
+ /* 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 allocated nexthops */
+ if ((*pctx)->u.rinfo.zd_ng.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->zd_ng.nexthop);
+ nexthops_free((*pctx)->u.rinfo.zd_ng.nexthop);
+
+ (*pctx)->u.rinfo.zd_ng.nexthop = NULL;
}
- if ((*pctx)->zd_old_ng.nexthop) {
+ if ((*pctx)->u.rinfo.zd_old_ng.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->zd_old_ng.nexthop);
+ nexthops_free((*pctx)->u.rinfo.zd_old_ng.nexthop);
+
+ (*pctx)->u.rinfo.zd_old_ng.nexthop = NULL;
}
- XFREE(MTYPE_DP_CTX, *pctx);
- *pctx = 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);
+ }
+
+ /* 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;
}
/*
@@ -414,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;
@@ -442,7 +517,7 @@ const struct prefix *dplane_ctx_get_dest(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return &(ctx->zd_dest);
+ return &(ctx->u.rinfo.zd_dest);
}
/* Source prefix is a little special - return NULL for "no src prefix" */
@@ -450,11 +525,11 @@ const struct prefix *dplane_ctx_get_src(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- if (ctx->zd_src.prefixlen == 0 &&
- IN6_IS_ADDR_UNSPECIFIED(&(ctx->zd_src.u.prefix6))) {
+ if (ctx->u.rinfo.zd_src.prefixlen == 0 &&
+ IN6_IS_ADDR_UNSPECIFIED(&(ctx->u.rinfo.zd_src.u.prefix6))) {
return NULL;
} else {
- return &(ctx->zd_src);
+ return &(ctx->u.rinfo.zd_src);
}
}
@@ -490,28 +565,28 @@ int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_type;
+ return ctx->u.rinfo.zd_type;
}
int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_old_type;
+ return ctx->u.rinfo.zd_old_type;
}
afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_afi;
+ return ctx->u.rinfo.zd_afi;
}
safi_t dplane_ctx_get_safi(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_safi;
+ return ctx->u.rinfo.zd_safi;
}
uint32_t dplane_ctx_get_table(const struct zebra_dplane_ctx *ctx)
@@ -525,70 +600,70 @@ route_tag_t dplane_ctx_get_tag(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_tag;
+ return ctx->u.rinfo.zd_tag;
}
route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_old_tag;
+ return ctx->u.rinfo.zd_old_tag;
}
uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_instance;
+ return ctx->u.rinfo.zd_instance;
}
uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_old_instance;
+ return ctx->u.rinfo.zd_old_instance;
}
uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_metric;
+ return ctx->u.rinfo.zd_metric;
}
uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_old_metric;
+ return ctx->u.rinfo.zd_old_metric;
}
uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_mtu;
+ return ctx->u.rinfo.zd_mtu;
}
uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_nexthop_mtu;
+ return ctx->u.rinfo.zd_nexthop_mtu;
}
uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_distance;
+ return ctx->u.rinfo.zd_distance;
}
uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->zd_old_distance;
+ return ctx->u.rinfo.zd_old_distance;
}
const struct nexthop_group *dplane_ctx_get_ng(
@@ -596,7 +671,7 @@ const struct nexthop_group *dplane_ctx_get_ng(
{
DPLANE_CTX_VALID(ctx);
- return &(ctx->zd_ng);
+ return &(ctx->u.rinfo.zd_ng);
}
const struct nexthop_group *dplane_ctx_get_old_ng(
@@ -604,7 +679,7 @@ const struct nexthop_group *dplane_ctx_get_old_ng(
{
DPLANE_CTX_VALID(ctx);
- return &(ctx->zd_old_ng);
+ return &(ctx->u.rinfo.zd_old_ng);
}
const struct zebra_dplane_info *dplane_ctx_get_ns(
@@ -615,6 +690,50 @@ const struct zebra_dplane_info *dplane_ctx_get_ns(
return &(ctx->zd_ns_info);
}
+/* Accessors for LSP information */
+
+mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.lsp.ile.in_label;
+}
+
+uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.lsp.addr_family;
+}
+
+uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.lsp.flags;
+}
+
+zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.lsp.nhlfe_list;
+}
+
+zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.lsp.best_nhlfe;
+}
+
+uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.lsp.num_ecmp;
+}
+
/*
* End of dplane context accessors
*/
@@ -652,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,
@@ -673,61 +814,50 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
- ctx->zd_type = re->type;
- ctx->zd_old_type = re->type;
+ ctx->u.rinfo.zd_type = re->type;
+ ctx->u.rinfo.zd_old_type = re->type;
/* Prefixes: dest, and optional source */
srcdest_rnode_prefixes(rn, &p, &src_p);
- prefix_copy(&(ctx->zd_dest), p);
+ prefix_copy(&(ctx->u.rinfo.zd_dest), p);
if (src_p)
- prefix_copy(&(ctx->zd_src), src_p);
+ prefix_copy(&(ctx->u.rinfo.zd_src), src_p);
else
- memset(&(ctx->zd_src), 0, sizeof(ctx->zd_src));
+ memset(&(ctx->u.rinfo.zd_src), 0, sizeof(ctx->u.rinfo.zd_src));
ctx->zd_table_id = re->table;
- ctx->zd_metric = re->metric;
- ctx->zd_old_metric = re->metric;
+ ctx->u.rinfo.zd_metric = re->metric;
+ ctx->u.rinfo.zd_old_metric = re->metric;
ctx->zd_vrf_id = re->vrf_id;
- ctx->zd_mtu = re->mtu;
- ctx->zd_nexthop_mtu = re->nexthop_mtu;
- ctx->zd_instance = re->instance;
- ctx->zd_tag = re->tag;
- ctx->zd_old_tag = re->tag;
- ctx->zd_distance = re->distance;
+ ctx->u.rinfo.zd_mtu = re->mtu;
+ ctx->u.rinfo.zd_nexthop_mtu = re->nexthop_mtu;
+ ctx->u.rinfo.zd_instance = re->instance;
+ ctx->u.rinfo.zd_tag = re->tag;
+ ctx->u.rinfo.zd_old_tag = re->tag;
+ ctx->u.rinfo.zd_distance = re->distance;
table = srcdest_rnode_table(rn);
info = table->info;
- ctx->zd_afi = info->afi;
- ctx->zd_safi = info->safi;
+ ctx->u.rinfo.zd_afi = info->afi;
+ ctx->u.rinfo.zd_safi = info->safi;
/* Extract ns info - can't use pointers to 'core' structs */
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->zd_ng.nexthop), re->ng.nexthop, NULL);
+ copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng.nexthop, NULL);
/* TODO -- maybe use array of nexthops to avoid allocs? */
/* Ensure that the dplane's nexthops flags are clear. */
- for (ALL_NEXTHOPS(ctx->zd_ng, nexthop))
+ for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
/* Trying out the sequence number idea, so we can try to detect
@@ -743,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,
@@ -821,17 +1015,17 @@ dplane_route_update_internal(struct route_node *rn,
old_re->dplane_sequence++;
ctx->zd_old_seq = old_re->dplane_sequence;
- ctx->zd_old_tag = old_re->tag;
- ctx->zd_old_type = old_re->type;
- ctx->zd_old_instance = old_re->instance;
- ctx->zd_old_distance = old_re->distance;
- ctx->zd_old_metric = old_re->metric;
+ ctx->u.rinfo.zd_old_tag = old_re->tag;
+ ctx->u.rinfo.zd_old_type = old_re->type;
+ ctx->u.rinfo.zd_old_instance = old_re->instance;
+ ctx->u.rinfo.zd_old_distance = old_re->distance;
+ ctx->u.rinfo.zd_old_metric = old_re->metric;
#ifndef HAVE_NETLINK
/* For bsd, capture previous re's nexthops too, sigh.
* We'll need these to do per-nexthop deletes.
*/
- copy_nexthops(&(ctx->zd_old_ng.nexthop),
+ copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
old_re->ng.nexthop, NULL);
#endif /* !HAVE_NETLINK */
}
@@ -847,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;
@@ -911,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.
@@ -932,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;
}
@@ -1219,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)
@@ -1239,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];
-
- prefix2str(dplane_ctx_get_dest(ctx),
- dest_str, sizeof(dest_str));
+ /* Dispatch to appropriate kernel-facing apis */
+ switch (dplane_ctx_get_op(ctx)) {
- 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 1c053b85b..562a8499a 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -28,6 +28,7 @@
#include "zebra/zebra_ns.h"
#include "zebra/rib.h"
#include "zebra/zserv.h"
+#include "zebra/zebra_mpls.h"
/* Key netlink info from zebra ns */
struct zebra_dplane_info {
@@ -101,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
};
/*
@@ -167,6 +172,8 @@ bool dplane_ctx_is_update(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_get_seq(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx);
vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx);
+
+/* Accessors for route update information */
int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx);
int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx);
afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx);
@@ -188,6 +195,15 @@ const struct nexthop_group *dplane_ctx_get_ng(
const struct nexthop_group *dplane_ctx_get_old_ng(
const struct zebra_dplane_ctx *ctx);
+/* Accessors for LSP information */
+mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx);
+uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx);
+zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx);
+zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx);
+
+/* Namespace info - esp. for netlink communication */
const struct zebra_dplane_info *dplane_ctx_get_ns(
const struct zebra_dplane_ctx *ctx);
@@ -209,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.c b/zebra/zebra_mpls.c
index c0764cd4b..4ea7f3244 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -862,7 +862,7 @@ static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt)
lsp = (zebra_lsp_t *)backet->data;
if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
- (void)kernel_del_lsp(lsp);
+ (void)dplane_lsp_delete(lsp);
}
/*
@@ -887,6 +887,7 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
zebra_nhlfe_t *oldbest, *newbest;
char buf[BUFSIZ], buf2[BUFSIZ];
struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
+ enum zebra_dplane_result res;
lsp = (zebra_lsp_t *)data;
if (!lsp) // unexpected
@@ -916,13 +917,20 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
if (newbest) {
UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
- switch (kernel_add_lsp(lsp)) {
+
+ switch (dplane_lsp_add(lsp)) {
case ZEBRA_DPLANE_REQUEST_QUEUED:
- flog_err(
- EC_ZEBRA_DP_INVALID_RC,
- "No current DataPlane interfaces can return this, please fix");
+ /* Set 'installed' flag so we will know
+ * that an install is in-flight.
+ */
+ SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
+
+ zvrf->lsp_installs_queued++;
break;
case ZEBRA_DPLANE_REQUEST_FAILURE:
+ flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
+ "LSP Install Failure: %u",
+ lsp->ile.in_label);
break;
case ZEBRA_DPLANE_REQUEST_SUCCESS:
zvrf->lsp_installs++;
@@ -932,14 +940,22 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
} else {
/* Installed, may need an update and/or delete. */
if (!newbest) {
+ res = dplane_lsp_delete(lsp);
- switch (kernel_del_lsp(lsp)) {
+ /* We do some of the lsp cleanup immediately for
+ * deletes.
+ */
+ UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
+ clear_nhlfe_installed(lsp);
+
+ switch (res) {
case ZEBRA_DPLANE_REQUEST_QUEUED:
- flog_err(
- EC_ZEBRA_DP_INVALID_RC,
- "No current DataPlane interfaces can return this, please fix");
+ zvrf->lsp_removals_queued++;
break;
case ZEBRA_DPLANE_REQUEST_FAILURE:
+ flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
+ "LSP Deletion Failure: %u",
+ lsp->ile.in_label);
break;
case ZEBRA_DPLANE_REQUEST_SUCCESS:
zvrf->lsp_removals++;
@@ -950,7 +966,10 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
struct nexthop *nexthop;
UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
- UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
+
+ /* We leave the INSTALLED flag set here
+ * so we know an update in in-flight.
+ */
/*
* Any NHLFE that was installed but is not
@@ -973,13 +992,14 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
}
}
- switch (kernel_upd_lsp(lsp)) {
+ switch (dplane_lsp_update(lsp)) {
case ZEBRA_DPLANE_REQUEST_QUEUED:
- flog_err(
- EC_ZEBRA_DP_INVALID_RC,
- "No current DataPlane interfaces can return this, please fix");
+ zvrf->lsp_installs_queued++;
break;
case ZEBRA_DPLANE_REQUEST_FAILURE:
+ flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
+ "LSP Update Failure: %u",
+ lsp->ile.in_label);
break;
case ZEBRA_DPLANE_REQUEST_SUCCESS:
zvrf->lsp_installs++;
@@ -1716,43 +1736,85 @@ static int mpls_processq_init(struct zebra_t *zebra)
/* Public functions */
-void kernel_lsp_pass_fail(zebra_lsp_t *lsp, enum zebra_dplane_status res)
+/*
+ * Process LSP update results from zebra dataplane.
+ */
+void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
{
- struct nexthop *nexthop;
+ struct zebra_vrf *zvrf;
+ zebra_ile_t tmp_ile;
+ struct hash *lsp_table;
+ zebra_lsp_t *lsp;
zebra_nhlfe_t *nhlfe;
+ struct nexthop *nexthop;
+ enum dplane_op_e op;
+ enum zebra_dplane_status status;
+
+ op = dplane_ctx_get_op(ctx);
+ status = dplane_ctx_get_status(ctx);
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
+ ctx, dplane_op2str(op),
+ dplane_ctx_get_in_label(ctx),
+ dplane_res2str(status));
+
+ switch (op) {
+ case DPLANE_OP_LSP_INSTALL:
+ case DPLANE_OP_LSP_UPDATE:
+ /* Look for zebra LSP object */
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (zvrf == NULL)
+ break;
- if (!lsp)
- return;
+ lsp_table = zvrf->lsp_table;
- switch (res) {
- case ZEBRA_DPLANE_INSTALL_FAILURE:
- UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
- clear_nhlfe_installed(lsp);
- flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
- "LSP Install Failure: %u", lsp->ile.in_label);
- break;
- case ZEBRA_DPLANE_INSTALL_SUCCESS:
- SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
- for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
- nexthop = nhlfe->nexthop;
- if (!nexthop)
- continue;
+ tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
+ lsp = hash_lookup(lsp_table, &tmp_ile);
+ if (lsp == NULL) {
+ if (IS_ZEBRA_DEBUG_DPLANE)
+ zlog_debug("LSP ctx %p: in-label %u not found",
+ ctx, dplane_ctx_get_in_label(ctx));
+ break;
+ }
- SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ /* TODO -- Confirm that this result is still 'current' */
+
+ if (dplane_ctx_get_status(ctx) ==
+ ZEBRA_DPLANE_REQUEST_SUCCESS) {
+ /* Update zebra object */
+ SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
+ for (nhlfe = lsp->nhlfe_list; nhlfe;
+ nhlfe = nhlfe->next) {
+ nexthop = nhlfe->nexthop;
+ if (!nexthop)
+ continue;
+
+ SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+ } else {
+ UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
+ clear_nhlfe_installed(lsp);
+ flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
+ "LSP Install Failure: in-label %u",
+ lsp->ile.in_label);
}
+
break;
- case ZEBRA_DPLANE_DELETE_SUCCESS:
- UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
- clear_nhlfe_installed(lsp);
- break;
- case ZEBRA_DPLANE_DELETE_FAILURE:
+
+ case DPLANE_OP_LSP_DELETE:
flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
- "LSP Deletion Failure: %u", lsp->ile.in_label);
+ "LSP Deletion Failure: in-label %u",
+ dplane_ctx_get_in_label(ctx));
break;
- case ZEBRA_DPLANE_STATUS_NONE:
+
+ default:
break;
- }
+
+ } /* Switch */
+
+ dplane_ctx_fini(&ctx);
}
/*
@@ -1808,6 +1870,29 @@ int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
}
/*
+ * Add an NHLFE to an LSP, return the newly-added object
+ */
+zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
+ enum lsp_types_t lsp_type,
+ enum nexthop_types_t gtype,
+ union g_addr *gate,
+ ifindex_t ifindex,
+ mpls_label_t out_label)
+{
+ /* Just a public pass-through to the internal implementation */
+ return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, out_label);
+}
+
+/*
+ * Free an allocated NHLFE
+ */
+void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe)
+{
+ /* Just a pass-through to the internal implementation */
+ nhlfe_del(nhlfe);
+}
+
+/*
* Registration from a client for the label binding for a FEC. If a binding
* already exists, it is informed to the client.
* NOTE: If there is a manually configured label binding, that is used.
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index c250fc405..fb32adde3 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -191,6 +191,17 @@ int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *re);
+/* Add an NHLFE to an LSP, return the newly-added object */
+zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
+ enum lsp_types_t lsp_type,
+ enum nexthop_types_t gtype,
+ union g_addr *gate,
+ ifindex_t ifindex,
+ mpls_label_t out_label);
+
+/* Free an allocated NHLFE */
+void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe);
+
int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
uint32_t label, uint32_t label_index,
struct zserv *client);
@@ -331,6 +342,14 @@ int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
ifindex_t ifindex);
/*
+ * Process LSP update results from zebra dataplane.
+ */
+/* Forward ref of dplane update context type */
+struct zebra_dplane_ctx;
+
+void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx);
+
+/*
* Schedule all MPLS label forwarding entries for processing.
* Called upon changes that may affect one or more of them such as
* interface or nexthop state changes.
diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c
index c4ab316d0..d8b5ef4ce 100644
--- a/zebra/zebra_mpls_netlink.c
+++ b/zebra/zebra_mpls_netlink.c
@@ -22,84 +22,43 @@
#ifdef HAVE_NETLINK
+#include "zebra/debug.h"
#include "zebra/rt.h"
#include "zebra/rt_netlink.h"
#include "zebra/zebra_mpls.h"
/*
- * Install Label Forwarding entry into the kernel.
+ * LSP forwarding update using dataplane context information.
*/
-enum zebra_dplane_result kernel_add_lsp(zebra_lsp_t *lsp)
+enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
{
- int ret;
+ int cmd, ret = -1;
- if (!lsp || !lsp->best_nhlfe) { // unexpected
- kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_INSTALL_FAILURE);
- return ZEBRA_DPLANE_REQUEST_FAILURE;
- }
+ /* Call to netlink layer based on type of update */
+ if (dplane_ctx_get_op(ctx) == DPLANE_OP_LSP_DELETE) {
+ cmd = RTM_DELROUTE;
+ } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_LSP_INSTALL ||
+ dplane_ctx_get_op(ctx) == DPLANE_OP_LSP_UPDATE) {
- ret = netlink_mpls_multipath(RTM_NEWROUTE, lsp);
+ /* Validate */
+ if (dplane_ctx_get_best_nhlfe(ctx) == NULL) {
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug("LSP in-label %u: update fails, no best NHLFE",
+ dplane_ctx_get_in_label(ctx));
+ goto done;
+ }
- kernel_lsp_pass_fail(lsp,
- (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS
- : ZEBRA_DPLANE_INSTALL_FAILURE);
+ cmd = RTM_NEWROUTE;
+ } else
+ /* Invalid op? */
+ goto done;
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
-}
-
-/*
- * 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.
- */
-enum zebra_dplane_result kernel_upd_lsp(zebra_lsp_t *lsp)
-{
- int ret;
-
- if (!lsp || !lsp->best_nhlfe) { // unexpected
- kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_INSTALL_FAILURE);
- return ZEBRA_DPLANE_REQUEST_FAILURE;
- }
-
- ret = netlink_mpls_multipath(RTM_NEWROUTE, lsp);
-
- kernel_lsp_pass_fail(lsp,
- (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS
- : ZEBRA_DPLANE_INSTALL_FAILURE);
-
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
-}
-
-/*
- * Delete Label Forwarding entry from the kernel.
- */
-enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp)
-{
- int ret;
-
- if (!lsp) { // unexpected
- kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_DELETE_FAILURE);
- return ZEBRA_DPLANE_REQUEST_FAILURE;
- }
-
- if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
- kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_DELETE_FAILURE);
- return ZEBRA_DPLANE_REQUEST_FAILURE;
- }
-
- ret = netlink_mpls_multipath(RTM_DELROUTE, lsp);
+ ret = netlink_mpls_multipath(cmd, ctx);
- kernel_lsp_pass_fail(lsp,
- (!ret) ? ZEBRA_DPLANE_DELETE_SUCCESS
- : ZEBRA_DPLANE_DELETE_FAILURE);
+done:
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
+ return (ret == 0 ?
+ ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
}
int mpls_kernel_init(void)
diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c
index 02ec506d8..409432c4f 100644
--- a/zebra/zebra_mpls_null.c
+++ b/zebra/zebra_mpls_null.c
@@ -24,24 +24,14 @@
#if !defined(HAVE_NETLINK) && !defined(OPEN_BSD)
-enum zebra_dplane_result kernel_add_lsp(zebra_lsp_t *lsp)
-{
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
-}
-
-enum zebra_dplane_result kernel_upd_lsp(zebra_lsp_t *lsp)
-{
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
-}
-
-enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp)
-{
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
-}
-
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..da76c6ebf 100644
--- a/zebra/zebra_mpls_openbsd.c
+++ b/zebra/zebra_mpls_openbsd.c
@@ -236,13 +236,28 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label,
return ret;
}
-static int kernel_lsp_cmd(int action, zebra_lsp_t *lsp)
+static int kernel_lsp_cmd(struct zebra_dplane_ctx *ctx)
{
zebra_nhlfe_t *nhlfe;
struct nexthop *nexthop = NULL;
unsigned int nexthop_num = 0;
+ int action;
- for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
+ switch (dplane_ctx_get_op(ctx)) {
+ case DPLANE_OP_LSP_DELETE:
+ action = RTM_DELETE;
+ break;
+ case DPLANE_OP_LSP_INSTALL:
+ action = RTM_ADD;
+ break;
+ case DPLANE_OP_LSP_UPDATE:
+ action = RTM_CHANGE;
+ break;
+ default:
+ return -1;
+ }
+
+ for (nhlfe = dplane_ctx_get_nhlfe(ctx); nhlfe; nhlfe = nhlfe->next) {
nexthop = nhlfe->nexthop;
if (!nexthop)
continue;
@@ -269,12 +284,16 @@ static int kernel_lsp_cmd(int action, zebra_lsp_t *lsp)
switch (NHLFE_FAMILY(nhlfe)) {
case AF_INET:
- kernel_send_rtmsg_v4(action, lsp->ile.in_label,
- nhlfe);
+ kernel_send_rtmsg_v4(
+ action,
+ dplane_ctx_get_in_label(ctx),
+ nhlfe);
break;
case AF_INET6:
- kernel_send_rtmsg_v6(action, lsp->ile.in_label,
- nhlfe);
+ kernel_send_rtmsg_v6(
+ action,
+ dplane_ctx_get_in_label(ctx),
+ nhlfe);
break;
default:
break;
@@ -285,62 +304,14 @@ static int kernel_lsp_cmd(int action, zebra_lsp_t *lsp)
return (0);
}
-enum zebra_dplane_result kernel_add_lsp(zebra_lsp_t *lsp)
+enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
{
int ret;
- if (!lsp || !lsp->best_nhlfe) { // unexpected
- kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_INSTALL_FAILURE);
- return ZEBRA_DPLANE_REQUEST_FAILURE;
- }
-
- ret = kernel_lsp_cmd(RTM_ADD, lsp);
-
- kernel_lsp_pass_fail(lsp,
- (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS
- : ZEBRA_DPLANE_INSTALL_FAILURE);
-
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
-}
-
-enum zebra_dplane_result kernel_upd_lsp(zebra_lsp_t *lsp)
-{
- int ret;
-
- if (!lsp || !lsp->best_nhlfe) { // unexpected
- kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_INSTALL_FAILURE);
- return ZEBRA_DPLANE_REQUEST_FAILURE;
- }
-
- ret = kernel_lsp_cmd(RTM_CHANGE, lsp);
-
- kernel_lsp_pass_fail(lsp,
- (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS
- : ZEBRA_DPLANE_INSTALL_FAILURE);
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
-}
-
-enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp)
-{
- int ret;
-
- if (!lsp) { // unexpected
- kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_DELETE_FAILURE);
- return ZEBRA_DPLANE_REQUEST_FAILURE;
- }
-
- if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
- kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_DELETE_FAILURE);
- return ZEBRA_DPLANE_REQUEST_FAILURE;
- }
-
- ret = kernel_lsp_cmd(RTM_DELETE, lsp);
-
- kernel_lsp_pass_fail(lsp,
- (!ret) ? ZEBRA_DPLANE_DELETE_SUCCESS
- : ZEBRA_DPLANE_DELETE_FAILURE);
+ ret = kernel_lsp_cmd(ctx);
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
+ return (ret == 0 ?
+ ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
}
static int kmpw_install(struct zebra_pw *pw)
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 7e4ac1ddd..34bf513bf 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1811,7 +1811,7 @@ done:
/*
* Route-update results processing after async dataplane update.
*/
-static void rib_process_after(struct zebra_dplane_ctx *ctx)
+static void rib_process_result(struct zebra_dplane_ctx *ctx)
{
struct route_table *table = NULL;
struct zebra_vrf *zvrf = NULL;
@@ -1931,8 +1931,6 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx)
}
switch (op) {
- case DPLANE_OP_NONE:
- break;
case DPLANE_OP_ROUTE_INSTALL:
case DPLANE_OP_ROUTE_UPDATE:
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
@@ -2015,6 +2013,8 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx)
dest_str, sizeof(dest_str)));
}
break;
+ default:
+ break;
}
done:
@@ -3191,7 +3191,8 @@ void rib_close_table(struct route_table *table)
}
/*
- *
+ * Handle results from the dataplane system. Dequeue update context
+ * structs, dispatch to appropriate internal handlers.
*/
static int rib_process_dplane_results(struct thread *thread)
{
@@ -3200,13 +3201,15 @@ static int rib_process_dplane_results(struct thread *thread)
/* Dequeue a list of completed updates with one lock/unlock cycle */
+ /* TODO -- dequeue a list with one lock/unlock cycle? */
+
do {
TAILQ_INIT(&ctxlist);
/* Take lock controlling queue of results */
pthread_mutex_lock(&dplane_mutex);
{
- /* Dequeue context block */
+ /* Dequeue list of context structs */
dplane_ctx_list_append(&ctxlist, &rib_dplane_q);
}
pthread_mutex_unlock(&dplane_mutex);
@@ -3219,7 +3222,24 @@ static int rib_process_dplane_results(struct thread *thread)
break;
while (ctx) {
- rib_process_after(ctx);
+ switch (dplane_ctx_get_op(ctx)) {
+ case DPLANE_OP_ROUTE_INSTALL:
+ case DPLANE_OP_ROUTE_UPDATE:
+ case DPLANE_OP_ROUTE_DELETE:
+ rib_process_result(ctx);
+ break;
+
+ case DPLANE_OP_LSP_INSTALL:
+ case DPLANE_OP_LSP_UPDATE:
+ case DPLANE_OP_LSP_DELETE:
+ zebra_mpls_lsp_dplane_result(ctx);
+ break;
+
+ default:
+ /* Don't expect this: just return the struct? */
+ dplane_ctx_fini(&ctx);
+ break;
+ } /* Dispatch by op code */
ctx = dplane_ctx_dequeue(&ctxlist);
}
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index c28025403..2473299d1 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -137,12 +137,14 @@ struct zebra_vrf {
*/
enum vxlan_flood_control vxlan_flood_ctrl;
- /* Route Installs */
+ /* Install stats */
uint64_t installs;
uint64_t removals;
uint64_t installs_queued;
uint64_t removals_queued;
uint64_t neigh_updates;
+ uint64_t lsp_installs_queued;
+ uint64_t lsp_removals_queued;
uint64_t lsp_installs;
uint64_t lsp_removals;
};