Merge pull request #1789 from Orange-OpenSource/master

ospfd: Add json output for Segment Routing
This commit is contained in:
Rafael Zalamena 2018-03-05 21:55:59 -03:00 committed by GitHub
commit cc7d9cab99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 219 additions and 59 deletions

View File

@ -5,6 +5,26 @@ This is an EXPERIMENTAL support of draft
`draft-ietf-ospf-segment-routing-extensions-24`. `draft-ietf-ospf-segment-routing-extensions-24`.
DON'T use it for production network. DON'T use it for production network.
Supported Features
------------------
* Automatic computation of Primary and Backup Adjacency SID with
Cisco experimental remote IP address
* SRGB configuration
* Prefix configuration for Node SID with optional NO-PHP flag (Linux
kernel support both mode)
* Node MSD configuration (with Linux Kernel >= 4.10 a maximum of 32 labels
could be stack)
* Automatic provisioning of MPLS table
* Static route configuration with label stack up to 32 labels
Interoperability
----------------
* tested on various topology including point-to-point and LAN interfaces
in a mix of Free Range Routing instance and Cisco IOS-XR 6.0.x
* check OSPF LSA conformity with latest wireshark release 2.5.0-rc
Implementation details Implementation details
---------------------- ----------------------
@ -248,9 +268,6 @@ Known limitations
* MPLS table are not flush at startup. Thus, restarting zebra process is * MPLS table are not flush at startup. Thus, restarting zebra process is
mandatory to remove old MPLS entries in the data plane after a crash of mandatory to remove old MPLS entries in the data plane after a crash of
ospfd daemon ospfd daemon
* Due to a bug in OSPF Opaque, LSA are not flood when enable Segment Routing
through CLI once OSPFd started. You must configure Segment Routing within
configuration file before launching OSPFd
* With NO Penultimate Hop Popping, it is not possible to express a Segment * With NO Penultimate Hop Popping, it is not possible to express a Segment
Path with an Adjacency SID due to the impossibility for the Linux Kernel to Path with an Adjacency SID due to the impossibility for the Linux Kernel to
perform double POP instruction. perform double POP instruction.

View File

@ -759,10 +759,11 @@ currently supported. The 'no-php-flag' means NO Penultimate Hop Popping that
allows SR node to request to its neighbor to not pop the label. allows SR node to request to its neighbor to not pop the label.
@end deffn @end deffn
@deffn {Command} {show ip ospf database segment-routing} {} @deffn {Command} {show ip ospf database segment-routing [json]} {}
@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router}} {} @deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router} [json]} {}
@deffnx {Command} {show ip ospf database segment-routing self-originate} {} @deffnx {Command} {show ip ospf database segment-routing self-originate [json]} {}
Show Segment Routing Data Base, all SR nodes, specific advertized router or self router. Show Segment Routing Data Base, all SR nodes, specific advertized router or self router.
Optional Json output could be obtain by adding 'json' at the end of the command.
@end deffn @end deffn
@node Debugging OSPF @node Debugging OSPF

View File

@ -47,6 +47,7 @@
#include "thread.h" #include "thread.h"
#include "vty.h" #include "vty.h"
#include "zclient.h" #include "zclient.h"
#include <lib/json.h>
#include "ospfd/ospfd.h" #include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h" #include "ospfd/ospf_interface.h"
@ -2130,91 +2131,197 @@ DEFUN (no_sr_prefix_sid,
static void show_vty_sr_node(struct vty *vty, struct sr_node *srn) static void show_sr_node(struct vty *vty, struct json_object *json,
struct sr_node *srn)
{ {
struct listnode *node; struct listnode *node;
struct sr_link *srl; struct sr_link *srl;
struct sr_prefix *srp; struct sr_prefix *srp;
struct interface *itf; struct interface *itf;
char pref[16]; char pref[19];
char sid[22]; char sid[22];
char label[8]; char label[8];
json_object *json_node = NULL, *json_algo, *json_obj;
json_object *json_prefix = NULL, *json_link = NULL;
/* Sanity Check */ /* Sanity Check */
if (srn == NULL) if (srn == NULL)
return; return;
vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router)); if (json) {
vty_out(vty, "\tSRGB (Size/Label): %u/%u", srn->srgb.range_size, json_node = json_object_new_object();
json_object_string_add(json_node, "routerID",
inet_ntoa(srn->adv_router));
json_object_int_add(json_node, "srgbSize",
srn->srgb.range_size);
json_object_int_add(json_node, "srgbLabel",
srn->srgb.lower_bound); srn->srgb.lower_bound);
json_algo = json_object_new_array();
json_object_object_add(json_node, "algorithms", json_algo);
for (int i = 0; i < ALGORITHM_COUNT; i++) {
if (srn->algo[i] == SR_ALGORITHM_UNSET)
continue;
json_obj = json_object_new_object();
char tmp[2];
snprintf(tmp, 2, "%u", i);
json_object_string_add(json_obj, tmp,
srn->algo[i] == SR_ALGORITHM_SPF ?
"SPF" : "S-SPF");
json_object_array_add(json_algo, json_obj);
}
if (srn->msd != 0)
json_object_int_add(json_node, "nodeMsd", srn->msd);
} else {
vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router));
vty_out(vty, "\tSRGB (Size/Label): %u/%u",
srn->srgb.range_size, srn->srgb.lower_bound);
vty_out(vty, "\tAlgorithm(s): %s", vty_out(vty, "\tAlgorithm(s): %s",
srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
for (int i = 1; i < ALGORITHM_COUNT; i++) { for (int i = 1; i < ALGORITHM_COUNT; i++) {
if (srn->algo[i] == SR_ALGORITHM_UNSET) if (srn->algo[i] == SR_ALGORITHM_UNSET)
continue; continue;
vty_out(vty, "/%s", vty_out(vty, "/%s",
srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); srn->algo[i] == SR_ALGORITHM_SPF ?
"SPF" : "S-SPF");
} }
if (srn->msd != 0) if (srn->msd != 0)
vty_out(vty, "\tMSD: %u", srn->msd); vty_out(vty, "\tMSD: %u", srn->msd);
}
if (!json) {
vty_out(vty, vty_out(vty,
"\n\n Prefix or Link Label In Label Out " "\n\n Prefix or Link Label In Label Out "
"Node or Adj. SID Interface Nexthop\n"); "Node or Adj. SID Interface Nexthop\n");
vty_out(vty, vty_out(vty,
"------------------ -------- --------- " "------------------ -------- --------- "
"--------------------- --------- ---------------\n"); "--------------------- --------- ---------------\n");
}
for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
strncpy(pref, inet_ntoa(srp->nhlfe.prefv4.prefix), 16); snprintf(pref, 19, "%s/%u",
inet_ntoa(srp->nhlfe.prefv4.prefix),
srp->nhlfe.prefv4.prefixlen);
snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid); snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid);
if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL) if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL)
sprintf(label, "pop"); sprintf(label, "pop");
else else
sprintf(label, "%u", srp->nhlfe.label_out); sprintf(label, "%u", srp->nhlfe.label_out);
itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT); itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, if (json) {
srp->nhlfe.prefv4.prefixlen, srp->nhlfe.label_in, label, if (!json_prefix) {
json_prefix = json_object_new_array();
json_object_object_add(json_node,
"extendedPrefix", json_prefix);
}
json_obj = json_object_new_object();
json_object_string_add(json_obj, "prefix", pref);
json_object_int_add(json_obj, "sid", srp->sid);
json_object_int_add(json_obj, "inputLabel",
srp->nhlfe.label_in);
json_object_string_add(json_obj, "outputLabel",
label);
json_object_string_add(json_obj, "interface",
itf ? itf->name : "-");
json_object_string_add(json_obj, "nexthop",
inet_ntoa(srp->nhlfe.nexthop));
json_object_array_add(json_prefix, json_obj);
} else {
vty_out(vty, "%18s %8u %9s %21s %9s %15s\n",
pref, srp->nhlfe.label_in, label,
sid, itf ? itf->name : "-", sid, itf ? itf->name : "-",
inet_ntoa(srp->nhlfe.nexthop)); inet_ntoa(srp->nhlfe.nexthop));
} }
}
for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) { for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) {
strncpy(pref, inet_ntoa(srl->nhlfe[0].prefv4.prefix), 16); snprintf(pref, 19, "%s/%u",
inet_ntoa(srl->nhlfe[0].prefv4.prefix),
srl->nhlfe[0].prefv4.prefixlen);
snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]); snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]);
if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL) if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL)
sprintf(label, "pop"); sprintf(label, "pop");
else else
sprintf(label, "%u", srl->nhlfe[0].label_out); sprintf(label, "%u", srl->nhlfe[0].label_out);
itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT); itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT);
vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, if (json) {
srl->nhlfe[0].prefv4.prefixlen, srl->nhlfe[0].label_in, if (!json_link) {
json_link = json_object_new_array();
json_object_object_add(json_node,
"extendedLink", json_link);
}
/* Primary Link */
json_obj = json_object_new_object();
json_object_string_add(json_obj, "prefix", pref);
json_object_int_add(json_obj, "sid", srl->sid[0]);
json_object_int_add(json_obj, "inputLabel",
srl->nhlfe[0].label_in);
json_object_string_add(json_obj, "outputLabel",
label);
json_object_string_add(json_obj, "interface",
itf ? itf->name : "-");
json_object_string_add(json_obj, "nexthop",
inet_ntoa(srl->nhlfe[0].nexthop));
json_object_array_add(json_link, json_obj);
/* Backup Link */
json_obj = json_object_new_object();
snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL)
sprintf(label, "pop");
else
sprintf(label, "%u", srl->nhlfe[0].label_out);
json_object_string_add(json_obj, "prefix", pref);
json_object_int_add(json_obj, "sid", srl->sid[1]);
json_object_int_add(json_obj, "inputLabel",
srl->nhlfe[1].label_in);
json_object_string_add(json_obj, "outputLabel",
label);
json_object_string_add(json_obj, "interface",
itf ? itf->name : "-");
json_object_string_add(json_obj, "nexthop",
inet_ntoa(srl->nhlfe[1].nexthop));
json_object_array_add(json_link, json_obj);
} else {
vty_out(vty, "%18s %8u %9s %21s %9s %15s\n",
pref, srl->nhlfe[0].label_in,
label, sid, itf ? itf->name : "-", label, sid, itf ? itf->name : "-",
inet_ntoa(srl->nhlfe[0].nexthop)); inet_ntoa(srl->nhlfe[0].nexthop));
snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL)
sprintf(label, "pop"); sprintf(label, "pop");
else else
sprintf(label, "%u", srl->nhlfe[0].label_out); sprintf(label, "%u", srl->nhlfe[1].label_out);
vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, vty_out(vty, "%18s %8u %9s %21s %9s %15s\n",
srl->nhlfe[1].prefv4.prefixlen, srl->nhlfe[1].label_in, pref, srl->nhlfe[1].label_in,
label, sid, itf ? itf->name : "-", label, sid, itf ? itf->name : "-",
inet_ntoa(srl->nhlfe[1].nexthop)); inet_ntoa(srl->nhlfe[1].nexthop));
} }
}
if (json)
json_object_array_add(json, json_node);
else
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
static void show_srdb_entry(struct hash_backet *backet, void *args) static void show_vty_srdb(struct hash_backet *backet, void *args)
{ {
struct vty *vty = (struct vty *)args; struct vty *vty = (struct vty *)args;
struct sr_node *srn = (struct sr_node *)backet->data; struct sr_node *srn = (struct sr_node *)backet->data;
show_vty_sr_node(vty, srn); show_sr_node(vty, NULL, srn);
}
static void show_json_srdb(struct hash_backet *backet, void *args)
{
struct json_object *json = (struct json_object *)args;
struct sr_node *srn = (struct sr_node *)backet->data;
show_sr_node(NULL, json, srn);
} }
DEFUN (show_ip_opsf_srdb, DEFUN (show_ip_opsf_srdb,
show_ip_ospf_srdb_cmd, show_ip_ospf_srdb_cmd,
"show ip ospf database segment-routing [adv-router A.B.C.D|self-originate]", "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate] [json]",
SHOW_STR SHOW_STR
IP_STR IP_STR
OSPF_STR OSPF_STR
@ -2222,23 +2329,41 @@ DEFUN (show_ip_opsf_srdb,
"Show Segment Routing Data Base\n" "Show Segment Routing Data Base\n"
"Advertising SR node\n" "Advertising SR node\n"
"Advertising SR node ID (as an IP address)\n" "Advertising SR node ID (as an IP address)\n"
"Self-originated SR node\n") "Self-originated SR node\n"
JSON_STR)
{ {
int idx = 0; int idx = 0;
struct in_addr rid; struct in_addr rid;
struct sr_node *srn; struct sr_node *srn;
u_char uj = use_json(argc, argv);
json_object *json = NULL, *json_node_array = NULL;
if (!OspfSR.enabled) { if (!OspfSR.enabled) {
vty_out(vty, "Segment Routing is disabled on this router\n"); vty_out(vty, "Segment Routing is disabled on this router\n");
return CMD_WARNING; return CMD_WARNING;
} }
vty_out(vty, "\n OSPF Segment Routing database for ID %s\n\n", if (uj) {
json = json_object_new_object();
json_node_array = json_object_new_array();
json_object_string_add(json, "srdbID",
inet_ntoa(OspfSR.self->adv_router)); inet_ntoa(OspfSR.self->adv_router));
json_object_object_add(json, "srNodes", json_node_array);
} else {
vty_out(vty,
"\n\t\tOSPF Segment Routing database for ID %s\n\n",
inet_ntoa(OspfSR.self->adv_router));
}
if (argv_find(argv, argc, "self-originate", &idx)) { if (argv_find(argv, argc, "self-originate", &idx)) {
srn = OspfSR.self; srn = OspfSR.self;
show_vty_sr_node(vty, srn); show_sr_node(vty, json_node_array, srn);
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -2252,15 +2377,32 @@ DEFUN (show_ip_opsf_srdb,
/* Get the SR Node from the SRDB */ /* Get the SR Node from the SRDB */
srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
(void *)&rid); (void *)&rid);
show_vty_sr_node(vty, srn); show_sr_node(vty, json_node_array, srn);
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS; return CMD_SUCCESS;
} }
/* No parameters have been provided, Iterate through all the SRDB */ /* No parameters have been provided, Iterate through all the SRDB */
if (uj) {
hash_iterate( hash_iterate(
OspfSR.neighbors, OspfSR.neighbors,
(void (*)(struct hash_backet *, void *))show_srdb_entry, (void (*)(struct hash_backet *, void *))show_json_srdb,
(void *)json_node_array);
vty_out(vty, "%s\n",
json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY));
json_object_free(json);
} else {
hash_iterate(
OspfSR.neighbors,
(void (*)(struct hash_backet *, void *))show_vty_srdb,
(void *)vty); (void *)vty);
}
return CMD_SUCCESS; return CMD_SUCCESS;
} }