]> git.puffer.fish Git - matthieu/frr.git/commitdiff
ospfd: Decode Router Info. TLVs for json output
authorOlivier Dugeon <olivier.dugeon@orange.com>
Tue, 19 Dec 2023 14:59:33 +0000 (15:59 +0100)
committerOlivier Dugeon <olivier.dugeon@orange.com>
Mon, 12 Feb 2024 16:52:00 +0000 (17:52 +0100)
When dumping ospf database with json output, decode Router Information TLVs
and sub-TLVs.

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
ospfd/ospf_ri.c

index 723ccf59af574dd679b7cc6e8016fe5001aa3938..99326b41b3bc4a768897f5a0141a04a9b2732059 100644 (file)
@@ -24,6 +24,7 @@
 #include "hash.h"
 #include "sockunion.h" /* for inet_aton() */
 #include "mpls.h"
+#include <lib/json.h>
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_interface.h"
@@ -1216,15 +1217,20 @@ static int ospf_router_info_lsa_update(struct ospf_lsa *lsa)
                }                                                              \
        } while (0)
 
-static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh,
+                                   json_object *json)
 {
        struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh;
 
        check_tlv_size(RI_TLV_CAPABILITIES_SIZE, "Router Capabilities");
 
        if (vty != NULL)
-               vty_out(vty, "  Router Capabilities: 0x%x\n",
-                       ntohl(top->value));
+               if (!json)
+                       vty_out(vty, "  Router Capabilities: 0x%x\n",
+                               ntohl(top->value));
+               else
+                       json_object_string_addf(json, "routerCapabilities",
+                                               "0x%x", ntohl(top->value));
        else
                zlog_debug("    Router Capabilities: 0x%x", ntohl(top->value));
 
@@ -1232,7 +1238,8 @@ static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh)
 }
 
 static uint16_t show_vty_pce_subtlv_address(struct vty *vty,
-                                           struct tlv_header *tlvh)
+                                           struct tlv_header *tlvh,
+                                           json_object *json)
 {
        struct ri_pce_subtlv_address *top =
                (struct ri_pce_subtlv_address *)tlvh;
@@ -1240,20 +1247,28 @@ static uint16_t show_vty_pce_subtlv_address(struct vty *vty,
        if (ntohs(top->address.type) == PCE_ADDRESS_IPV4) {
                check_tlv_size(PCE_ADDRESS_IPV4_SIZE, "PCE Address");
                if (vty != NULL)
-                       vty_out(vty, "  PCE Address: %pI4\n",
-                               &top->address.value);
+                       if (!json)
+                               vty_out(vty, "  PCE Address: %pI4\n",
+                                       &top->address.value);
+                       else
+                               json_object_string_addf(json, "pceAddress",
+                                                       "%pI4",
+                                                       &top->address.value);
                else
                        zlog_debug("    PCE Address: %pI4",
                                   &top->address.value);
        } else if (ntohs(top->address.type) == PCE_ADDRESS_IPV6) {
-               /* TODO: Add support to IPv6 with inet_ntop() */
                check_tlv_size(PCE_ADDRESS_IPV6_SIZE, "PCE Address");
                if (vty != NULL)
-                       vty_out(vty, "  PCE Address: 0x%x\n",
-                               ntohl(top->address.value.s_addr));
+                       if (!json)
+                               vty_out(vty,
+                                       "  PCE Address: unsupported IPv6\n");
+                       else
+                               json_object_string_add(json, "pceAddress",
+                                                      "unsupported IPv6");
+
                else
-                       zlog_debug("    PCE Address: 0x%x",
-                                  ntohl(top->address.value.s_addr));
+                       zlog_debug("    PCE Address: unsupported IPv6");
        } else {
                if (vty != NULL)
                        vty_out(vty, "  Wrong PCE Address type: 0x%x\n",
@@ -1267,7 +1282,8 @@ static uint16_t show_vty_pce_subtlv_address(struct vty *vty,
 }
 
 static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
-                                              struct tlv_header *tlvh)
+                                              struct tlv_header *tlvh,
+                                              json_object *json)
 {
        struct ri_pce_subtlv_path_scope *top =
                (struct ri_pce_subtlv_path_scope *)tlvh;
@@ -1275,7 +1291,12 @@ static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
        check_tlv_size(RI_PCE_SUBTLV_PATH_SCOPE_SIZE, "PCE Path Scope");
 
        if (vty != NULL)
-               vty_out(vty, "  PCE Path Scope: 0x%x\n", ntohl(top->value));
+               if (!json)
+                       vty_out(vty, "  PCE Path Scope: 0x%x\n",
+                               ntohl(top->value));
+               else
+                       json_object_string_addf(json, "pcePathScope", "0x%x",
+                                               ntohl(top->value));
        else
                zlog_debug("    PCE Path Scope: 0x%x", ntohl(top->value));
 
@@ -1283,7 +1304,8 @@ static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
 }
 
 static uint16_t show_vty_pce_subtlv_domain(struct vty *vty,
-                                          struct tlv_header *tlvh)
+                                          struct tlv_header *tlvh,
+                                          json_object *json)
 {
        struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh;
        struct in_addr tmp;
@@ -1293,13 +1315,21 @@ static uint16_t show_vty_pce_subtlv_domain(struct vty *vty,
        if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
                tmp.s_addr = top->value;
                if (vty != NULL)
-                       vty_out(vty, "  PCE Domain Area: %pI4\n", &tmp);
+                       if (!json)
+                               vty_out(vty, "  PCE Domain Area: %pI4\n", &tmp);
+                       else
+                               json_object_string_addf(json, "pceDomainArea",
+                                                       "%pI4", &tmp);
                else
                        zlog_debug("    PCE Domain Area: %pI4", &tmp);
        } else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) {
                if (vty != NULL)
-                       vty_out(vty, "  PCE Domain AS: %d\n",
-                               ntohl(top->value));
+                       if (!json)
+                               vty_out(vty, "  PCE Domain AS: %d\n",
+                                       ntohl(top->value));
+                       else
+                               json_object_int_add(json, "pceDomainAS",
+                                                   ntohl(top->value));
                else
                        zlog_debug("    PCE Domain AS: %d", ntohl(top->value));
        } else {
@@ -1315,7 +1345,8 @@ static uint16_t show_vty_pce_subtlv_domain(struct vty *vty,
 }
 
 static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
-                                            struct tlv_header *tlvh)
+                                            struct tlv_header *tlvh,
+                                            json_object *json)
 {
 
        struct ri_pce_subtlv_neighbor *top =
@@ -1327,13 +1358,22 @@ static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
        if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
                tmp.s_addr = top->value;
                if (vty != NULL)
-                       vty_out(vty, "  PCE Neighbor Area: %pI4\n", &tmp);
+                       if (!json)
+                               vty_out(vty, "  PCE Neighbor Area: %pI4\n",
+                                       &tmp);
+                       else
+                               json_object_string_addf(json, "pceNeighborArea",
+                                                       "%pI4", &tmp);
                else
                        zlog_debug("    PCE Neighbor Area: %pI4", &tmp);
        } else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) {
                if (vty != NULL)
-                       vty_out(vty, "  PCE Neighbor AS: %d\n",
-                               ntohl(top->value));
+                       if (!json)
+                               vty_out(vty, "  PCE Neighbor AS: %d\n",
+                                       ntohl(top->value));
+                       else
+                               json_object_int_add(json, "pceNeighborAS",
+                                                   ntohl(top->value));
                else
                        zlog_debug("    PCE Neighbor AS: %d",
                                   ntohl(top->value));
@@ -1350,7 +1390,8 @@ static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
 }
 
 static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
-                                            struct tlv_header *tlvh)
+                                            struct tlv_header *tlvh,
+                                            json_object *json)
 {
        struct ri_pce_subtlv_cap_flag *top =
                (struct ri_pce_subtlv_cap_flag *)tlvh;
@@ -1358,8 +1399,12 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
        check_tlv_size(RI_PCE_SUBTLV_CAP_FLAG_SIZE, "PCE Capabilities");
 
        if (vty != NULL)
-               vty_out(vty, "  PCE Capabilities Flag: 0x%x\n",
-                       ntohl(top->value));
+               if (!json)
+                       vty_out(vty, "  PCE Capabilities Flag: 0x%x\n",
+                               ntohl(top->value));
+               else
+                       json_object_string_addf(json, "pceCapabilities",
+                                               "0x%x", ntohl(top->value));
        else
                zlog_debug("    PCE Capabilities Flag: 0x%x",
                           ntohl(top->value));
@@ -1368,8 +1413,10 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
 }
 
 static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
-                                    size_t buf_size)
+                                    size_t buf_size, json_object *json)
 {
+       json_object *obj;
+
        if (TLV_SIZE(tlvh) > buf_size) {
                if (vty != NULL)
                        vty_out(vty,
@@ -1383,8 +1430,18 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
        }
 
        if (vty != NULL)
-               vty_out(vty, "  Unknown TLV: [type(0x%x), length(0x%x)]\n",
-                       ntohs(tlvh->type), ntohs(tlvh->length));
+               if (!json)
+                       vty_out(vty,
+                               "  Unknown TLV: [type(0x%x), length(0x%x)]\n",
+                               ntohs(tlvh->type), ntohs(tlvh->length));
+               else {
+                       obj = json_object_new_object();
+                       json_object_string_addf(obj, "type", "0x%x",
+                                               ntohs(tlvh->type));
+                       json_object_string_addf(obj, "length", "0x%x",
+                                               ntohs(tlvh->length));
+                       json_object_object_add(json, "unknownTLV", obj);
+               }
        else
                zlog_debug("    Unknown TLV: [type(0x%x), length(0x%x)]",
                           ntohs(tlvh->type), ntohs(tlvh->length));
@@ -1393,7 +1450,7 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
 }
 
 static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
-                                 size_t buf_size)
+                                 size_t buf_size, json_object *json)
 {
        struct tlv_header *tlvh;
        uint16_t length = ntohs(ri->length);
@@ -1410,22 +1467,23 @@ static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
        for (tlvh = ri; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case RI_PCE_SUBTLV_ADDRESS:
-                       sum += show_vty_pce_subtlv_address(vty, tlvh);
+                       sum += show_vty_pce_subtlv_address(vty, tlvh, json);
                        break;
                case RI_PCE_SUBTLV_PATH_SCOPE:
-                       sum += show_vty_pce_subtlv_path_scope(vty, tlvh);
+                       sum += show_vty_pce_subtlv_path_scope(vty, tlvh, json);
                        break;
                case RI_PCE_SUBTLV_DOMAIN:
-                       sum += show_vty_pce_subtlv_domain(vty, tlvh);
+                       sum += show_vty_pce_subtlv_domain(vty, tlvh, json);
                        break;
                case RI_PCE_SUBTLV_NEIGHBOR:
-                       sum += show_vty_pce_subtlv_neighbor(vty, tlvh);
+                       sum += show_vty_pce_subtlv_neighbor(vty, tlvh, json);
                        break;
                case RI_PCE_SUBTLV_CAP_FLAG:
-                       sum += show_vty_pce_subtlv_cap_flag(vty, tlvh);
+                       sum += show_vty_pce_subtlv_cap_flag(vty, tlvh, json);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
+                       sum += show_vty_unknown_tlv(vty, tlvh, length - sum,
+                                                   json);
                        break;
                }
        }
@@ -1433,33 +1491,62 @@ static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
 }
 
 /* Display Segment Routing Algorithm TLV information */
-static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh,
+                                     json_object *json)
 {
        struct ri_sr_tlv_sr_algorithm *algo =
                (struct ri_sr_tlv_sr_algorithm *)tlvh;
        int i;
+       json_object *json_algo, *obj;
+       char buf[2];
 
        check_tlv_size(ALGORITHM_COUNT, "Segment Routing Algorithm");
 
-       if (vty != NULL) {
-               vty_out(vty, "  Segment Routing Algorithm TLV:\n");
-               for (i = 0; i < ntohs(algo->header.length); i++) {
-                       switch (algo->value[i]) {
-                       case 0:
-                               vty_out(vty, "    Algorithm %d: SPF\n", i);
-                               break;
-                       case 1:
-                               vty_out(vty, "    Algorithm %d: Strict SPF\n",
-                                       i);
-                               break;
-                       default:
-                               vty_out(vty,
-                                       "  Algorithm %d: Unknown value %d\n", i,
-                                       algo->value[i]);
-                               break;
+       if (vty != NULL)
+               if (!json) {
+                       vty_out(vty, "  Segment Routing Algorithm TLV:\n");
+                       for (i = 0; i < ntohs(algo->header.length); i++) {
+                               switch (algo->value[i]) {
+                               case 0:
+                                       vty_out(vty,
+                                               "    Algorithm %d: SPF\n", i);
+                                       break;
+                               case 1:
+                                       vty_out(vty,
+                                               "    Algorithm %d: Strict SPF\n",
+                                               i);
+                                       break;
+                               default:
+                                       vty_out(vty,
+                                               "  Algorithm %d: Unknown value %d\n", i,
+                                               algo->value[i]);
+                                       break;
+                               }
+                       }
+               } else {
+                       json_algo = json_object_new_array();
+                       json_object_object_add(json, "algorithms",
+                                              json_algo);
+                       for (i = 0; i < ntohs(algo->header.length); i++) {
+                               obj = json_object_new_object();
+                               snprintfrr(buf, 2, "%d", i);
+                               switch (algo->value[i]) {
+                               case 0:
+                                       json_object_string_add(obj, buf, "SPF");
+                                       break;
+                               case 1:
+                                       json_object_string_add(obj, buf,
+                                                              "strictSPF");
+                                       break;
+                               default:
+                                       json_object_string_add(obj, buf,
+                                                              "unknown");
+                                       break;
+                               }
+                               json_object_array_add(json_algo, obj);
                        }
                }
-       else {
+       else {
                zlog_debug("  Segment Routing Algorithm TLV:");
                for (i = 0; i < ntohs(algo->header.length); i++)
                        switch (algo->value[i]) {
@@ -1480,24 +1567,47 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
 }
 
 /* Display Segment Routing SID/Label Range TLV information */
-static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh,
+                                 json_object *json)
 {
        struct ri_sr_tlv_sid_label_range *range =
                (struct ri_sr_tlv_sid_label_range *)tlvh;
+       json_object *obj;
+       uint32_t upper;
 
        check_tlv_size(RI_SR_TLV_LABEL_RANGE_SIZE, "SR Label Range");
 
-       if (vty != NULL) {
-               vty_out(vty,
-                       "  Segment Routing %s Range TLV:\n"
-                       "    Range Size = %d\n"
-                       "    SID Label = %d\n\n",
-                       ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE
-                               ? "Global"
-                               : "Local",
-                       GET_RANGE_SIZE(ntohl(range->size)),
-                       GET_LABEL(ntohl(range->lower.value)));
-       } else {
+       if (vty != NULL)
+               if (!json) {
+                       vty_out(vty,
+                               "  Segment Routing %s Range TLV:\n"
+                               "    Range Size = %d\n"
+                               "    SID Label = %d\n\n",
+                               ntohs(range->header.type) ==
+                                               RI_SR_TLV_SRGB_LABEL_RANGE
+                                       ? "Global"
+                                       : "Local",
+                               GET_RANGE_SIZE(ntohl(range->size)),
+                               GET_LABEL(ntohl(range->lower.value)));
+               } else {
+                       /*
+                        * According to draft-ietf-teas-yang-sr-te-topo, SRGB
+                        * and SRLB are describe with lower and upper bounds
+                        */
+                       upper = GET_LABEL(ntohl(range->lower.value)) +
+                               GET_RANGE_SIZE(ntohl(range->size)) - 1;
+                       obj = json_object_new_object();
+                       json_object_int_add(obj, "upperBound", upper);
+                       json_object_int_add(obj, "lowerBound",
+                               GET_LABEL(ntohl(range->lower.value)));
+                       json_object_object_add(json,
+                                              ntohs(range->header.type) ==
+                                                    RI_SR_TLV_SRGB_LABEL_RANGE
+                                                    ? "srgb"
+                                                    : "srlb",
+                                              obj);
+               }
+       else {
                zlog_debug(
                        "  Segment Routing %s Range TLV:  Range Size = %d  SID Label = %d",
                        ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE
@@ -1511,22 +1621,25 @@ static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh)
 }
 
 /* Display Segment Routing Maximum Stack Depth TLV information */
-static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh,
+                               json_object *json)
 {
        struct ri_sr_tlv_node_msd *msd = (struct ri_sr_tlv_node_msd *)tlvh;
 
        check_tlv_size(RI_SR_TLV_NODE_MSD_SIZE, "Node Maximum Stack Depth");
 
-       if (vty != NULL) {
-               vty_out(vty,
-                       "  Segment Routing MSD TLV:\n"
-                       "    Node Maximum Stack Depth = %d\n",
-                       msd->value);
-       } else {
+       if (vty != NULL)
+               if (!json)
+                       vty_out(vty,
+                               "  Segment Routing MSD TLV:\n"
+                               "    Node Maximum Stack Depth = %d\n",
+                               msd->value);
+               else
+                       json_object_int_add(json, "nodeMsd", msd->value);
+       else
                zlog_debug(
                        "  Segment Routing MSD TLV:  Node Maximum Stack Depth = %d",
                        msd->value);
-       }
 
        return TLV_SIZE(tlvh);
 }
@@ -1538,9 +1651,14 @@ static void ospf_router_info_show_info(struct vty *vty,
        struct lsa_header *lsah = lsa->data;
        struct tlv_header *tlvh;
        uint16_t length = 0, sum = 0;
+       json_object *jri = NULL, *jpce = NULL, *jsr = NULL;
 
-       if (json)
-               return;
+       if (json) {
+               jri = json_object_new_object();
+               json_object_object_add(json, "routerInformation", jri);
+               jpce = json_object_new_object();
+               jsr = json_object_new_object();
+       }
 
        /* Initialize TLV browsing */
        length = lsa->size - OSPF_LSA_HEADER_SIZE;
@@ -1549,30 +1667,36 @@ static void ospf_router_info_show_info(struct vty *vty,
             tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case RI_TLV_CAPABILITIES:
-                       sum += show_vty_router_cap(vty, tlvh);
+                       sum += show_vty_router_cap(vty, tlvh, jri);
                        break;
                case RI_TLV_PCE:
                        tlvh++;
                        sum += TLV_HDR_SIZE;
-                       sum += show_vty_pce_info(vty, tlvh, length - sum);
+                       sum += show_vty_pce_info(vty, tlvh, length - sum, jpce);
                        break;
                case RI_SR_TLV_SR_ALGORITHM:
-                       sum += show_vty_sr_algorithm(vty, tlvh);
+                       sum += show_vty_sr_algorithm(vty, tlvh, jsr);
                        break;
                case RI_SR_TLV_SRGB_LABEL_RANGE:
                case RI_SR_TLV_SRLB_LABEL_RANGE:
-                       sum += show_vty_sr_range(vty, tlvh);
+                       sum += show_vty_sr_range(vty, tlvh, jsr);
                        break;
                case RI_SR_TLV_NODE_MSD:
-                       sum += show_vty_sr_msd(vty, tlvh);
+                       sum += show_vty_sr_msd(vty, tlvh, jsr);
                        break;
 
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh, length);
+                       sum += show_vty_unknown_tlv(vty, tlvh, length, jri);
                        break;
                }
        }
 
+       if (json) {
+               if (json_object_object_length(jpce) > 1)
+                       json_object_object_add(jri, "pceInformation", jpce);
+               if (json_object_object_length(jsr) > 1)
+                       json_object_object_add(jri, "segmentRouting", jsr);
+       }
        return;
 }
 
@@ -2045,7 +2169,7 @@ DEFUN (show_ip_ospf_router_info,
 
        if (OspfRI.enabled) {
                vty_out(vty, "--- Router Information parameters ---\n");
-               show_vty_router_cap(vty, &OspfRI.router_cap.header);
+               show_vty_router_cap(vty, &OspfRI.router_cap.header, NULL);
        } else {
                if (vty != NULL)
                        vty_out(vty,
@@ -2074,27 +2198,32 @@ DEFUN (show_ip_opsf_router_info_pce,
 
                if (pce->pce_address.header.type != 0)
                        show_vty_pce_subtlv_address(vty,
-                                                   &pce->pce_address.header);
+                                                   &pce->pce_address.header,
+                                                   NULL);
 
                if (pce->pce_scope.header.type != 0)
                        show_vty_pce_subtlv_path_scope(vty,
-                                                      &pce->pce_scope.header);
+                                                      &pce->pce_scope.header,
+                                                      NULL);
 
                for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
                        if (domain->header.type != 0)
                                show_vty_pce_subtlv_domain(vty,
-                                                          &domain->header);
+                                                          &domain->header,
+                                                          NULL);
                }
 
                for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
                        if (neighbor->header.type != 0)
                                show_vty_pce_subtlv_neighbor(vty,
-                                                            &neighbor->header);
+                                                            &neighbor->header,
+                                                            NULL);
                }
 
                if (pce->pce_cap_flag.header.type != 0)
                        show_vty_pce_subtlv_cap_flag(vty,
-                                                    &pce->pce_cap_flag.header);
+                                                    &pce->pce_cap_flag.header,
+                                                    NULL);
 
        } else {
                vty_out(vty, "  PCE info is disabled on this router\n");