mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 08:24:30 +00:00
zebra: wip: early version of dplane result handler
Early try at a result handler for async dplane route updates Signed-off-by: Mark Stapp <mjs@voltanet.io>
This commit is contained in:
parent
7cdb1a8445
commit
e5ac2adf17
@ -1868,6 +1868,252 @@ static void rib_process(struct route_node *rn)
|
||||
rib_gc_dest(rn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility to match route with dplane context data
|
||||
*/
|
||||
static bool rib_route_match_ctx(const struct route_entry *re,
|
||||
const dplane_ctx_h ctx, bool is_update)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (is_update) {
|
||||
/*
|
||||
* In 'update' case, we test info about the 'previous' or
|
||||
* 'old' route
|
||||
*/
|
||||
if ((re->type == dplane_ctx_get_old_type(ctx)) &&
|
||||
(re->instance == dplane_ctx_get_old_instance(ctx))) {
|
||||
result = true;
|
||||
|
||||
/* TODO -- we're using this extra test, but it's not
|
||||
* exactly clear why.
|
||||
*/
|
||||
if (re->type == ZEBRA_ROUTE_STATIC &&
|
||||
(re->distance != dplane_ctx_get_old_distance(ctx) ||
|
||||
re->tag != dplane_ctx_get_old_tag(ctx))) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Ordinary, single-route case using primary context info
|
||||
*/
|
||||
if ((dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE) &&
|
||||
CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
|
||||
/* Skip route that's been deleted */
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((re->type == dplane_ctx_get_type(ctx)) &&
|
||||
(re->instance == dplane_ctx_get_instance(ctx))) {
|
||||
result = true;
|
||||
|
||||
/* TODO -- we're using this extra test, but it's not
|
||||
* exactly clear why.
|
||||
*/
|
||||
if (re->type == ZEBRA_ROUTE_STATIC &&
|
||||
(re->distance != dplane_ctx_get_distance(ctx) ||
|
||||
re->tag != dplane_ctx_get_tag(ctx))) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO - WIP
|
||||
*/
|
||||
static void rib_process_after(dplane_ctx_h ctx)
|
||||
{
|
||||
struct route_table *table = NULL;
|
||||
struct route_node *rn = NULL;
|
||||
struct route_entry *re = NULL, *old_re = NULL, *rib;
|
||||
bool is_update = false;
|
||||
struct nexthop *nexthop;
|
||||
char dest_str[PREFIX_STRLEN];
|
||||
dplane_op_e op;
|
||||
enum zebra_dplane_result status;
|
||||
const struct prefix *dest_pfx, *src_pfx;
|
||||
|
||||
/* Locate rn and re(s) from ctx */
|
||||
|
||||
table = zebra_vrf_table_with_table_id(dplane_ctx_get_afi(ctx),
|
||||
dplane_ctx_get_safi(ctx),
|
||||
dplane_ctx_get_vrf(ctx),
|
||||
dplane_ctx_get_table(ctx));
|
||||
if (table == NULL) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE) {
|
||||
zlog_debug("Failed to process dplane results: no table "
|
||||
"for afi %d, safi %d, vrf %u",
|
||||
dplane_ctx_get_afi(ctx),
|
||||
dplane_ctx_get_safi(ctx),
|
||||
dplane_ctx_get_vrf(ctx));
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
dest_pfx = dplane_ctx_get_dest(ctx);
|
||||
|
||||
/* Note well: only capturing the prefix string if debug is enabled here;
|
||||
* unconditional log messages will have to generate the string.
|
||||
*/
|
||||
if (IS_ZEBRA_DEBUG_DPLANE) {
|
||||
prefix2str(dest_pfx, dest_str, sizeof(dest_str));
|
||||
}
|
||||
|
||||
src_pfx = dplane_ctx_get_src(ctx);
|
||||
rn = srcdest_rnode_get(table, dplane_ctx_get_dest(ctx),
|
||||
src_pfx ? (struct prefix_ipv6 * )src_pfx : NULL);
|
||||
if (rn == NULL) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE) {
|
||||
zlog_debug("Failed to process dplane results: no "
|
||||
"route for %u:%s",
|
||||
dplane_ctx_get_vrf(ctx), dest_str);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx);
|
||||
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
status = dplane_ctx_get_status(ctx);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
|
||||
zlog_debug("%u:%s Processing dplane ctx %p, op %s result %d",
|
||||
dplane_ctx_get_vrf(ctx), dest_str, ctx,
|
||||
dplane_op2str(op), status);
|
||||
}
|
||||
|
||||
if (op == DPLANE_OP_ROUTE_DELETE) {
|
||||
/*
|
||||
* In the delete case, the zebra core datastructs were
|
||||
* updated (or removed) at the time the delete was issued,
|
||||
* so we're just notifying the route owner.
|
||||
*/
|
||||
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
|
||||
zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED);
|
||||
} else {
|
||||
zsend_route_notify_owner_ctx(ctx,
|
||||
ZAPI_ROUTE_FAIL_INSTALL);
|
||||
|
||||
zlog_warn("%u:%s: Route Deletion failure",
|
||||
dplane_ctx_get_vrf(ctx),
|
||||
prefix2str(dest_pfx,
|
||||
dest_str, sizeof(dest_str)));
|
||||
}
|
||||
|
||||
/* Nothing more to do in delete case */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update is a bit of a special case, where we may have both old and new
|
||||
* routes to post-process.
|
||||
*/
|
||||
is_update = dplane_ctx_is_update(ctx);
|
||||
|
||||
/*
|
||||
* Take a pass through the routes, look for matches with the context
|
||||
* info.
|
||||
*/
|
||||
RNODE_FOREACH_RE(rn, rib) {
|
||||
|
||||
if (re == NULL) {
|
||||
if (rib_route_match_ctx(rib, ctx, false)) {
|
||||
re = rib;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for old route match */
|
||||
if (is_update && (old_re == NULL)) {
|
||||
if (rib_route_match_ctx(rib, ctx, true /*is_update*/)) {
|
||||
old_re = rib;
|
||||
}
|
||||
}
|
||||
|
||||
/* Have we found the routes we need to work on? */
|
||||
if (re && ((!is_update || old_re))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check sequence number(s) to detect stale results before continuing
|
||||
*/
|
||||
if (re && (re->dplane_sequence != dplane_ctx_get_seq(ctx))) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
|
||||
zlog_debug("%u:%s Stale dplane result for re %p",
|
||||
dplane_ctx_get_vrf(ctx), dest_str, re);
|
||||
}
|
||||
re = NULL;
|
||||
}
|
||||
|
||||
if (old_re &&
|
||||
(old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx))) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
|
||||
zlog_debug("%u:%s Stale dplane result for old_re %p",
|
||||
dplane_ctx_get_vrf(ctx), dest_str, old_re);
|
||||
}
|
||||
old_re = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here's sort of a tough one: the route update result is stale.
|
||||
* Is it better to use the context block info to generate
|
||||
* redist and owner notification, or is it better to wait
|
||||
* for the up-to-date result to arrive?
|
||||
*/
|
||||
if (re == NULL) {
|
||||
/* TODO -- for now, only expose up-to-date results */
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
|
||||
/* Set nexthop FIB flags */
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
continue;
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
else
|
||||
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
}
|
||||
|
||||
/* Redistribute */
|
||||
/* TODO -- still calling the redist api using the route_entries,
|
||||
* and there's a corner-case here: if there's no client
|
||||
* for the 'new' route, a redist deleting the 'old' route
|
||||
* will be sent. But if the 'old' context info was stale,
|
||||
* 'old_re' will be NULL here and that delete will not be sent.
|
||||
*/
|
||||
redistribute_update(dest_pfx, src_pfx, re, old_re);
|
||||
|
||||
/* Notify route owner */
|
||||
zsend_route_notify_owner(re,
|
||||
dest_pfx, ZAPI_ROUTE_INSTALLED);
|
||||
|
||||
} else {
|
||||
zsend_route_notify_owner(re, dest_pfx,
|
||||
ZAPI_ROUTE_FAIL_INSTALL);
|
||||
|
||||
zlog_warn("%u:%s: Route install failed",
|
||||
dplane_ctx_get_vrf(ctx),
|
||||
prefix2str(dest_pfx,
|
||||
dest_str, sizeof(dest_str)));
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
/* Return context to dataplane module */
|
||||
dplane_ctx_fini(&ctx);
|
||||
}
|
||||
|
||||
/* Take a list of route_node structs and return 1, if there was a record
|
||||
* picked from it and processed by rib_process(). Don't process more,
|
||||
* than one RN record; operate only in the specified sub-queue.
|
||||
@ -3029,7 +3275,7 @@ static int rib_process_dplane_results(struct thread *thread)
|
||||
pthread_mutex_unlock(&dplane_mutex);
|
||||
|
||||
if (ctx) {
|
||||
dplane_ctx_fini(&ctx);
|
||||
rib_process_after(ctx);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user