]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: revise vty output for backup nexthops
authorMark Stapp <mjs@voltanet.io>
Fri, 22 May 2020 20:42:23 +0000 (16:42 -0400)
committerMark Stapp <mjs@voltanet.io>
Tue, 7 Jul 2020 17:14:01 +0000 (13:14 -0400)
Include backup nexthops in json output; function-ify the json
output for nexthops; revise the display of backup nexthops to
use the 'b' character.

Signed-off-by: Mark Stapp <mjs@voltanet.io>
zebra/zebra_vty.c

index 9718b40d9da68ac660984a58a8ca954b07e08ed4..1da266050901d872b8b7d561a21570ddd3ee9240 100644 (file)
@@ -516,8 +516,189 @@ static void show_route_nexthop_helper(struct vty *vty,
                                       sizeof(buf), 1));
        }
 
-       if ((re == NULL) && nexthop->weight)
+       if (nexthop->weight)
                vty_out(vty, ", weight %u", nexthop->weight);
+
+       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+               vty_out(vty, ", backup %d", nexthop->backup_idx);
+}
+
+/*
+ * Render a nexthop into a json object; the caller allocates and owns
+ * the json object memory.
+ */
+static void show_nexthop_json_helper(json_object *json_nexthop,
+                                    const struct nexthop *nexthop,
+                                    const struct route_entry *re)
+{
+       char buf[SRCDEST2STR_BUFFER];
+       struct vrf *vrf = NULL;
+       json_object *json_labels = NULL;
+
+       json_object_int_add(json_nexthop, "flags",
+                           nexthop->flags);
+
+       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
+               json_object_boolean_true_add(json_nexthop,
+                                            "duplicate");
+
+       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+               json_object_boolean_true_add(json_nexthop,
+                                            "fib");
+
+       switch (nexthop->type) {
+       case NEXTHOP_TYPE_IPV4:
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+               json_object_string_add(
+                       json_nexthop, "ip",
+                       inet_ntoa(nexthop->gate.ipv4));
+               json_object_string_add(json_nexthop, "afi",
+                                      "ipv4");
+
+               if (nexthop->ifindex) {
+                       json_object_int_add(json_nexthop,
+                                           "interfaceIndex",
+                                           nexthop->ifindex);
+                       json_object_string_add(
+                               json_nexthop, "interfaceName",
+                               ifindex2ifname(
+                                       nexthop->ifindex,
+                                       nexthop->vrf_id));
+               }
+               break;
+       case NEXTHOP_TYPE_IPV6:
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+               json_object_string_add(
+                       json_nexthop, "ip",
+                       inet_ntop(AF_INET6, &nexthop->gate.ipv6,
+                                 buf, sizeof(buf)));
+               json_object_string_add(json_nexthop, "afi",
+                                      "ipv6");
+
+               if (nexthop->ifindex) {
+                       json_object_int_add(json_nexthop,
+                                           "interfaceIndex",
+                                           nexthop->ifindex);
+                       json_object_string_add(
+                               json_nexthop, "interfaceName",
+                               ifindex2ifname(
+                                       nexthop->ifindex,
+                                       nexthop->vrf_id));
+               }
+               break;
+
+       case NEXTHOP_TYPE_IFINDEX:
+               json_object_boolean_true_add(
+                       json_nexthop, "directlyConnected");
+               json_object_int_add(json_nexthop,
+                                   "interfaceIndex",
+                                   nexthop->ifindex);
+               json_object_string_add(
+                       json_nexthop, "interfaceName",
+                       ifindex2ifname(nexthop->ifindex,
+                                      nexthop->vrf_id));
+               break;
+       case NEXTHOP_TYPE_BLACKHOLE:
+               json_object_boolean_true_add(json_nexthop,
+                                            "unreachable");
+               switch (nexthop->bh_type) {
+               case BLACKHOLE_REJECT:
+                       json_object_boolean_true_add(
+                               json_nexthop, "reject");
+                       break;
+               case BLACKHOLE_ADMINPROHIB:
+                       json_object_boolean_true_add(
+                               json_nexthop,
+                               "admin-prohibited");
+                       break;
+               case BLACKHOLE_NULL:
+                       json_object_boolean_true_add(
+                               json_nexthop, "blackhole");
+                       break;
+               case BLACKHOLE_UNSPEC:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       if ((nexthop->vrf_id != re->vrf_id)
+           && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
+               vrf = vrf_lookup_by_id(nexthop->vrf_id);
+               json_object_string_add(json_nexthop, "vrf",
+                                      vrf->name);
+       }
+       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
+               json_object_boolean_true_add(json_nexthop,
+                                            "duplicate");
+
+       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+               json_object_boolean_true_add(json_nexthop,
+                                            "active");
+
+       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
+               json_object_boolean_true_add(json_nexthop,
+                                            "onLink");
+
+       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+               json_object_boolean_true_add(json_nexthop,
+                                            "recursive");
+
+       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+               json_object_int_add(json_nexthop, "backupIndex",
+                                   nexthop->backup_idx);
+
+       switch (nexthop->type) {
+       case NEXTHOP_TYPE_IPV4:
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+               if (nexthop->src.ipv4.s_addr) {
+                       if (inet_ntop(AF_INET,
+                                     &nexthop->src.ipv4, buf,
+                                     sizeof(buf)))
+                               json_object_string_add(
+                                       json_nexthop, "source",
+                                       buf);
+               }
+               break;
+       case NEXTHOP_TYPE_IPV6:
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+               if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
+                                   &in6addr_any)) {
+                       if (inet_ntop(AF_INET6,
+                                     &nexthop->src.ipv6, buf,
+                                     sizeof(buf)))
+                               json_object_string_add(
+                                       json_nexthop, "source",
+                                       buf);
+               }
+               break;
+       default:
+               break;
+       }
+
+       if (nexthop->nh_label
+           && nexthop->nh_label->num_labels) {
+               json_labels = json_object_new_array();
+
+               for (int label_index = 0;
+                    label_index
+                            < nexthop->nh_label->num_labels;
+                    label_index++)
+                       json_object_array_add(
+                               json_labels,
+                               json_object_new_int(
+                                       nexthop->nh_label->label
+                                       [label_index]));
+
+               json_object_object_add(json_nexthop, "labels",
+                                      json_labels);
+       }
+
+       if (nexthop->weight)
+               json_object_int_add(json_nexthop, "weight",
+                                   nexthop->weight);
+
 }
 
 static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
@@ -530,12 +711,12 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
        json_object *json_nexthops = NULL;
        json_object *json_nexthop = NULL;
        json_object *json_route = NULL;
-       json_object *json_labels = NULL;
        time_t uptime;
        struct vrf *vrf = NULL;
        rib_dest_t *dest = rib_dest_from_rnode(rn);
        struct nexthop_group *nhg;
        char up_str[MONOTIME_STRLEN];
+       bool first_p;
 
        uptime = monotime(NULL);
        uptime -= re->uptime;
@@ -546,7 +727,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
         * nexthops.
         */
        if (is_fib)
-               nhg = rib_active_nhg(re);
+               nhg = rib_get_fib_nhg(re);
        else
                nhg = &(re->nhe->nhg);
 
@@ -611,177 +792,44 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
                        json_nexthop = json_object_new_object();
 
-                       json_object_int_add(json_nexthop, "flags",
-                                           nexthop->flags);
+                       show_nexthop_json_helper(json_nexthop, nexthop, re);
+                       json_object_array_add(json_nexthops, json_nexthop);
+               }
 
-                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
-                               json_object_boolean_true_add(json_nexthop,
-                                                            "duplicate");
+               json_object_object_add(json_route, "nexthops", json_nexthops);
 
-                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
-                               json_object_boolean_true_add(json_nexthop,
-                                                            "fib");
+               /* If there are backup nexthops, include them */
+               if (is_fib)
+                       nhg = rib_get_fib_backup_nhg(re);
+               else
+                       nhg = zebra_nhg_get_backup_nhg(re->nhe);
 
-                       switch (nexthop->type) {
-                       case NEXTHOP_TYPE_IPV4:
-                       case NEXTHOP_TYPE_IPV4_IFINDEX:
-                               json_object_string_add(
-                                       json_nexthop, "ip",
-                                       inet_ntoa(nexthop->gate.ipv4));
-                               json_object_string_add(json_nexthop, "afi",
-                                                      "ipv4");
-
-                               if (nexthop->ifindex) {
-                                       json_object_int_add(json_nexthop,
-                                                           "interfaceIndex",
-                                                           nexthop->ifindex);
-                                       json_object_string_add(
-                                               json_nexthop, "interfaceName",
-                                               ifindex2ifname(
-                                                       nexthop->ifindex,
-                                                       nexthop->vrf_id));
-                               }
-                               break;
-                       case NEXTHOP_TYPE_IPV6:
-                       case NEXTHOP_TYPE_IPV6_IFINDEX:
-                               json_object_string_add(
-                                       json_nexthop, "ip",
-                                       inet_ntop(AF_INET6, &nexthop->gate.ipv6,
-                                                 buf, sizeof(buf)));
-                               json_object_string_add(json_nexthop, "afi",
-                                                      "ipv6");
-
-                               if (nexthop->ifindex) {
-                                       json_object_int_add(json_nexthop,
-                                                           "interfaceIndex",
-                                                           nexthop->ifindex);
-                                       json_object_string_add(
-                                               json_nexthop, "interfaceName",
-                                               ifindex2ifname(
-                                                       nexthop->ifindex,
-                                                       nexthop->vrf_id));
-                               }
-                               break;
-
-                       case NEXTHOP_TYPE_IFINDEX:
-                               json_object_boolean_true_add(
-                                       json_nexthop, "directlyConnected");
-                               json_object_int_add(json_nexthop,
-                                                   "interfaceIndex",
-                                                   nexthop->ifindex);
-                               json_object_string_add(
-                                       json_nexthop, "interfaceName",
-                                       ifindex2ifname(nexthop->ifindex,
-                                                      nexthop->vrf_id));
-                               break;
-                       case NEXTHOP_TYPE_BLACKHOLE:
-                               json_object_boolean_true_add(json_nexthop,
-                                                            "unreachable");
-                               switch (nexthop->bh_type) {
-                               case BLACKHOLE_REJECT:
-                                       json_object_boolean_true_add(
-                                               json_nexthop, "reject");
-                                       break;
-                               case BLACKHOLE_ADMINPROHIB:
-                                       json_object_boolean_true_add(
-                                               json_nexthop,
-                                               "admin-prohibited");
-                                       break;
-                               case BLACKHOLE_NULL:
-                                       json_object_boolean_true_add(
-                                               json_nexthop, "blackhole");
-                                       break;
-                               case BLACKHOLE_UNSPEC:
-                                       break;
-                               }
-                               break;
-                       default:
-                               break;
-                       }
+               if (nhg) {
+                       json_nexthops = json_object_new_array();
 
-                       if ((nexthop->vrf_id != re->vrf_id)
-                            && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
-                               vrf = vrf_lookup_by_id(nexthop->vrf_id);
-                               json_object_string_add(json_nexthop, "vrf",
-                                                      vrf->name);
-                       }
-                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
-                               json_object_boolean_true_add(json_nexthop,
-                                                            "duplicate");
-
-                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
-                               json_object_boolean_true_add(json_nexthop,
-                                                            "active");
-
-                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
-                               json_object_boolean_true_add(json_nexthop,
-                                                            "onLink");
-
-                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
-                               json_object_boolean_true_add(json_nexthop,
-                                                            "recursive");
-
-                       switch (nexthop->type) {
-                       case NEXTHOP_TYPE_IPV4:
-                       case NEXTHOP_TYPE_IPV4_IFINDEX:
-                               if (nexthop->src.ipv4.s_addr) {
-                                       if (inet_ntop(AF_INET,
-                                                     &nexthop->src.ipv4, buf,
-                                                     sizeof(buf)))
-                                               json_object_string_add(
-                                                       json_nexthop, "source",
-                                                       buf);
-                               }
-                               break;
-                       case NEXTHOP_TYPE_IPV6:
-                       case NEXTHOP_TYPE_IPV6_IFINDEX:
-                               if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
-                                                   &in6addr_any)) {
-                                       if (inet_ntop(AF_INET6,
-                                                     &nexthop->src.ipv6, buf,
-                                                     sizeof(buf)))
-                                               json_object_string_add(
-                                                       json_nexthop, "source",
-                                                       buf);
-                               }
-                               break;
-                       default:
-                               break;
-                       }
+                       for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
+                               json_nexthop = json_object_new_object();
 
-                       if (nexthop->nh_label
-                           && nexthop->nh_label->num_labels) {
-                               json_labels = json_object_new_array();
-
-                               for (int label_index = 0;
-                                    label_index
-                                    < nexthop->nh_label->num_labels;
-                                    label_index++)
-                                       json_object_array_add(
-                                               json_labels,
-                                               json_object_new_int(
-                                                       nexthop->nh_label->label
-                                                               [label_index]));
-
-                               json_object_object_add(json_nexthop, "labels",
-                                                      json_labels);
+                               show_nexthop_json_helper(json_nexthop,
+                                                        nexthop, re);
+                               json_object_array_add(json_nexthops,
+                                                     json_nexthop);
                        }
 
-                       if (nexthop->weight)
-                               json_object_int_add(json_nexthop, "weight",
-                                                   nexthop->weight);
-
-                       json_object_array_add(json_nexthops, json_nexthop);
+                       json_object_object_add(json_route, "backupNexthops",
+                                              json_nexthops);
                }
 
-               json_object_object_add(json_route, "nexthops", json_nexthops);
                json_object_array_add(json, json_route);
                return;
        }
 
        /* Nexthop information. */
+       first_p = true;
        for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
-               if (nexthop == nhg->nexthop) {
+               if (first_p) {
+                       first_p = false;
+
                        /* Prefix information. */
                        len = vty_out(vty, "%c", zebra_route_char(re->type));
                        if (re->instance)
@@ -808,40 +856,36 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
 
                show_route_nexthop_helper(vty, re, nexthop);
 
-               if (nexthop->weight)
-                       vty_out(vty, ", weight %u", nexthop->weight);
-
                vty_out(vty, ", %s\n", up_str);
+       }
 
-               /* Check for backup info */
-               if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
-                       struct nexthop *backup;
-                       int i;
+       /* Check for backup info if present */
+       if (is_fib)
+               nhg = rib_get_fib_backup_nhg(re);
+       else
+               nhg = zebra_nhg_get_backup_nhg(re->nhe);
 
-                       if (re->nhe->backup_info == NULL ||
-                           re->nhe->backup_info->nhe == NULL)
-                               continue;
+       if (nhg == NULL)
+               return;
 
-                       i = 0;
-                       for (ALL_NEXTHOPS(re->nhe->backup_info->nhe->nhg,
-                                         backup)) {
-                               if (i == nexthop->backup_idx)
-                                       break;
-                               i++;
-                       }
+       /* Print backup info */
+       for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
+               bool star_p = false;
 
-                       /* Print useful backup info */
-                       if (backup) {
-                               /* TODO -- install state is not accurate */
-                               vty_out(vty, "   %*c [backup %d]",
-                                       /*re_status_output_char(re, backup),*/
-                                       len - 3 + (2 * nexthop_level(nexthop)),
-                                       ' ', nexthop->backup_idx);
-                               show_route_nexthop_helper(vty, re, backup);
-                               vty_out(vty, "\n");
-                       }
-               }
+               if (is_fib)
+                       star_p = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+
+               /* TODO -- it'd be nice to be able to include
+                * the entire list of backups, *and* include the
+                * real installation state.
+                */
+               vty_out(vty, "  b%c %*c",
+                       (star_p ? '*' : ' '),
+                       len - 3 + (2 * nexthop_level(nexthop)), ' ');
+               show_route_nexthop_helper(vty, re, nexthop);
+               vty_out(vty, "\n");
        }
+
 }
 
 static void vty_show_ip_route_detail_json(struct vty *vty,