zebra: include backup nexthops in nexthop-tracking

Include backup nexthops when examining routes that resolve
NHT requests. Include installed backups when sending nexthops
in zapi messages to client daemons.

Signed-off-by: Mark Stapp <mjs@voltanet.io>
This commit is contained in:
Mark Stapp 2020-05-27 12:53:20 -04:00
parent 9959f1daba
commit cadd02e166

View file

@ -458,12 +458,12 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
char buf[PREFIX_STRLEN];
char buf1[PREFIX_STRLEN];
char buf1[SRCDEST2STR_BUFFER];
zlog_debug("%s: %u:%s Resolved Import Entry to %s", __func__,
rnh->vrf_id,
prefix2str(&rnh->node->p, buf, sizeof(buf)),
srcdest_rnode2str(rn, buf1, sizeof(buf)));
srcdest_rnode2str(rn, buf1, sizeof(buf1)));
}
/* Identify appropriate route entry. */
@ -974,12 +974,131 @@ static void copy_state(struct rnh *rnh, const struct route_entry *re,
state->vrf_id = re->vrf_id;
state->status = re->status;
state->nhe = zebra_nhg_alloc();
state->nhe = zebra_nhe_copy(re->nhe, 0);
/* Copy the 'fib' nexthops also, if present - we want to capture
* the true installed nexthops.
*/
if (re->fib_ng.nexthop)
nexthop_group_copy(&state->fib_ng, &re->fib_ng);
if (re->fib_backup_ng.nexthop)
nexthop_group_copy(&state->fib_backup_ng, &re->fib_backup_ng);
nexthop_group_copy(&(state->nhe->nhg), &(re->nhe->nhg));
rnh->state = state;
}
/*
* Compare two route_entries' nexthops.
*/
static bool compare_valid_nexthops(struct route_entry *r1,
struct route_entry *r2)
{
bool matched_p = false;
struct nexthop_group *nhg1, *nhg2;
struct nexthop *nh1, *nh2;
/* Account for backup nexthops and for the 'fib' nexthop lists,
* if present.
*/
nhg1 = rib_get_fib_nhg(r1);
nhg2 = rib_get_fib_nhg(r2);
nh1 = nhg1->nexthop;
nh2 = nhg2->nexthop;
while (1) {
/* Find each list's next valid nexthop */
while ((nh1 != NULL) && !rnh_nexthop_valid(r1, nh1))
nh1 = nexthop_next(nh1);
while ((nh2 != NULL) && !rnh_nexthop_valid(r2, nh2))
nh2 = nexthop_next(nh2);
if (nh1 && nh2) {
/* Any difference is a no-match */
if (nexthop_cmp(nh1, nh2) != 0) {
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug("%s: nh1, nh2 differ",
__func__);
goto done;
}
nh1 = nexthop_next(nh1);
nh2 = nexthop_next(nh2);
} else if (nh1 || nh2) {
/* One list has more valid nexthops than the other */
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug("%s: nh1 %s, nh2 %s", __func__,
nh1 ? "non-NULL" : "NULL",
nh2 ? "non-NULL" : "NULL");
goto done;
} else
break; /* Done with both lists */
}
/* The test for the backups is slightly different: the only installed
* backups will be in the 'fib' list.
*/
nhg1 = rib_get_fib_backup_nhg(r1);
if (nhg1 == zebra_nhg_get_backup_nhg(r1->nhe))
nhg1 = NULL;
nhg2 = rib_get_fib_backup_nhg(r2);
if (nhg2 == zebra_nhg_get_backup_nhg(r2->nhe))
nhg2 = NULL;
if (nhg1)
nh1 = nhg1->nexthop;
else
nh1 = NULL;
if (nhg2)
nh2 = nhg2->nexthop;
else
nh2 = NULL;
while (1) {
/* Find each backup list's next valid nexthop */
while ((nh1 != NULL) && !rnh_nexthop_valid(r1, nh1))
nh1 = nexthop_next(nh1);
while ((nh2 != NULL) && !rnh_nexthop_valid(r2, nh2))
nh2 = nexthop_next(nh2);
if (nh1 && nh2) {
/* Any difference is a no-match */
if (nexthop_cmp(nh1, nh2) != 0) {
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug("%s: backup nh1, nh2 differ",
__func__);
goto done;
}
nh1 = nexthop_next(nh1);
nh2 = nexthop_next(nh2);
} else if (nh1 || nh2) {
/* One list has more valid nexthops than the other */
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug("%s: backup nh1 %s, nh2 %s",
__func__,
nh1 ? "non-NULL" : "NULL",
nh2 ? "non-NULL" : "NULL");
goto done;
} else
break; /* Done with both lists */
}
/* Well, it's a match */
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug("%s: matched", __func__);
matched_p = true;
done:
return matched_p;
}
static int compare_state(struct route_entry *r1, struct route_entry *r2)
{
if (!r1 && !r2)
@ -994,12 +1113,7 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2)
if (r1->metric != r2->metric)
return 1;
if (nexthop_group_nexthop_num(&(r1->nhe->nhg))
!= nexthop_group_nexthop_num(&(r2->nhe->nhg)))
return 1;
if (nexthop_group_hash(&(r1->nhe->nhg)) !=
nexthop_group_hash(&(r2->nhe->nhg)))
if (!compare_valid_nexthops(r1, r2))
return 1;
return 0;
@ -1044,6 +1158,7 @@ static int send_client(struct rnh *rnh, struct zserv *client,
}
if (re) {
struct zapi_nexthop znh;
struct nexthop_group *nhg;
stream_putc(s, re->type);
stream_putw(s, re->instance);
@ -1052,7 +1167,9 @@ static int send_client(struct rnh *rnh, struct zserv *client,
num = 0;
nump = stream_get_endp(s);
stream_putc(s, 0);
for (ALL_NEXTHOPS(re->nhe->nhg, nh))
nhg = rib_get_fib_nhg(re);
for (ALL_NEXTHOPS_PTR(nhg, nh))
if (rnh_nexthop_valid(re, nh)) {
zapi_nexthop_from_nexthop(&znh, nh);
ret = zapi_nexthop_encode(s, &znh, 0/*flags*/);
@ -1061,6 +1178,21 @@ static int send_client(struct rnh *rnh, struct zserv *client,
num++;
}
nhg = rib_get_fib_backup_nhg(re);
if (nhg == zebra_nhg_get_backup_nhg(re->nhe))
nhg = NULL;
if (nhg) {
for (ALL_NEXTHOPS_PTR(nhg, nh))
if (rnh_nexthop_valid(re, nh)) {
zapi_nexthop_from_nexthop(&znh, nh);
zapi_nexthop_encode(s, &znh,
0 /* flags */);
num++;
}
}
stream_putc_at(s, nump, num);
} else {
stream_putc(s, 0); // type