#include "lib/memory.h"
#include "lib/queue.h"
#include "lib/zebra.h"
+#include "zebra/zebra_router.h"
#include "zebra/zebra_memory.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/zebra_dplane.h"
#include "zebra/rt.h"
#include "zebra/debug.h"
#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;
uint32_t zd_mtu;
uint32_t zd_nexthop_mtu;
- /* Namespace info */
- struct zebra_dplane_info zd_ns_info;
-
/* Nexthops */
struct nexthop_group zd_ng;
/* TODO -- use fixed array of nexthops, to avoid mallocs? */
+};
+
+/*
+ * Pseudowire info for the dataplane
+ */
+struct dplane_pw_info {
+ char ifname[IF_NAMESIZE];
+ ifindex_t ifindex;
+ int type;
+ int af;
+ int status;
+ uint32_t flags;
+ union g_addr dest;
+ mpls_label_t local_label;
+ mpls_label_t remote_label;
+
+ /* Nexthops */
+ struct nexthop_group nhg;
+
+ union pw_protocol_fields fields;
+};
+
+/*
+ * 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;
+ struct dplane_pw_info pw;
+ } 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;
};
_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_lsp_errors;
+
+ _Atomic uint32_t dg_pws_in;
+ _Atomic uint32_t dg_pw_errors;
+
_Atomic uint32_t dg_update_yields;
/* Dataplane pthread */
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);
+static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
+ enum dplane_op_e op);
/*
* Public APIs
*/
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_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
+ /* Free allocated nexthops */
+ if ((*pctx)->u.pw.nhg.nexthop) {
+ /* This deals with recursive nexthops too */
+ nexthops_free((*pctx)->u.pw.nhg.nexthop);
+
+ (*pctx)->u.pw.nhg.nexthop = NULL;
+ }
+ break;
+
+ case DPLANE_OP_NONE:
+ break;
+ }
+
+ XFREE(MTYPE_DP_CTX, *pctx);
+ *pctx = NULL;
}
/*
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;
+
+ case DPLANE_OP_PW_INSTALL:
+ ret = "PW_INSTALL";
+ break;
+ case DPLANE_OP_PW_UNINSTALL:
+ ret = "PW_UNINSTALL";
+ break;
+
+ }
return ret;
}
case ZEBRA_DPLANE_REQUEST_SUCCESS:
ret = "SUCCESS";
break;
- };
+ }
return ret;
}
{
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" */
{
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);
}
}
{
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)
{
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(
{
DPLANE_CTX_VALID(ctx);
- return &(ctx->zd_ng);
+ return &(ctx->u.rinfo.zd_ng);
}
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(
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;
+}
+
+const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.lsp.nhlfe_list;
+}
+
+const zebra_nhlfe_t *
+dplane_ctx_get_best_nhlfe(const 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;
+}
+
+const char *dplane_ctx_get_pw_ifname(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.ifname;
+}
+
+mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.local_label;
+}
+
+mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.remote_label;
+}
+
+int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.type;
+}
+
+int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.af;
+}
+
+uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.flags;
+}
+
+int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.status;
+}
+
+const union g_addr *dplane_ctx_get_pw_dest(
+ const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.pw.dest);
+}
+
+const union pw_protocol_fields *dplane_ctx_get_pw_proto(
+ const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.pw.fields);
+}
+
+const struct nexthop_group *
+dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.pw.nhg);
+}
+
/*
* End of dplane context accessors
*/
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.
*/
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
* when a result is stale.
*/
- re->dplane_sequence++;
+ re->dplane_sequence = zebra_router_get_next_sequence();
ctx->zd_seq = re->dplane_sequence;
ret = AOK;
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;
+}
+
+/*
+ * Capture information for an LSP update in a dplane context.
+ */
+static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op,
+ struct zebra_pw *pw)
+{
+ struct prefix p;
+ afi_t afi;
+ struct route_table *table;
+ struct route_node *rn;
+ struct route_entry *re;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
+ dplane_op2str(op), pw->ifname, pw->local_label,
+ pw->remote_label);
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ /* Capture namespace info: no netlink support as of 12/18,
+ * but just in case...
+ */
+ dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
+
+ memset(&ctx->u.pw, 0, sizeof(ctx->u.pw));
+
+ /* This name appears to be c-string, so we use string copy. */
+ strlcpy(ctx->u.pw.ifname, pw->ifname, sizeof(ctx->u.pw.ifname));
+
+ ctx->zd_vrf_id = pw->vrf_id;
+ ctx->u.pw.ifindex = pw->ifindex;
+ ctx->u.pw.type = pw->type;
+ ctx->u.pw.af = pw->af;
+ ctx->u.pw.local_label = pw->local_label;
+ ctx->u.pw.remote_label = pw->remote_label;
+ ctx->u.pw.flags = pw->flags;
+
+ ctx->u.pw.dest = pw->nexthop;
+
+ ctx->u.pw.fields = pw->data;
+
+ /* Capture nexthop info for the pw destination. We need to look
+ * up and use zebra datastructs, but we're running in the zebra
+ * pthread here so that should be ok.
+ */
+ memcpy(&p.u, &pw->nexthop, sizeof(pw->nexthop));
+ p.family = pw->af;
+ p.prefixlen = ((pw->af == AF_INET) ?
+ IPV4_MAX_PREFIXLEN : IPV6_MAX_PREFIXLEN);
+
+ afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6;
+ table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id);
+ if (table) {
+ rn = route_node_match(table, &p);
+ if (rn) {
+ RNODE_FOREACH_RE(rn, re) {
+ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
+ break;
+ }
+
+ if (re)
+ copy_nexthops(&(ctx->u.pw.nhg.nexthop),
+ re->ng.nexthop, NULL);
+
+ route_unlock_node(rn);
+ }
+ }
+
+ return AOK;
+}
+
/*
* 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,
old_re && (old_re != re)) {
ctx->zd_is_update = true;
- old_re->dplane_sequence++;
+ old_re->dplane_sequence =
+ zebra_router_get_next_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 */
}
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;
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;
+}
+
+/*
+ * Enqueue pseudowire install for the dataplane.
+ */
+enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw)
+{
+ return pw_update_internal(pw, DPLANE_OP_PW_INSTALL);
+}
+
+/*
+ * Enqueue pseudowire un-install for the dataplane.
+ */
+enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw)
+{
+ return pw_update_internal(pw, DPLANE_OP_PW_UNINSTALL);
+}
+
+/*
+ * 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;
+}
+
+/*
+ * Internal, common handler for pseudowire updates.
+ */
+static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
+ enum dplane_op_e op)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ ctx = dplane_ctx_alloc();
+ if (ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = dplane_ctx_pw_init(ctx, op, pw);
+ if (ret != AOK)
+ goto done;
+
+ ret = dplane_route_enqueue(ctx);
+
+done:
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_pws_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_pw_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.
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;
}
/* Allocate and init new provider struct */
p = XCALLOC(MTYPE_DP_PROV, sizeof(struct zebra_dplane_provider));
- if (p == NULL) {
- ret = ENOMEM;
- goto done;
- }
pthread_mutex_init(&(p->dp_mutex), NULL);
TAILQ_INIT(&(p->dp_ctx_in_q));
* 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 pseudowire updates
+ */
+static enum zebra_dplane_result
+kernel_dplane_pw_update(struct zebra_dplane_ctx *ctx)
+{
+ enum zebra_dplane_result res;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u",
+ dplane_ctx_get_pw_ifname(ctx),
+ dplane_op2str(ctx->zd_op),
+ dplane_ctx_get_pw_af(ctx),
+ dplane_ctx_get_pw_local_label(ctx),
+ dplane_ctx_get_pw_remote_label(ctx));
+
+ res = kernel_pw_update(ctx);
+
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(
+ &zdplane_info.dg_pw_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
*/
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));
+ case DPLANE_OP_ROUTE_INSTALL:
+ case DPLANE_OP_ROUTE_UPDATE:
+ case DPLANE_OP_ROUTE_DELETE:
+ res = kernel_dplane_route_update(ctx);
+ break;
- 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_LSP_INSTALL:
+ case DPLANE_OP_LSP_UPDATE:
+ case DPLANE_OP_LSP_DELETE:
+ res = kernel_dplane_lsp_update(ctx);
+ break;
- /* Call into the synchronous kernel-facing code here */
- res = kernel_route_update(ctx);
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
+ res = kernel_dplane_pw_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);
/* We appear to be done - schedule a final callback event
* for the zebra main pthread.
*/
- thread_add_event(zebrad.master, zebra_finalize, NULL, 0, NULL);
+ thread_add_event(zrouter.master, zebra_finalize, NULL, 0, NULL);
}
return 0;
/*
* Initialize the dataplane module during startup, internal/private version
*/
-static void zebra_dplane_init_internal(struct zebra_t *zebra)
+static void zebra_dplane_init_internal(void)
{
memset(&zdplane_info, 0, sizeof(zdplane_info));
*/
void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_q *))
{
- zebra_dplane_init_internal(&zebrad);
+ zebra_dplane_init_internal();
zdplane_info.dg_results_cb = results_fp;
}