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`.
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
----------------------
@ -248,9 +268,6 @@ Known limitations
* 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
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
Path with an Adjacency SID due to the impossibility for the Linux Kernel to
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.
@end deffn
@deffn {Command} {show ip ospf database segment-routing} {}
@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router}} {}
@deffnx {Command} {show ip ospf database segment-routing self-originate} {}
@deffn {Command} {show ip ospf database segment-routing [json]} {}
@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router} [json]} {}
@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.
Optional Json output could be obtain by adding 'json' at the end of the command.
@end deffn
@node Debugging OSPF

View File

@ -47,6 +47,7 @@
#include "thread.h"
#include "vty.h"
#include "zclient.h"
#include <lib/json.h>
#include "ospfd/ospfd.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 sr_link *srl;
struct sr_prefix *srp;
struct interface *itf;
char pref[16];
char pref[19];
char sid[22];
char label[8];
json_object *json_node = NULL, *json_algo, *json_obj;
json_object *json_prefix = NULL, *json_link = NULL;
/* Sanity Check */
if (srn == NULL)
return;
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",
srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
for (int i = 1; i < ALGORITHM_COUNT; i++) {
if (srn->algo[i] == SR_ALGORITHM_UNSET)
continue;
vty_out(vty, "/%s",
srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
}
if (srn->msd != 0)
vty_out(vty, "\tMSD: %u", srn->msd);
if (json) {
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);
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];
vty_out(vty,
"\n\n Prefix or Link Label In Label Out "
"Node or Adj. SID Interface Nexthop\n");
vty_out(vty,
"------------------ -------- --------- "
"--------------------- --------- ---------------\n");
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",
srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
for (int i = 1; i < ALGORITHM_COUNT; i++) {
if (srn->algo[i] == SR_ALGORITHM_UNSET)
continue;
vty_out(vty, "/%s",
srn->algo[i] == SR_ALGORITHM_SPF ?
"SPF" : "S-SPF");
}
if (srn->msd != 0)
vty_out(vty, "\tMSD: %u", srn->msd);
}
if (!json) {
vty_out(vty,
"\n\n Prefix or Link Label In Label Out "
"Node or Adj. SID Interface Nexthop\n");
vty_out(vty,
"------------------ -------- --------- "
"--------------------- --------- ---------------\n");
}
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);
if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL)
sprintf(label, "pop");
else
sprintf(label, "%u", srp->nhlfe.label_out);
itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref,
srp->nhlfe.prefv4.prefixlen, srp->nhlfe.label_in, label,
sid, itf ? itf->name : "-",
inet_ntoa(srp->nhlfe.nexthop));
if (json) {
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 : "-",
inet_ntoa(srp->nhlfe.nexthop));
}
}
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]);
if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL)
sprintf(label, "pop");
else
sprintf(label, "%u", srl->nhlfe[0].label_out);
itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT);
vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref,
srl->nhlfe[0].prefv4.prefixlen, srl->nhlfe[0].label_in,
label, sid, itf ? itf->name : "-",
inet_ntoa(srl->nhlfe[0].nexthop));
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);
vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref,
srl->nhlfe[1].prefv4.prefixlen, srl->nhlfe[1].label_in,
label, sid, itf ? itf->name : "-",
inet_ntoa(srl->nhlfe[1].nexthop));
if (json) {
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 : "-",
inet_ntoa(srl->nhlfe[0].nexthop));
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[1].label_out);
vty_out(vty, "%18s %8u %9s %21s %9s %15s\n",
pref, srl->nhlfe[1].label_in,
label, sid, itf ? itf->name : "-",
inet_ntoa(srl->nhlfe[1].nexthop));
}
}
vty_out(vty, "\n");
if (json)
json_object_array_add(json, json_node);
else
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 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,
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
IP_STR
OSPF_STR
@ -2222,23 +2329,41 @@ DEFUN (show_ip_opsf_srdb,
"Show Segment Routing Data Base\n"
"Advertising SR node\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;
struct in_addr rid;
struct sr_node *srn;
u_char uj = use_json(argc, argv);
json_object *json = NULL, *json_node_array = NULL;
if (!OspfSR.enabled) {
vty_out(vty, "Segment Routing is disabled on this router\n");
return CMD_WARNING;
}
vty_out(vty, "\n OSPF Segment Routing database for ID %s\n\n",
inet_ntoa(OspfSR.self->adv_router));
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));
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)) {
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;
}
@ -2252,15 +2377,32 @@ DEFUN (show_ip_opsf_srdb,
/* Get the SR Node from the SRDB */
srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
(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;
}
/* No parameters have been provided, Iterate through all the SRDB */
hash_iterate(
OspfSR.neighbors,
(void (*)(struct hash_backet *, void *))show_srdb_entry,
(void *)vty);
if (uj) {
hash_iterate(
OspfSR.neighbors,
(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);
}
return CMD_SUCCESS;
}