bgpd: Add JSON output for show rpki prefix and other show commands

```
spine1-debian-11# sh rpki prefix 192.168.100.1/32
Prefix                                   Prefix Length  Origin-AS
192.168.100.1                               32 -  32        47583
spine1-debian-11# sh rpki prefix 192.168.100.1/32 json
{
  "prefixes":[
    {
      "prefix":"192.168.100.1",
      "prefixLenMin":32,
      "prefixLenMax":32,
      "asn":47583
    }
  ]
}
```

```
spine1-debian-11# sh rpki as-number 47583 json
{
  "prefixes":[
    {
      "prefix":"192.168.100.1",
      "prefixLenMin":32,
      "prefixLenMax":32,
      "asn":47583
    },
    {
      "prefix":"2606:4700:7000::",
      "prefixLenMin":48,
      "prefixLenMax":48,
      "asn":47583
    }
  ],
  "ipv4PrefixCount":1,
  "ipv6PrefixCount":1
}
spine1-debian-11# sh rpki as-number 47583
RPKI/RTR prefix table
Prefix                                   Prefix Length  Origin-AS
192.168.100.1                               32 -  32        47583
2606:4700:7000::                            48 -  48        47583
Number of IPv4 Prefixes: 1
Number of IPv6 Prefixes: 1
```

Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
This commit is contained in:
Donatas Abraitis 2022-05-30 09:05:34 +03:00
parent 859cca2f70
commit dff41cc8a9
2 changed files with 146 additions and 47 deletions

View file

@ -98,13 +98,14 @@ struct rpki_for_each_record_arg {
struct vty *vty; struct vty *vty;
unsigned int *prefix_amount; unsigned int *prefix_amount;
as_t as; as_t as;
json_object *json;
}; };
static int start(void); static int start(void);
static void stop(void); static void stop(void);
static int reset(bool force); static int reset(bool force);
static struct rtr_mgr_group *get_connected_group(void); static struct rtr_mgr_group *get_connected_group(void);
static void print_prefix_table(struct vty *vty); static void print_prefix_table(struct vty *vty, json_object *json);
static void install_cli_commands(void); static void install_cli_commands(void);
static int config_write(struct vty *vty); static int config_write(struct vty *vty);
static int config_on_exit(struct vty *vty); static int config_on_exit(struct vty *vty);
@ -121,7 +122,8 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket);
static struct cache *find_cache(const uint8_t preference); static struct cache *find_cache(const uint8_t preference);
static int add_tcp_cache(const char *host, const char *port, static int add_tcp_cache(const char *host, const char *port,
const uint8_t preference, const char *bindaddr); const uint8_t preference, const char *bindaddr);
static void print_record(const struct pfx_record *record, struct vty *vty); static void print_record(const struct pfx_record *record, struct vty *vty,
json_object *json);
static bool is_synchronized(void); static bool is_synchronized(void);
static bool is_running(void); static bool is_running(void);
static bool is_stopping(void); static bool is_stopping(void);
@ -274,13 +276,27 @@ static struct cache *find_cache(const uint8_t preference)
return NULL; return NULL;
} }
static void print_record(const struct pfx_record *record, struct vty *vty) static void print_record(const struct pfx_record *record, struct vty *vty,
json_object *json)
{ {
char ip[INET6_ADDRSTRLEN]; char ip[INET6_ADDRSTRLEN];
json_object *json_record = NULL;
lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip)); lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
record->max_len, record->asn); if (!json) {
vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
record->max_len, record->asn);
} else {
json_record = json_object_new_object();
json_object_string_add(json_record, "prefix", ip);
json_object_int_add(json_record, "prefixLenMin",
record->min_len);
json_object_int_add(json_record, "prefixLenMax",
record->max_len);
json_object_int_add(json_record, "asn", record->asn);
json_object_array_add(json, json_record);
}
} }
static void print_record_by_asn(const struct pfx_record *record, void *data) static void print_record_by_asn(const struct pfx_record *record, void *data)
@ -290,7 +306,7 @@ static void print_record_by_asn(const struct pfx_record *record, void *data)
if (record->asn == arg->as) { if (record->asn == arg->as) {
(*arg->prefix_amount)++; (*arg->prefix_amount)++;
print_record(record, vty); print_record(record, vty, arg->json);
} }
} }
@ -301,7 +317,7 @@ static void print_record_cb(const struct pfx_record *record, void *data)
(*arg->prefix_amount)++; (*arg->prefix_amount)++;
print_record(record, vty); print_record(record, vty, arg->json);
} }
static struct rtr_mgr_group *get_groups(void) static struct rtr_mgr_group *get_groups(void)
@ -653,25 +669,36 @@ static struct rtr_mgr_group *get_connected_group(void)
return rtr_mgr_get_first_group(rtr_config); return rtr_mgr_get_first_group(rtr_config);
} }
static void print_prefix_table_by_asn(struct vty *vty, as_t as) static void print_prefix_table_by_asn(struct vty *vty, as_t as,
json_object *json)
{ {
unsigned int number_of_ipv4_prefixes = 0; unsigned int number_of_ipv4_prefixes = 0;
unsigned int number_of_ipv6_prefixes = 0; unsigned int number_of_ipv6_prefixes = 0;
struct rtr_mgr_group *group = get_connected_group(); struct rtr_mgr_group *group = get_connected_group();
struct rpki_for_each_record_arg arg; struct rpki_for_each_record_arg arg;
json_object *json_records = NULL;
arg.vty = vty; arg.vty = vty;
arg.as = as; arg.as = as;
arg.json = NULL;
if (!group) { if (!group) {
vty_out(vty, "Cannot find a connected group.\n"); if (!json)
vty_out(vty, "Cannot find a connected group.\n");
return; return;
} }
struct pfx_table *pfx_table = group->sockets[0]->pfx_table; struct pfx_table *pfx_table = group->sockets[0]->pfx_table;
vty_out(vty, "RPKI/RTR prefix table\n"); if (!json) {
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS"); vty_out(vty, "RPKI/RTR prefix table\n");
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
"Origin-AS");
} else {
json_records = json_object_new_array();
json_object_object_add(json, "prefixes", json_records);
arg.json = json_records;
}
arg.prefix_amount = &number_of_ipv4_prefixes; arg.prefix_amount = &number_of_ipv4_prefixes;
pfx_table_for_each_ipv4_record(pfx_table, print_record_by_asn, &arg); pfx_table_for_each_ipv4_record(pfx_table, print_record_by_asn, &arg);
@ -679,27 +706,51 @@ static void print_prefix_table_by_asn(struct vty *vty, as_t as)
arg.prefix_amount = &number_of_ipv6_prefixes; arg.prefix_amount = &number_of_ipv6_prefixes;
pfx_table_for_each_ipv6_record(pfx_table, print_record_by_asn, &arg); pfx_table_for_each_ipv6_record(pfx_table, print_record_by_asn, &arg);
vty_out(vty, "Number of IPv4 Prefixes: %u\n", number_of_ipv4_prefixes); if (!json) {
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes); vty_out(vty, "Number of IPv4 Prefixes: %u\n",
number_of_ipv4_prefixes);
vty_out(vty, "Number of IPv6 Prefixes: %u\n",
number_of_ipv6_prefixes);
} else {
json_object_int_add(json, "ipv4PrefixCount",
number_of_ipv4_prefixes);
json_object_int_add(json, "ipv6PrefixCount",
number_of_ipv6_prefixes);
}
if (json)
vty_json(vty, json);
} }
static void print_prefix_table(struct vty *vty) static void print_prefix_table(struct vty *vty, json_object *json)
{ {
struct rpki_for_each_record_arg arg; struct rpki_for_each_record_arg arg;
unsigned int number_of_ipv4_prefixes = 0; unsigned int number_of_ipv4_prefixes = 0;
unsigned int number_of_ipv6_prefixes = 0; unsigned int number_of_ipv6_prefixes = 0;
struct rtr_mgr_group *group = get_connected_group(); struct rtr_mgr_group *group = get_connected_group();
json_object *json_records = NULL;
arg.vty = vty; arg.vty = vty;
arg.json = NULL;
if (!group) if (!group) {
if (!json)
vty_out(vty, "Cannot find a connected group.\n");
return; return;
}
struct pfx_table *pfx_table = group->sockets[0]->pfx_table; struct pfx_table *pfx_table = group->sockets[0]->pfx_table;
vty_out(vty, "RPKI/RTR prefix table\n"); if (!json) {
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS"); vty_out(vty, "RPKI/RTR prefix table\n");
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
"Origin-AS");
} else {
json_records = json_object_new_array();
json_object_object_add(json, "prefixes", json_records);
arg.json = json_records;
}
arg.prefix_amount = &number_of_ipv4_prefixes; arg.prefix_amount = &number_of_ipv4_prefixes;
pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg); pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg);
@ -707,8 +758,20 @@ static void print_prefix_table(struct vty *vty)
arg.prefix_amount = &number_of_ipv6_prefixes; arg.prefix_amount = &number_of_ipv6_prefixes;
pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg); pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg);
vty_out(vty, "Number of IPv4 Prefixes: %u\n", number_of_ipv4_prefixes); if (!json) {
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes); vty_out(vty, "Number of IPv4 Prefixes: %u\n",
number_of_ipv4_prefixes);
vty_out(vty, "Number of IPv6 Prefixes: %u\n",
number_of_ipv6_prefixes);
} else {
json_object_int_add(json, "ipv4PrefixCount",
number_of_ipv4_prefixes);
json_object_int_add(json, "ipv6PrefixCount",
number_of_ipv6_prefixes);
}
if (json)
vty_json(vty, json);
} }
static int rpki_validate_prefix(struct peer *peer, struct attr *attr, static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
@ -1187,49 +1250,70 @@ DEFPY (no_rpki_cache,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_rpki_prefix_table, DEFPY (show_rpki_prefix_table,
show_rpki_prefix_table_cmd, show_rpki_prefix_table_cmd,
"show rpki prefix-table", "show rpki prefix-table [json$uj]",
SHOW_STR SHOW_STR
RPKI_OUTPUT_STRING RPKI_OUTPUT_STRING
"Show validated prefixes which were received from RPKI Cache\n") "Show validated prefixes which were received from RPKI Cache\n"
JSON_STR)
{ {
if (is_synchronized()) struct json_object *json = NULL;
print_prefix_table(vty);
else
vty_out(vty, "No connection to RPKI cache server.\n");
return CMD_SUCCESS;
}
DEFPY (show_rpki_as_number, show_rpki_as_number_cmd,
"show rpki as-number (1-4294967295)$by_asn",
SHOW_STR RPKI_OUTPUT_STRING
"Lookup by ASN in prefix table\n"
"AS Number\n")
{
if (!is_synchronized()) { if (!is_synchronized()) {
vty_out(vty, "No Connection to RPKI cache server.\n"); if (!uj)
vty_out(vty, "No connection to RPKI cache server.\n");
return CMD_WARNING; return CMD_WARNING;
} }
print_prefix_table_by_asn(vty, by_asn); if (uj)
json = json_object_new_object();
print_prefix_table(vty, json);
return CMD_SUCCESS;
}
DEFPY (show_rpki_as_number,
show_rpki_as_number_cmd,
"show rpki as-number (1-4294967295)$by_asn [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Lookup by ASN in prefix table\n"
"AS Number\n"
JSON_STR)
{
struct json_object *json = NULL;
if (!is_synchronized()) {
if (!uj)
vty_out(vty, "No Connection to RPKI cache server.\n");
return CMD_WARNING;
}
if (uj)
json = json_object_new_object();
print_prefix_table_by_asn(vty, by_asn, json);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFPY (show_rpki_prefix, DEFPY (show_rpki_prefix,
show_rpki_prefix_cmd, show_rpki_prefix_cmd,
"show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn]", "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn] [json$uj]",
SHOW_STR SHOW_STR
RPKI_OUTPUT_STRING RPKI_OUTPUT_STRING
"Lookup IP prefix and optionally ASN in prefix table\n" "Lookup IP prefix and optionally ASN in prefix table\n"
"IPv4 prefix\n" "IPv4 prefix\n"
"IPv6 prefix\n" "IPv6 prefix\n"
"AS Number\n") "AS Number\n"
JSON_STR)
{ {
json_object *json = NULL;
json_object *json_records = NULL;
if (!is_synchronized()) { if (!is_synchronized()) {
vty_out(vty, "No Connection to RPKI cache server.\n"); if (!uj)
vty_out(vty, "No Connection to RPKI cache server.\n");
return CMD_WARNING; return CMD_WARNING;
} }
@ -1241,7 +1325,8 @@ DEFPY (show_rpki_prefix,
memcpy(addr_str, prefix_str, addr_len); memcpy(addr_str, prefix_str, addr_len);
if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) { if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) {
vty_out(vty, "Invalid IP prefix\n"); if (!json)
vty_out(vty, "Invalid IP prefix\n");
return CMD_WARNING; return CMD_WARNING;
} }
@ -1252,21 +1337,35 @@ DEFPY (show_rpki_prefix,
if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count, if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
asn, &addr, prefix->prefixlen, &result) asn, &addr, prefix->prefixlen, &result)
!= PFX_SUCCESS) { != PFX_SUCCESS) {
vty_out(vty, "Prefix lookup failed\n"); if (!json)
vty_out(vty, "Prefix lookup failed\n");
return CMD_WARNING; return CMD_WARNING;
} }
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS"); if (uj)
json = json_object_new_object();
if (!json) {
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
"Origin-AS");
} else {
json_records = json_object_new_array();
json_object_object_add(json, "prefixes", json_records);
}
for (size_t i = 0; i < match_count; ++i) { for (size_t i = 0; i < match_count; ++i) {
const struct pfx_record *record = &matches[i]; const struct pfx_record *record = &matches[i];
if (record->max_len >= prefix->prefixlen if (record->max_len >= prefix->prefixlen
&& ((asn != 0 && (uint32_t)asn == record->asn) && ((asn != 0 && (uint32_t)asn == record->asn)
|| asn == 0)) { || asn == 0)) {
print_record(&matches[i], vty); print_record(&matches[i], vty, json_records);
} }
} }
if (json)
vty_json(vty, json);
return CMD_SUCCESS; return CMD_SUCCESS;
} }

View file

@ -200,17 +200,17 @@ Debugging
Displaying RPKI Displaying RPKI
--------------- ---------------
.. clicmd:: show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)] .. clicmd:: show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)] [json]
Display validated prefixes received from the cache servers filtered Display validated prefixes received from the cache servers filtered
by the specified prefix. by the specified prefix.
.. clicmd:: show rpki as-number ASN .. clicmd:: show rpki as-number ASN [json]
Display validated prefixes received from the cache servers filtered Display validated prefixes received from the cache servers filtered
by ASN. by ASN.
.. clicmd:: show rpki prefix-table .. clicmd:: show rpki prefix-table [json]
Display all validated prefix to origin AS mappings/records which have been Display all validated prefix to origin AS mappings/records which have been
received from the cache servers and stored in the router. Based on this data, received from the cache servers and stored in the router. Based on this data,