break;
}
- /* Need to copy flags too */
+ /* Need to copy flags and backup info too */
new_nhlfe->flags = nhlfe->flags;
new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
+ if (CHECK_FLAG(new_nhlfe->nexthop->flags,
+ NEXTHOP_FLAG_HAS_BACKUP)) {
+ new_nhlfe->nexthop->backup_num =
+ nhlfe->nexthop->backup_num;
+ memcpy(new_nhlfe->nexthop->backup_idx,
+ nhlfe->nexthop->backup_idx,
+ new_nhlfe->nexthop->backup_num);
+ }
+
if (nhlfe == lsp->best_nhlfe)
ctx->u.lsp.best_nhlfe = new_nhlfe;
}
if (re) {
nhg = rib_get_fib_nhg(re);
- copy_nexthops(&(ctx->u.pw.nhg.nexthop),
- nhg->nexthop, NULL);
+ if (nhg && nhg->nexthop)
+ copy_nexthops(&(ctx->u.pw.nhg.nexthop),
+ nhg->nexthop, NULL);
}
route_unlock_node(rn);
}
enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
struct zebra_dplane_ctx *new_ctx = NULL;
struct nexthop *nexthop;
+ struct nexthop_group *nhg;
if (rn == NULL || re == NULL)
goto done;
nexthops_free(new_ctx->u.rinfo.zd_ng.nexthop);
new_ctx->u.rinfo.zd_ng.nexthop = NULL;
- copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
- (rib_get_fib_nhg(re))->nexthop, NULL);
+ nhg = rib_get_fib_nhg(re);
+ if (nhg && nhg->nexthop)
+ copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
+ nhg->nexthop, NULL);
- /* Check for backup nexthops also */
- if (re->fib_backup_ng.nexthop) {
+ /* Check for installed backup nexthops also */
+ nhg = rib_get_fib_backup_nhg(re);
+ if (nhg && nhg->nexthop) {
copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
- re->fib_backup_ng.nexthop, NULL);
+ nhg->nexthop, NULL);
}
for (ALL_NEXTHOPS(new_ctx->u.rinfo.zd_ng, nexthop))
*/
void zebra_dplane_pre_finish(void)
{
- struct zebra_dplane_provider *dp;
+ struct zebra_dplane_provider *prov;
if (IS_ZEBRA_DEBUG_DPLANE)
- zlog_debug("Zebra dataplane pre-fini called");
+ zlog_debug("Zebra dataplane pre-finish called");
zdplane_info.dg_is_shutdown = true;
/* Notify provider(s) of pending shutdown. */
- TAILQ_FOREACH(dp, &zdplane_info.dg_providers_q, dp_prov_link) {
- if (dp->dp_fini == NULL)
+ TAILQ_FOREACH(prov, &zdplane_info.dg_providers_q, dp_prov_link) {
+ if (prov->dp_fini == NULL)
continue;
- dp->dp_fini(dp, true);
+ prov->dp_fini(prov, true /* early */);
}
}
zdplane_info.dg_pthread = NULL;
zdplane_info.dg_master = NULL;
- /* Notify provider(s) of final shutdown. */
+ /* Notify provider(s) of final shutdown.
+ * Note that this call is in the main pthread, so providers must
+ * be prepared for that.
+ */
TAILQ_FOREACH(dp, &zdplane_info.dg_providers_q, dp_prov_link) {
if (dp->dp_fini == NULL)
continue;
enum lsp_types_t type);
static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
mpls_label_t in_label);
-static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty);
+static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty,
+ const char *indent);
static void lsp_print(struct vty *vty, zebra_lsp_t *lsp);
static void *slsp_alloc(void *p);
static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
{
char buf[BUFSIZ];
json_object *json_nhlfe = NULL;
+ json_object *json_backups = NULL;
struct nexthop *nexthop = nhlfe->nexthop;
+ int i;
json_nhlfe = json_object_new_object();
json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
default:
break;
}
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ json_backups = json_object_new_array();
+ for (i = 0; i < nexthop->backup_num; i++) {
+ json_object_array_add(
+ json_backups,
+ json_object_new_int(nexthop->backup_idx[i]));
+ }
+
+ json_object_object_add(json_nhlfe, "backupIndex",
+ json_backups);
+ }
+
return json_nhlfe;
}
/*
* Print the NHLFE for a LSP forwarding entry.
*/
-static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty)
+static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty,
+ const char *indent)
{
struct nexthop *nexthop;
char buf[MPLS_LABEL_STRLEN];
nexthop->nh_label->label,
buf, sizeof(buf), 0),
nhlfe->distance);
+
+ if (indent)
+ vty_out(vty, "%s", indent);
+
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
: "");
frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
- nhlfe_print(nhlfe, vty);
+ nhlfe_print(nhlfe, vty, NULL);
- if (nhlfe->nexthop &&
+ if (nhlfe->nexthop == NULL ||
!CHECK_FLAG(nhlfe->nexthop->flags,
NEXTHOP_FLAG_HAS_BACKUP))
continue;
if (backup) {
vty_out(vty, " [backup %d]", i);
- nhlfe_print(backup, vty);
+ nhlfe_print(backup, vty, " ");
}
}
}
json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
json_object_object_add(json, "nexthops", json_nhlfe_list);
+ json_nhlfe_list = NULL;
+
+
+ frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
+ if (json_nhlfe_list == NULL)
+ json_nhlfe_list = json_object_new_array();
+
+ json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
+ }
+
+ if (json_nhlfe_list)
+ json_object_object_add(json, "backupNexthops", json_nhlfe_list);
+
return json;
}
goto done_with_match;
}
- /* Examine installed nexthops */
- nhg = &match->nhe->nhg;
+ /* Examine installed nexthops; note that there
+ * may not be any installed primary nexthops if
+ * only backups are installed.
+ */
+ nhg = rib_get_fib_nhg(match);
for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
if (!nexthop_valid_resolve(nexthop, newhop))
continue;
* dedicated fib list.
*/
nhg = rib_get_fib_backup_nhg(match);
- if (nhg == NULL ||
- nhg == zebra_nhg_get_backup_nhg(match->nhe))
+ if (nhg == NULL || nhg->nexthop == NULL)
goto done_with_match;
for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
* 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;
+ nh1 = nhg1->nexthop;
+ nh2 = nhg2->nexthop;
while (1) {
/* Find each backup list's next valid nexthop */
}
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)) {
}
static char re_status_output_char(const struct route_entry *re,
- const struct nexthop *nhop)
+ const struct nexthop *nhop,
+ bool is_fib)
{
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
- if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) &&
- !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
+ bool star_p = false;
+
+ if (nhop &&
+ !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) &&
+ !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) {
+ /* More-specific test for 'fib' output */
+ if (is_fib) {
+ star_p = !!CHECK_FLAG(nhop->flags,
+ NEXTHOP_FLAG_FIB);
+ } else
+ star_p = true;
+ }
+
+ if (star_p)
return '*';
else
return ' ';
/* Double-check that there _is_ a backup */
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP) ||
- re->nhe->backup_info == NULL || re->nhe->backup_info->nhe == NULL)
+ re->nhe->backup_info == NULL || re->nhe->backup_info->nhe == NULL ||
+ re->nhe->backup_info->nhe->nhg.nexthop == NULL)
return;
/* Locate the backup nexthop(s) */
break;
}
+ /* It's possible for backups to be recursive too,
+ * so walk the recursive resolution list if present.
+ */
temp = backup;
while (backup) {
vty_out(vty, " ");
nexthop->rparent ? " " : "");
else
vty_out(vty, " %c%s",
- re_status_output_char(re, nexthop),
+ re_status_output_char(re, nexthop, false),
nexthop->rparent ? " " : "");
switch (nexthop->type) {
struct route_entry *re, json_object *json,
bool is_fib)
{
- struct nexthop *nexthop;
+ const struct nexthop *nexthop;
int len = 0;
char buf[SRCDEST2STR_BUFFER];
json_object *json_nexthops = NULL;
json_object *json_nexthop = NULL;
json_object *json_route = NULL;
time_t uptime;
- struct vrf *vrf = NULL;
- rib_dest_t *dest = rib_dest_from_rnode(rn);
- struct nexthop_group *nhg;
+ const struct vrf *vrf = NULL;
+ const rib_dest_t *dest = rib_dest_from_rnode(rn);
+ const struct nexthop_group *nhg;
char up_str[MONOTIME_STRLEN];
- bool first_p;
+ bool first_p = true;
+ bool nhg_from_backup = false;
uptime = monotime(NULL);
uptime -= re->uptime;
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
json_nexthop = json_object_new_object();
+ show_nexthop_json_helper(json_nexthop,
+ nexthop, re);
- show_nexthop_json_helper(json_nexthop, nexthop, re);
- json_object_array_add(json_nexthops, json_nexthop);
+ json_object_array_add(json_nexthops,
+ json_nexthop);
}
json_object_object_add(json_route, "nexthops", json_nexthops);
else
nhg = zebra_nhg_get_backup_nhg(re->nhe);
- if (nhg) {
+ if (nhg && nhg->nexthop) {
json_nexthops = json_object_new_array();
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
return;
}
+ /* Prefix information, and first nexthop. If we're showing 'fib',
+ * and there are no installed primary nexthops, see if there are any
+ * backup nexthops and start with those.
+ */
+ if (is_fib && nhg->nexthop == NULL) {
+ nhg = rib_get_fib_backup_nhg(re);
+ nhg_from_backup = true;
+ }
+
+ len = vty_out(vty, "%c", zebra_route_char(re->type));
+ if (re->instance)
+ len += vty_out(vty, "[%d]", re->instance);
+ if (nhg_from_backup && nhg->nexthop) {
+ len += vty_out(
+ vty, "%cb%c %s",
+ CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ',
+ re_status_output_char(re, nhg->nexthop, is_fib),
+ srcdest_rnode2str(rn, buf, sizeof(buf)));
+ } else {
+ len += vty_out(
+ vty, "%c%c %s",
+ CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ',
+ re_status_output_char(re, nhg->nexthop, is_fib),
+ srcdest_rnode2str(rn, buf, sizeof(buf)));
+ }
+
+ /* Distance and metric display. */
+ if (((re->type == ZEBRA_ROUTE_CONNECT) &&
+ (re->distance || re->metric)) ||
+ (re->type != ZEBRA_ROUTE_CONNECT))
+ len += vty_out(vty, " [%u/%u]", re->distance,
+ re->metric);
+
/* Nexthop information. */
- first_p = true;
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
if (first_p) {
first_p = false;
-
- /* Prefix information. */
- len = vty_out(vty, "%c", zebra_route_char(re->type));
- if (re->instance)
- len += vty_out(vty, "[%d]", re->instance);
- len += vty_out(
- vty, "%c%c %s",
- CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)
- ? '>'
- : ' ',
- re_status_output_char(re, nexthop),
- srcdest_rnode2str(rn, buf, sizeof(buf)));
-
- /* Distance and metric display. */
- if (((re->type == ZEBRA_ROUTE_CONNECT) &&
- (re->distance || re->metric)) ||
- (re->type != ZEBRA_ROUTE_CONNECT))
- len += vty_out(vty, " [%u/%u]", re->distance,
- re->metric);
+ } else if (nhg_from_backup) {
+ vty_out(vty, " b%c%*c",
+ re_status_output_char(re, nexthop, is_fib),
+ len - 3 + (2 * nexthop_level(nexthop)), ' ');
} else {
vty_out(vty, " %c%*c",
- re_status_output_char(re, nexthop),
+ re_status_output_char(re, nexthop, is_fib),
len - 3 + (2 * nexthop_level(nexthop)), ' ');
}
show_route_nexthop_helper(vty, re, nexthop);
-
vty_out(vty, ", %s\n", up_str);
}
- /* Check for backup info if present */
+ /* If we only had backup nexthops, we're done */
+ if (nhg_from_backup)
+ return;
+
+ /* Check for backup nexthop info if present */
if (is_fib)
nhg = rib_get_fib_backup_nhg(re);
else