ospfd: Decode Router Info. TLVs for json output

When dumping ospf database with json output, decode Router Information TLVs
and sub-TLVs.

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
This commit is contained in:
Olivier Dugeon 2023-12-19 15:59:33 +01:00
parent 95c9cb9aa9
commit b27d9e4d3b

View 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");