forked from Mirror/frr
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:
parent
859cca2f70
commit
dff41cc8a9
187
bgpd/bgp_rpki.c
187
bgpd/bgp_rpki.c
|
@ -98,13 +98,14 @@ struct rpki_for_each_record_arg {
|
|||
struct vty *vty;
|
||||
unsigned int *prefix_amount;
|
||||
as_t as;
|
||||
json_object *json;
|
||||
};
|
||||
|
||||
static int start(void);
|
||||
static void stop(void);
|
||||
static int reset(bool force);
|
||||
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 int config_write(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 int add_tcp_cache(const char *host, const char *port,
|
||||
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_running(void);
|
||||
static bool is_stopping(void);
|
||||
|
@ -274,13 +276,27 @@ static struct cache *find_cache(const uint8_t preference)
|
|||
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];
|
||||
json_object *json_record = NULL;
|
||||
|
||||
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)
|
||||
|
@ -290,7 +306,7 @@ static void print_record_by_asn(const struct pfx_record *record, void *data)
|
|||
|
||||
if (record->asn == arg->as) {
|
||||
(*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)++;
|
||||
|
||||
print_record(record, vty);
|
||||
print_record(record, vty, arg->json);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_ipv6_prefixes = 0;
|
||||
struct rtr_mgr_group *group = get_connected_group();
|
||||
struct rpki_for_each_record_arg arg;
|
||||
json_object *json_records = NULL;
|
||||
|
||||
arg.vty = vty;
|
||||
arg.as = as;
|
||||
arg.json = NULL;
|
||||
|
||||
if (!group) {
|
||||
vty_out(vty, "Cannot find a connected group.\n");
|
||||
if (!json)
|
||||
vty_out(vty, "Cannot find a connected group.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct pfx_table *pfx_table = group->sockets[0]->pfx_table;
|
||||
|
||||
vty_out(vty, "RPKI/RTR prefix table\n");
|
||||
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
|
||||
if (!json) {
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes);
|
||||
if (!json) {
|
||||
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;
|
||||
|
||||
unsigned int number_of_ipv4_prefixes = 0;
|
||||
unsigned int number_of_ipv6_prefixes = 0;
|
||||
struct rtr_mgr_group *group = get_connected_group();
|
||||
json_object *json_records = NULL;
|
||||
|
||||
arg.vty = vty;
|
||||
arg.json = NULL;
|
||||
|
||||
if (!group)
|
||||
if (!group) {
|
||||
if (!json)
|
||||
vty_out(vty, "Cannot find a connected group.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct pfx_table *pfx_table = group->sockets[0]->pfx_table;
|
||||
|
||||
vty_out(vty, "RPKI/RTR prefix table\n");
|
||||
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
|
||||
if (!json) {
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes);
|
||||
if (!json) {
|
||||
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,
|
||||
|
@ -1187,49 +1250,70 @@ DEFPY (no_rpki_cache,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_rpki_prefix_table,
|
||||
DEFPY (show_rpki_prefix_table,
|
||||
show_rpki_prefix_table_cmd,
|
||||
"show rpki prefix-table",
|
||||
"show rpki prefix-table [json$uj]",
|
||||
SHOW_STR
|
||||
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())
|
||||
print_prefix_table(vty);
|
||||
else
|
||||
vty_out(vty, "No connection to RPKI cache server.\n");
|
||||
struct json_object *json = NULL;
|
||||
|
||||
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()) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
DEFPY (show_rpki_prefix,
|
||||
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
|
||||
RPKI_OUTPUT_STRING
|
||||
"Lookup IP prefix and optionally ASN in prefix table\n"
|
||||
"IPv4 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()) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1241,7 +1325,8 @@ DEFPY (show_rpki_prefix,
|
|||
memcpy(addr_str, prefix_str, addr_len);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1252,21 +1337,35 @@ DEFPY (show_rpki_prefix,
|
|||
if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
|
||||
asn, &addr, prefix->prefixlen, &result)
|
||||
!= PFX_SUCCESS) {
|
||||
vty_out(vty, "Prefix lookup failed\n");
|
||||
if (!json)
|
||||
vty_out(vty, "Prefix lookup failed\n");
|
||||
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) {
|
||||
const struct pfx_record *record = &matches[i];
|
||||
|
||||
if (record->max_len >= prefix->prefixlen
|
||||
&& ((asn != 0 && (uint32_t)asn == record->asn)
|
||||
|| asn == 0)) {
|
||||
print_record(&matches[i], vty);
|
||||
print_record(&matches[i], vty, json_records);
|
||||
}
|
||||
}
|
||||
|
||||
if (json)
|
||||
vty_json(vty, json);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -200,17 +200,17 @@ Debugging
|
|||
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
|
||||
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
|
||||
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
|
||||
received from the cache servers and stored in the router. Based on this data,
|
||||
|
|
Loading…
Reference in a new issue