summaryrefslogtreecommitdiff
path: root/zebra/zebra_dplane.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_dplane.c')
-rw-r--r--zebra/zebra_dplane.c280
1 files changed, 203 insertions, 77 deletions
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 459d2bc620..143354b166 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -32,6 +32,7 @@
#include "zebra/zebra_memory.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_vxlan_private.h"
#include "zebra/rt.h"
#include "zebra/debug.h"
@@ -113,10 +114,15 @@ struct dplane_route_info {
struct dplane_nexthop_info nhe;
/* Nexthops */
+ uint32_t zd_nhg_id;
struct nexthop_group zd_ng;
+ /* Backup nexthops (if present) */
+ struct nexthop_group backup_ng;
+
/* "Previous" nexthops, used only in route updates without netlink */
struct nexthop_group zd_old_ng;
+ struct nexthop_group old_backup_ng;
/* TODO -- use fixed array of nexthops, to avoid mallocs? */
@@ -173,7 +179,6 @@ struct dplane_mac_info {
struct ethaddr mac;
struct in_addr vtep_ip;
bool is_sticky;
-
};
/*
@@ -396,7 +401,7 @@ static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
static enum zebra_dplane_result intf_addr_update_internal(
const struct interface *ifp, const struct connected *ifc,
enum dplane_op_e op);
-static enum zebra_dplane_result mac_update_internal(
+static enum zebra_dplane_result mac_update_common(
enum dplane_op_e op, const struct interface *ifp,
const struct interface *br_ifp,
vlanid_t vid, const struct ethaddr *mac,
@@ -440,23 +445,15 @@ void dplane_enable_sys_route_notifs(void)
}
/*
- * Free a dataplane results context.
+ * Clean up dependent/internal allocations inside a context object
*/
-static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
+static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
{
- if (pctx == NULL)
- return;
-
- 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
+ /*
+ * Some internal allocations may need to be freed, depending on
* the type of info captured in the ctx.
*/
- switch ((*pctx)->zd_op) {
+ switch (ctx->zd_op) {
case DPLANE_OP_ROUTE_INSTALL:
case DPLANE_OP_ROUTE_UPDATE:
case DPLANE_OP_ROUTE_DELETE:
@@ -465,18 +462,33 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
case DPLANE_OP_ROUTE_NOTIFY:
/* Free allocated nexthops */
- if ((*pctx)->u.rinfo.zd_ng.nexthop) {
+ if (ctx->u.rinfo.zd_ng.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->u.rinfo.zd_ng.nexthop);
+ nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
- (*pctx)->u.rinfo.zd_ng.nexthop = NULL;
+ ctx->u.rinfo.zd_ng.nexthop = NULL;
}
- if ((*pctx)->u.rinfo.zd_old_ng.nexthop) {
+ /* Free backup info also (if present) */
+ if (ctx->u.rinfo.backup_ng.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->u.rinfo.zd_old_ng.nexthop);
+ nexthops_free(ctx->u.rinfo.backup_ng.nexthop);
- (*pctx)->u.rinfo.zd_old_ng.nexthop = NULL;
+ ctx->u.rinfo.backup_ng.nexthop = NULL;
+ }
+
+ if (ctx->u.rinfo.zd_old_ng.nexthop) {
+ /* This deals with recursive nexthops too */
+ nexthops_free(ctx->u.rinfo.zd_old_ng.nexthop);
+
+ ctx->u.rinfo.zd_old_ng.nexthop = NULL;
+ }
+
+ if (ctx->u.rinfo.old_backup_ng.nexthop) {
+ /* This deals with recursive nexthops too */
+ nexthops_free(ctx->u.rinfo.old_backup_ng.nexthop);
+
+ ctx->u.rinfo.old_backup_ng.nexthop = NULL;
}
break;
@@ -484,11 +496,11 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
case DPLANE_OP_NH_INSTALL:
case DPLANE_OP_NH_UPDATE:
case DPLANE_OP_NH_DELETE: {
- if ((*pctx)->u.rinfo.nhe.ng.nexthop) {
+ if (ctx->u.rinfo.nhe.ng.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->u.rinfo.nhe.ng.nexthop);
+ nexthops_free(ctx->u.rinfo.nhe.ng.nexthop);
- (*pctx)->u.rinfo.nhe.ng.nexthop = NULL;
+ ctx->u.rinfo.nhe.ng.nexthop = NULL;
}
break;
}
@@ -501,7 +513,7 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
zebra_nhlfe_t *nhlfe, *next;
/* Free allocated NHLFEs */
- for (nhlfe = (*pctx)->u.lsp.nhlfe_list; nhlfe; nhlfe = next) {
+ for (nhlfe = ctx->u.lsp.nhlfe_list; nhlfe; nhlfe = next) {
next = nhlfe->next;
zebra_mpls_nhlfe_del(nhlfe);
@@ -510,8 +522,8 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
/* 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;
+ ctx->u.lsp.nhlfe_list = NULL;
+ ctx->u.lsp.best_nhlfe = NULL;
break;
}
@@ -519,21 +531,21 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
case DPLANE_OP_PW_INSTALL:
case DPLANE_OP_PW_UNINSTALL:
/* Free allocated nexthops */
- if ((*pctx)->u.pw.nhg.nexthop) {
+ if (ctx->u.pw.nhg.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->u.pw.nhg.nexthop);
+ nexthops_free(ctx->u.pw.nhg.nexthop);
- (*pctx)->u.pw.nhg.nexthop = NULL;
+ ctx->u.pw.nhg.nexthop = NULL;
}
break;
case DPLANE_OP_ADDR_INSTALL:
case DPLANE_OP_ADDR_UNINSTALL:
/* Maybe free label string, if allocated */
- if ((*pctx)->u.intf.label != NULL &&
- (*pctx)->u.intf.label != (*pctx)->u.intf.label_buf) {
- free((*pctx)->u.intf.label);
- (*pctx)->u.intf.label = NULL;
+ if (ctx->u.intf.label != NULL &&
+ ctx->u.intf.label != ctx->u.intf.label_buf) {
+ free(ctx->u.intf.label);
+ ctx->u.intf.label = NULL;
}
break;
@@ -547,11 +559,41 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
case DPLANE_OP_NONE:
break;
}
+}
+
+/*
+ * Free a dataplane results context.
+ */
+static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
+{
+ if (pctx == NULL)
+ return;
+
+ 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.
+ */
+ dplane_ctx_free_internal(*pctx);
XFREE(MTYPE_DP_CTX, *pctx);
}
/*
+ * Reset an allocated context object for re-use. All internal allocations are
+ * freed and the context is memset.
+ */
+void dplane_ctx_reset(struct zebra_dplane_ctx *ctx)
+{
+ dplane_ctx_free_internal(ctx);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+/*
* Return a context block to the dplane module after processing
*/
void dplane_ctx_fini(struct zebra_dplane_ctx **pctx)
@@ -1038,6 +1080,12 @@ void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
nexthop_group_copy_nh_sorted(&(ctx->u.rinfo.zd_ng), nh);
}
+uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.zd_nhg_id;
+}
+
const struct nexthop_group *dplane_ctx_get_ng(
const struct zebra_dplane_ctx *ctx)
{
@@ -1046,14 +1094,30 @@ const struct nexthop_group *dplane_ctx_get_ng(
return &(ctx->u.rinfo.zd_ng);
}
-const struct nexthop_group *dplane_ctx_get_old_ng(
- const struct zebra_dplane_ctx *ctx)
+const struct nexthop_group *
+dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rinfo.backup_ng);
+}
+
+const struct nexthop_group *
+dplane_ctx_get_old_ng(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
return &(ctx->u.rinfo.zd_old_ng);
}
+const struct nexthop_group *
+dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rinfo.old_backup_ng);
+}
+
const struct zebra_dplane_info *dplane_ctx_get_ns(
const struct zebra_dplane_ctx *ctx)
{
@@ -1461,10 +1525,8 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
/*
* Initialize a context block for a route update from zebra data structs.
*/
-static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
- enum dplane_op_e op,
- struct route_node *rn,
- struct route_entry *re)
+int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ struct route_node *rn, struct route_entry *re)
{
int ret = EINVAL;
const struct route_table *table = NULL;
@@ -1473,6 +1535,7 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
struct zebra_ns *zns;
struct zebra_vrf *zvrf;
struct nexthop *nexthop;
+ zebra_l3vni_t *zl3vni;
if (!ctx || !rn || !re)
goto done;
@@ -1514,11 +1577,32 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
/* Copy nexthops; recursive info is included too */
copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop),
re->nhe->nhg.nexthop, NULL);
+ ctx->u.rinfo.zd_nhg_id = re->nhe->id;
- /* Ensure that the dplane nexthops' flags are clear. */
- for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop))
+ /* Copy backup nexthop info, if present */
+ if (re->nhe->backup_info && re->nhe->backup_info->nhe) {
+ copy_nexthops(&(ctx->u.rinfo.backup_ng.nexthop),
+ re->nhe->backup_info->nhe->nhg.nexthop, NULL);
+ }
+
+ /*
+ * Ensure that the dplane nexthops' flags are clear and copy
+ * encapsulation information.
+ */
+ for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) {
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ /* Check for available encapsulations. */
+ if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
+ continue;
+
+ zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
+ if (zl3vni && is_l3vni_oper_up(zl3vni)) {
+ nexthop->nh_encap_type = NET_VXLAN;
+ nexthop->nh_encap.vni = zl3vni->vni;
+ }
+ }
+
/* Don't need some info when capturing a system notification */
if (op == DPLANE_OP_SYS_ROUTE_ADD ||
op == DPLANE_OP_SYS_ROUTE_DELETE) {
@@ -1532,9 +1616,8 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
#ifdef HAVE_NETLINK
- if (re->nhe_id) {
- struct nhg_hash_entry *nhe =
- zebra_nhg_resolve(zebra_nhg_lookup_id(re->nhe_id));
+ {
+ struct nhg_hash_entry *nhe = zebra_nhg_resolve(re->nhe);
ctx->u.rinfo.nhe.id = nhe->id;
/*
@@ -1581,7 +1664,6 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx,
{
struct zebra_vrf *zvrf = NULL;
struct zebra_ns *zns = NULL;
-
int ret = EINVAL;
if (!ctx || !nhe)
@@ -1850,6 +1932,17 @@ dplane_route_update_internal(struct route_node *rn,
*/
copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
old_re->nhe->nhg.nexthop, NULL);
+
+ if (zebra_nhg_get_backup_nhg(old_re->nhe) != NULL) {
+ struct nexthop_group *nhg;
+ struct nexthop **nh;
+
+ nhg = zebra_nhg_get_backup_nhg(old_re->nhe);
+ nh = &(ctx->u.rinfo.old_backup_ng.nexthop);
+
+ if (nhg->nexthop)
+ copy_nexthops(nh, nhg->nexthop, NULL);
+ }
#endif /* !HAVE_NETLINK */
}
@@ -2412,8 +2505,8 @@ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp,
enum zebra_dplane_result result;
/* Use common helper api */
- result = mac_update_internal(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
- vid, mac, vtep_ip, sticky);
+ result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
+ vid, mac, vtep_ip, sticky);
return result;
}
@@ -2429,41 +2522,25 @@ enum zebra_dplane_result dplane_mac_del(const struct interface *ifp,
enum zebra_dplane_result result;
/* Use common helper api */
- result = mac_update_internal(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
- vid, mac, vtep_ip, false);
+ result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
+ vid, mac, vtep_ip, false);
return result;
}
/*
- * Common helper api for MAC address/vxlan updates
+ * Public api to init an empty context - either newly-allocated or
+ * reset/cleared - for a MAC update.
*/
-static enum zebra_dplane_result
-mac_update_internal(enum dplane_op_e op,
- const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky)
+void dplane_mac_init(struct zebra_dplane_ctx *ctx,
+ const struct interface *ifp,
+ const struct interface *br_ifp,
+ vlanid_t vid,
+ const struct ethaddr *mac,
+ struct in_addr vtep_ip,
+ bool sticky)
{
- enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
- int ret;
- struct zebra_dplane_ctx *ctx = NULL;
struct zebra_ns *zns;
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
- char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN];
-
- zlog_debug("init mac ctx %s: mac %s, ifp %s, vtep %s",
- dplane_op2str(op),
- prefix_mac2str(mac, buf1, sizeof(buf1)),
- ifp->name,
- inet_ntop(AF_INET, &vtep_ip, buf2, sizeof(buf2)));
- }
-
- ctx = dplane_ctx_alloc();
-
- ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
ctx->zd_vrf_id = ifp->vrf_id;
@@ -2481,6 +2558,39 @@ mac_update_internal(enum dplane_op_e op,
ctx->u.macinfo.mac = *mac;
ctx->u.macinfo.vid = vid;
ctx->u.macinfo.is_sticky = sticky;
+}
+
+/*
+ * Common helper api for MAC address/vxlan updates
+ */
+static enum zebra_dplane_result
+mac_update_common(enum dplane_op_e op,
+ const struct interface *ifp,
+ const struct interface *br_ifp,
+ vlanid_t vid,
+ const struct ethaddr *mac,
+ struct in_addr vtep_ip,
+ bool sticky)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN];
+
+ zlog_debug("init mac ctx %s: mac %s, ifp %s, vtep %s",
+ dplane_op2str(op),
+ prefix_mac2str(mac, buf1, sizeof(buf1)),
+ ifp->name,
+ inet_ntop(AF_INET, &vtep_ip, buf2, sizeof(buf2)));
+ }
+
+ ctx = dplane_ctx_alloc();
+ ctx->zd_op = op;
+
+ /* Common init for the ctx */
+ dplane_mac_init(ctx, ifp, br_ifp, vid, mac, vtep_ip, sticky);
/* Enqueue for processing on the dplane pthread */
ret = dplane_update_enqueue(ctx);
@@ -3447,12 +3557,20 @@ bool dplane_is_in_shutdown(void)
*/
void zebra_dplane_pre_finish(void)
{
+ struct zebra_dplane_provider *dp;
+
if (IS_ZEBRA_DEBUG_DPLANE)
zlog_debug("Zebra dataplane pre-fini called");
zdplane_info.dg_is_shutdown = true;
- /* TODO -- Notify provider(s) of pending shutdown */
+ /* Notify provider(s) of pending shutdown. */
+ TAILQ_FOREACH(dp, &zdplane_info.dg_providers_q, dp_prov_link) {
+ if (dp->dp_fini == NULL)
+ continue;
+
+ dp->dp_fini(dp, true);
+ }
}
/*
@@ -3753,6 +3871,8 @@ done:
*/
void zebra_dplane_shutdown(void)
{
+ struct zebra_dplane_provider *dp;
+
if (IS_ZEBRA_DEBUG_DPLANE)
zlog_debug("Zebra dataplane shutdown called");
@@ -3771,7 +3891,13 @@ void zebra_dplane_shutdown(void)
zdplane_info.dg_pthread = NULL;
zdplane_info.dg_master = NULL;
- /* TODO -- Notify provider(s) of final shutdown */
+ /* Notify provider(s) of final shutdown. */
+ TAILQ_FOREACH(dp, &zdplane_info.dg_providers_q, dp_prov_link) {
+ if (dp->dp_fini == NULL)
+ continue;
+
+ dp->dp_fini(dp, false);
+ }
/* TODO -- Clean-up provider objects */