diff options
Diffstat (limited to 'zebra/zebra_dplane.c')
| -rw-r--r-- | zebra/zebra_dplane.c | 280 |
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 */ |
