From dff41cc8a96c7712db26b4711e5d668a7111b471 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Mon, 30 May 2022 09:05:34 +0300 Subject: [PATCH] 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 --- bgpd/bgp_rpki.c | 179 +++++++++++++++++++++++++++++++++++----------- doc/user/rpki.rst | 6 +- 2 files changed, 142 insertions(+), 43 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index c28b81a413..1c7dc7cb0a 100644 --- a/bgpd/bgp_rpki.c +++ b/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; + + 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(vty, json); 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") +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()) { - 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_by_asn(vty, by_asn, json); return CMD_SUCCESS; } DEFPY (show_rpki_prefix, show_rpki_prefix_cmd, - "show rpki prefix [(1-4294967295)$asn]", + "show rpki prefix [(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; } diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index ece788d9e3..e5bd59d9cb 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -200,17 +200,17 @@ Debugging Displaying RPKI --------------- -.. clicmd:: show rpki prefix [(1-4294967295)] +.. clicmd:: show rpki prefix [(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, -- 2.39.5