zebra: add optional extra data about routes' interfaces

Add extra data about the interfaces used in route updates'
nexthops - some consumers of route updates may want additional
data, but dataplane plugins running in the dplane pthread
cannot safely access the normal zebra data structures. Capturing
this info is optional - a plugin must request it (via an api).

Signed-off-by: Mark Stapp <mjs@voltanet.io>
This commit is contained in:
Mark Stapp 2020-10-30 10:51:54 -04:00
parent 93ca501b61
commit 5917df094a
2 changed files with 126 additions and 2 deletions

View File

@ -40,12 +40,18 @@
/* Memory type for context blocks */
DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx")
DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf")
DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider")
#ifndef AOK
# define AOK 0
#endif
/* Control for collection of extra interface info with route updates; a plugin
* can enable the extra info via a dplane api.
*/
static bool dplane_collect_extra_intf_info;
/* Enable test dataplane provider */
/*#define DPLANE_TEST_PROVIDER 1 */
@ -84,6 +90,18 @@ struct dplane_nexthop_info {
uint8_t nh_grp_count;
};
/*
* Optional extra info about interfaces used in route updates' nexthops.
*/
struct dplane_intf_extra {
vrf_id_t vrf_id;
uint32_t ifindex;
uint32_t flags;
uint32_t status;
TAILQ_ENTRY(dplane_intf_extra) link;
};
/*
* Route information captured for route updates.
*/
@ -127,8 +145,8 @@ struct dplane_route_info {
struct nexthop_group zd_old_ng;
struct nexthop_group old_backup_ng;
/* TODO -- use fixed array of nexthops, to avoid mallocs? */
/* Optional list of extra interface info */
TAILQ_HEAD(dp_intf_extra_q, dplane_intf_extra) intf_extra_q;
};
/*
@ -507,6 +525,8 @@ void dplane_enable_sys_route_notifs(void)
*/
static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
{
struct dplane_intf_extra *if_extra, *if_tmp;
/*
* Some internal allocations may need to be freed, depending on
* the type of info captured in the ctx.
@ -549,6 +569,14 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
ctx->u.rinfo.old_backup_ng.nexthop = NULL;
}
/* Optional extra interface info */
TAILQ_FOREACH_SAFE(if_extra, &ctx->u.rinfo.intf_extra_q,
link, if_tmp) {
TAILQ_REMOVE(&ctx->u.rinfo.intf_extra_q, if_extra,
link);
XFREE(MTYPE_DP_INTF, if_extra);
}
break;
case DPLANE_OP_NH_INSTALL:
@ -1819,6 +1847,45 @@ dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx)
* End of dplane context accessors
*/
/* Optional extra info about interfaces in nexthops - a plugin must enable
* this extra info.
*/
const struct dplane_intf_extra *
dplane_ctx_get_intf_extra(const struct zebra_dplane_ctx *ctx)
{
return TAILQ_FIRST(&ctx->u.rinfo.intf_extra_q);
}
const struct dplane_intf_extra *
dplane_ctx_intf_extra_next(const struct zebra_dplane_ctx *ctx,
const struct dplane_intf_extra *ptr)
{
return TAILQ_NEXT(ptr, link);
}
vrf_id_t dplane_intf_extra_get_vrfid(const struct dplane_intf_extra *ptr)
{
return ptr->vrf_id;
}
uint32_t dplane_intf_extra_get_ifindex(const struct dplane_intf_extra *ptr)
{
return ptr->ifindex;
}
uint32_t dplane_intf_extra_get_flags(const struct dplane_intf_extra *ptr)
{
return ptr->flags;
}
uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr)
{
return ptr->status;
}
/*
* End of interface extra info accessors
*/
/*
* Retrieve the limit on the number of pending, unprocessed updates.
@ -1887,10 +1954,14 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
struct zebra_vrf *zvrf;
struct nexthop *nexthop;
zebra_l3vni_t *zl3vni;
const struct interface *ifp;
struct dplane_intf_extra *if_extra;
if (!ctx || !rn || !re)
goto done;
TAILQ_INIT(&ctx->u.rinfo.intf_extra_q);
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
@ -1952,6 +2023,27 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
nexthop->nh_encap_type = NET_VXLAN;
nexthop->nh_encap.vni = zl3vni->vni;
}
/* Optionally capture extra interface info while we're in the
* main zebra pthread - a plugin has to ask for this info.
*/
if (dplane_collect_extra_intf_info) {
ifp = if_lookup_by_index(nexthop->ifindex,
nexthop->vrf_id);
if (ifp) {
if_extra = XCALLOC(
MTYPE_DP_INTF,
sizeof(struct dplane_intf_extra));
if_extra->vrf_id = nexthop->vrf_id;
if_extra->ifindex = nexthop->ifindex;
if_extra->flags = ifp->flags;
if_extra->status = ifp->status;
TAILQ_INSERT_TAIL(&ctx->u.rinfo.intf_extra_q,
if_extra, link);
}
}
}
/* Don't need some info when capturing a system notification */
@ -4243,6 +4335,14 @@ bool dplane_is_in_shutdown(void)
return zdplane_info.dg_is_shutdown;
}
/*
* Enable collection of extra info about interfaces in route updates.
*/
void dplane_enable_intf_extra_info(void)
{
dplane_collect_extra_intf_info = true;
}
/*
* Early or pre-shutdown, de-init notification api. This runs pretty
* early during zebra shutdown, as a signal to stop new work and prepare

View File

@ -204,6 +204,9 @@ void dplane_enable_sys_route_notifs(void);
*/
TAILQ_HEAD(dplane_ctx_q, zebra_dplane_ctx);
/* Declare a type for (optional) extended interface info objects. */
TAILQ_HEAD(dplane_intf_extra_q, dplane_intf_extra);
/* Allocate a context object */
struct zebra_dplane_ctx *dplane_ctx_alloc(void);
@ -313,6 +316,21 @@ const struct nexthop_group *dplane_ctx_get_ng(
const struct nexthop_group *dplane_ctx_get_old_ng(
const struct zebra_dplane_ctx *ctx);
/* Optional extra info about interfaces in nexthops - a plugin must enable
* this extra info.
*/
const struct dplane_intf_extra *
dplane_ctx_get_intf_extra(const struct zebra_dplane_ctx *ctx);
const struct dplane_intf_extra *
dplane_ctx_intf_extra_next(const struct zebra_dplane_ctx *ctx,
const struct dplane_intf_extra *ptr);
vrf_id_t dplane_intf_extra_get_vrfid(const struct dplane_intf_extra *ptr);
uint32_t dplane_intf_extra_get_ifindex(const struct dplane_intf_extra *ptr);
uint32_t dplane_intf_extra_get_flags(const struct dplane_intf_extra *ptr);
uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr);
/* Backup nexthop information (list of nexthops) if present. */
const struct nexthop_group *
dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx);
@ -743,6 +761,12 @@ void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
/* Enqueue a context directly to zebra main. */
void dplane_provider_enqueue_to_zebra(struct zebra_dplane_ctx *ctx);
/* Enable collection of extra info about interfaces in route updates;
* this allows a provider/plugin to see some extra info in route update
* context objects.
*/
void dplane_enable_intf_extra_info(void);
/*
* Initialize the dataplane modules at zebra startup. This is currently called
* by the rib module. Zebra registers a results callback with the dataplane.