From 7d177be5b067e2d52a2290072576806614f2acbb Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 5 Sep 2019 12:00:59 +0200 Subject: [PATCH 01/22] bgpd: notify user that pub key file may be overriden currently, private and public key files must differ with the suffix keywork : '.pub'. If it is not the case, the pub key is ignored. Inform user for that. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index d904b9f6f1..e26032744a 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -7,6 +7,7 @@ * Hamburg * Copyright (C) 2017-2018 Marcel Röthke (marcel.roethke@haw-hamburg.de), * for HAW Hamburg + * Copyright (C) 2019 6WIND * * This file is part of FRRouting. * @@ -854,6 +855,9 @@ static int add_ssh_cache(const char *host, const unsigned int port, ssh_config->bindaddr = NULL; ssh_config->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username); + /* public key path is derived from private key path + * by appending '.pub' to the private key name + */ ssh_config->client_privkey_path = XSTRDUP(MTYPE_BGP_RPKI_CACHE, client_privkey_path); ssh_config->server_hostkey_path = @@ -1141,6 +1145,7 @@ DEFPY (rpki_cache, int return_value; struct listnode *cache_node; struct cache *current_cache; + char *pub = NULL; for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, current_cache)) { if (current_cache->preference == preference) { @@ -1155,9 +1160,22 @@ DEFPY (rpki_cache, // use ssh connection if (ssh_uname) { #if defined(FOUND_SSH) + if (ssh_privkey && ssh_pubkey) { + pub = XCALLOC(MTYPE_BGP_RPKI_CACHE, + strlen(ssh_privkey) + 5); + snprintf(pub, strlen(ssh_privkey) + 5, "%s.pub", + ssh_privkey); + if (!strmatch(pub, ssh_pubkey)) { + vty_out(vty, + "ssh public key overriden: %s.pub\n", + ssh_privkey); + } + } return_value = add_ssh_cache(cache, sshport, ssh_uname, ssh_privkey, - ssh_pubkey, server_pubkey, preference); + pub, server_pubkey, preference); + if (pub) + XFREE(MTYPE_BGP_RPKI_CACHE, pub); #else return_value = SUCCESS; vty_out(vty, From bd32bb80581964d4631068199fe82c75a16d87b0 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 5 Sep 2019 12:01:54 +0200 Subject: [PATCH 02/22] bgpd: remove double spaces with rpki running config & ssh remove double spaces when doing show running-config. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index e26032744a..d62ad3e922 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -937,7 +937,7 @@ static int config_write(struct vty *vty) ssh_config->server_hostkey_path != NULL ? ssh_config ->server_hostkey_path - : " "); + : ""); break; #endif default: From b5b9dcae9c2429cd205e4ec498065f3b38a053c5 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 5 Sep 2019 12:06:37 +0200 Subject: [PATCH 03/22] bgpd: avoid crash when calling show rpki-table if ssh cache servers are configured, then show rpki-table is looking at the tcp server context. Fix this by checking the server cache type, and also display the ssh context if this is configured. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index d62ad3e922..6ead123dcb 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1242,9 +1242,14 @@ DEFUN (show_rpki_prefix_table, struct cache *cache; for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { - vty_out(vty, "host: %s port: %s\n", - cache->tr_config.tcp_config->host, - cache->tr_config.tcp_config->port); + if (cache->type == TCP) + vty_out(vty, "host: %s port: %s\n", + cache->tr_config.tcp_config->host, + cache->tr_config.tcp_config->port); + else + vty_out(vty, "host: %s port: %u SSH\n", + cache->tr_config.ssh_config->host, + cache->tr_config.ssh_config->port); } if (is_synchronized()) print_prefix_table(vty); From f9dea02e96679edf229b48bff417b0135ace239b Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 08:28:14 +0200 Subject: [PATCH 04/22] bgpd: missing rpki retry-interval in show running-config show running-config did not display rpki retry-interval. fixes this. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 6ead123dcb..22eb02d1cb 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -916,6 +916,7 @@ static int config_write(struct vty *vty) vty_out(vty, "!\n"); vty_out(vty, "rpki\n"); vty_out(vty, " rpki polling_period %d\n", polling_period); + vty_out(vty, " rpki retry-interval %d\n", retry_interval); for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { switch (cache->type) { struct tr_tcp_config *tcp_config; From 416d0484c061e9b8c586ee7ba3cc079c827bfd8f Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 10:15:05 +0200 Subject: [PATCH 05/22] bgpd: missing rpki expire-interval in show running-config a missing command expire-interval was not present in show running-config. append it. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 22eb02d1cb..3bd4f6ff5a 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -917,6 +917,7 @@ static int config_write(struct vty *vty) vty_out(vty, "rpki\n"); vty_out(vty, " rpki polling_period %d\n", polling_period); vty_out(vty, " rpki retry-interval %d\n", retry_interval); + vty_out(vty, " rpki expire_interval %d\n", expire_interval) for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { switch (cache->type) { struct tr_tcp_config *tcp_config; From f3517f58f198cef90bf1e04449f8514daf818630 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 09:14:53 +0200 Subject: [PATCH 06/22] bgpd: running-config rpki indicates only non default values the show running-config rpki was displaying systematically the default values, when at least one cache server was configured. now, if the rpki configuration has been changed, either because of a new cache server, or because of a change in the default settings, then the associated configuration is dumped in the 'show running-config' command. adding to this, to permit user to dump the settings values, the command 'show rpki configuration' dumps the values whatever default or not. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 3bd4f6ff5a..1e2ebf580f 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -904,20 +904,36 @@ static void free_cache(struct cache *cache) XFREE(MTYPE_BGP_RPKI_CACHE, cache); } + +/* return true if config changed from default */ +static bool config_changed(void) +{ + if (polling_period != POLLING_PERIOD_DEFAULT) + return true; + if (retry_interval != RETRY_INTERVAL_DEFAULT) + return true; + if (expire_interval != EXPIRE_INTERVAL_DEFAULT) + return true; + return false; +} + static int config_write(struct vty *vty) { struct listnode *cache_node; struct cache *cache; - if (listcount(cache_list)) { + if (listcount(cache_list) && config_changed()) { if (rpki_debug) vty_out(vty, "debug rpki\n"); vty_out(vty, "!\n"); vty_out(vty, "rpki\n"); - vty_out(vty, " rpki polling_period %d\n", polling_period); - vty_out(vty, " rpki retry-interval %d\n", retry_interval); - vty_out(vty, " rpki expire_interval %d\n", expire_interval) + if (polling_period != POLLING_PERIOD_DEFAULT) + vty_out(vty, " rpki polling_period %d\n", polling_period); + if (retry_interval != RETRY_INTERVAL_DEFAULT) + vty_out(vty, " rpki retry-interval %d\n", retry_interval); + if (expire_interval != EXPIRE_INTERVAL_DEFAULT) + vty_out(vty, " rpki expire_interval %d\n", expire_interval); for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { switch (cache->type) { struct tr_tcp_config *tcp_config; @@ -1423,6 +1439,25 @@ DEFUN (show_rpki_cache_connection, return CMD_SUCCESS; } +DEFUN (show_rpki_configuration, + show_rpki_configuration_cmd, + "show rpki configuration", + SHOW_STR + RPKI_OUTPUT_STRING + "Show RPKI configuration\n") +{ + vty_out(vty, "rpki is %s", + listcount(cache_list) ? "Enabled" : "Disabled"); + if (!listcount(cache_list)) + return CMD_SUCCESS; + vty_out(vty, " (%d cache servers configured)", listcount(cache_list)); + vty_out(vty, "\n"); + vty_out(vty, "\tpolling period %d\n", polling_period); + vty_out(vty, "\tretry interval %d\n", retry_interval); + vty_out(vty, "\texpire interval %d\n", expire_interval); + return CMD_SUCCESS; +} + static int config_on_exit(struct vty *vty) { reset(false); @@ -1564,6 +1599,7 @@ static void install_cli_commands(void) install_element(VIEW_NODE, &show_rpki_cache_server_cmd); install_element(VIEW_NODE, &show_rpki_prefix_cmd); install_element(VIEW_NODE, &show_rpki_as_number_cmd); + install_element(VIEW_NODE, &show_rpki_configuration_cmd); /* Install debug commands */ install_element(CONFIG_NODE, &debug_rpki_cmd); From aa31aef3598373cc1eecbb7faa5bf30b7893afb4 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 09:11:18 +0200 Subject: [PATCH 07/22] bgpd: add hooks for displaying debug information of a plugin when a plugin is attached, some debugs may be attached to that plugin. For that, add one hook that is interacting with vty: a boolean indicates what the usage is for: either for impacting the 'show running-config', or for impacting the 'show debugging' command. Signed-off-by: Philippe Guibert --- bgpd/bgp_debug.c | 9 ++++++++- bgpd/bgp_debug.h | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 2ca9e5ee13..f3d387a0e1 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -30,6 +30,7 @@ #include "memory.h" #include "queue.h" #include "filter.h" +#include "hook.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" @@ -47,6 +48,9 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_flowspec.h" +DEFINE_HOOK(bgp_hook_config_write_debug, (struct vty *vty, bool running), + (vty, running)) + unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; unsigned long conf_bgp_debug_events; @@ -2168,7 +2172,7 @@ DEFUN_NOSH (show_debugging_bgp, vty_out(vty, " BGP policy based routing debugging is on\n"); if (BGP_DEBUG(pbr, PBR_ERROR)) vty_out(vty, " BGP policy based routing error debugging is on\n"); - + hook_call(bgp_hook_config_write_debug, vty, false); vty_out(vty, "\n"); return CMD_SUCCESS; } @@ -2284,6 +2288,9 @@ static int bgp_config_write_debug(struct vty *vty) vty_out(vty, "debug bgp graceful-restart\n"); write++; } + + if (hook_call(bgp_hook_config_write_debug, vty, true)) + write++; return write; } diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 69f25566a9..e021f19c45 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -21,9 +21,15 @@ #ifndef _QUAGGA_BGP_DEBUG_H #define _QUAGGA_BGP_DEBUG_H +#include "hook.h" +#include "vty.h" + #include "bgp_attr.h" #include "bgp_updgrp.h" +DECLARE_HOOK(bgp_hook_config_write_debug, (struct vty *vty, bool running), + (vty, running)) + /* sort of packet direction */ #define DUMP_ON 1 #define DUMP_SEND 2 From fed3793b6a0641ea215d709ee71a25457fda1528 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 09:14:25 +0200 Subject: [PATCH 08/22] bgpd: link rpki debug with bgp debugging hook rpki debugging is linked with standard bgp debugging facilities. - debug rpki is dumped in running-config if the command is executed from configure terminal. - show debugging indicated whether rpki debug is enabled or not. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 1e2ebf580f..809f0557fb 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -48,6 +48,7 @@ #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_route.h" +#include "bgpd/bgp_debug.h" #include "lib/network.h" #include "lib/thread.h" #ifndef VTYSH_EXTRACT_PL @@ -73,7 +74,7 @@ DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group") #define RETRY_INTERVAL_DEFAULT 600 #define RPKI_DEBUG(...) \ - if (rpki_debug) { \ + if (rpki_debug_conf || rpki_debug_term) { \ zlog_debug("RPKI: " __VA_ARGS__); \ } @@ -98,6 +99,7 @@ struct rpki_for_each_record_arg { as_t as; }; +static int bgp_rpki_write_debug(struct vty *vty, bool running); static int start(void); static void stop(void); static int reset(bool force); @@ -136,7 +138,7 @@ static struct list *cache_list; static int rtr_is_running; static int rtr_is_stopping; static _Atomic int rtr_update_overflow; -static int rpki_debug; +static int rpki_debug_conf, rpki_debug_term; static unsigned int polling_period; static unsigned int expire_interval; static unsigned int retry_interval; @@ -535,7 +537,8 @@ err: static int bgp_rpki_init(struct thread_master *master) { - rpki_debug = 0; + rpki_debug_conf = 0; + rpki_debug_term = 0; rtr_is_running = 0; rtr_is_stopping = 0; @@ -567,6 +570,7 @@ static int bgp_rpki_module_init(void) hook_register(frr_late_init, bgp_rpki_init); hook_register(frr_early_fini, &bgp_rpki_fini); + hook_register(bgp_hook_config_write_debug, &bgp_rpki_write_debug); return 0; } @@ -904,7 +908,6 @@ static void free_cache(struct cache *cache) XFREE(MTYPE_BGP_RPKI_CACHE, cache); } - /* return true if config changed from default */ static bool config_changed(void) { @@ -917,15 +920,25 @@ static bool config_changed(void) return false; } +static int bgp_rpki_write_debug(struct vty *vty, bool running) +{ + if (rpki_debug_conf && running) { + vty_out(vty, "debug rpki\n"); + return 1; + } + if ((rpki_debug_conf || rpki_debug_term) && !running) { + vty_out(vty, " BGP RPKI debugging is on\n"); + return 1; + } + return 0; +} + static int config_write(struct vty *vty) { struct listnode *cache_node; struct cache *cache; if (listcount(cache_list) && config_changed()) { - if (rpki_debug) - vty_out(vty, "debug rpki\n"); - vty_out(vty, "!\n"); vty_out(vty, "rpki\n"); if (polling_period != POLLING_PERIOD_DEFAULT) @@ -1479,7 +1492,10 @@ DEFUN (debug_rpki, DEBUG_STR "Enable debugging for rpki\n") { - rpki_debug = 1; + if (vty->node == CONFIG_NODE) + rpki_debug_conf = 1; + else + rpki_debug_term = 1; return CMD_SUCCESS; } @@ -1490,7 +1506,10 @@ DEFUN (no_debug_rpki, DEBUG_STR "Disable debugging for rpki\n") { - rpki_debug = 0; + if (vty->node == CONFIG_NODE) + rpki_debug_conf = 0; + else + rpki_debug_term = 0; return CMD_SUCCESS; } From 743453433f28ea77f351951f50092a1d07a301e2 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 4 Sep 2019 17:51:22 +0200 Subject: [PATCH 09/22] bgpd: encapsulate rpki attributes in a context this work is a preparatory work so that rpki can have per-vrf contexts. the work consists in allocating a rpki_vrf structure with all inside: rtr_config, cache, etc.. This work is also necessary in the long term support with yang northboundapi. Indeed, there may be highly possible that yang context for rpki be defined per core instance. That work also instantiates a list of rpki_vrf, though only one instance is created. That work also introduces a vrfname field attribute that is set to null for now , and stands for default vrf where rpki is configured on. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 553 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 379 insertions(+), 174 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 809f0557fb..a357eb5e6d 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -99,31 +99,50 @@ struct rpki_for_each_record_arg { as_t as; }; +struct rpki_vrf { + struct rtr_mgr_config *rtr_config; + struct list *cache_list; + int rtr_is_running; + int rtr_is_stopping; + _Atomic int rtr_update_overflow; + unsigned int polling_period; + unsigned int expire_interval; + unsigned int retry_interval; + int rpki_sync_socket_rtr; + int rpki_sync_socket_bgpd; + char *vrfname; + + QOBJ_FIELDS +}; + static int bgp_rpki_write_debug(struct vty *vty, bool running); -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 int start(struct rpki_vrf *rpki_vrf); +static void stop(struct rpki_vrf *rpki_vrf); +static int reset(bool force, struct rpki_vrf *rpki_vrf); +static struct rtr_mgr_group *get_connected_group(struct rpki_vrf *rpki_vrf); +static void print_prefix_table(struct vty *vty, struct rpki_vrf *rpki_vrf); static void install_cli_commands(void); static int config_write(struct vty *vty); static int config_on_exit(struct vty *vty); static void free_cache(struct cache *cache); -static struct rtr_mgr_group *get_groups(void); +static struct rtr_mgr_group *get_groups(struct list *cache_list); #if defined(FOUND_SSH) -static int add_ssh_cache(const char *host, const unsigned int port, +static int add_ssh_cache(struct rpki_vrf *rpki_vrf, + const char *host, + const unsigned int port, const char *username, const char *client_privkey_path, const char *client_pubkey_path, const char *server_pubkey_path, const uint8_t preference); #endif 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); +static struct cache *find_cache(const uint8_t preference, + struct list *cache_list); +static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host, + const char *port, const uint8_t preference); static void print_record(const struct pfx_record *record, struct vty *vty); -static int is_synchronized(void); -static int is_running(void); +static int is_synchronized(struct rpki_vrf *rpki); +static int is_running(struct rpki_vrf *rpki); static void route_match_free(void *rule); static enum route_map_cmd_result_t route_match(void *rule, const struct prefix *prefix, @@ -133,17 +152,12 @@ static void *route_match_compile(const char *arg); static void revalidate_bgp_node(struct bgp_dest *dest, afi_t afi, safi_t safi); static void revalidate_all_routes(void); -static struct rtr_mgr_config *rtr_config; -static struct list *cache_list; -static int rtr_is_running; -static int rtr_is_stopping; -static _Atomic int rtr_update_overflow; static int rpki_debug_conf, rpki_debug_term; -static unsigned int polling_period; -static unsigned int expire_interval; -static unsigned int retry_interval; -static int rpki_sync_socket_rtr; -static int rpki_sync_socket_bgpd; + +DECLARE_QOBJ_TYPE(rpki_vrf) +DEFINE_QOBJ_TYPE(rpki_vrf) + +struct list *rpki_vrf_list; static struct cmd_node rpki_node = { .name = "rpki", @@ -262,11 +276,30 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket) return rtr_socket; } -static struct cache *find_cache(const uint8_t preference) +static struct rpki_vrf *find_rpki_vrf(const char *vrfname) +{ + struct listnode *rpki_vrf_nnode; + struct rpki_vrf *rpki_vrf; + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf_list, rpki_vrf_nnode, rpki_vrf)) { + if ((!vrfname && rpki_vrf->vrfname) || + (vrfname && !rpki_vrf->vrfname) || + (vrfname && rpki_vrf->vrfname && + !strmatch(vrfname, rpki_vrf->vrfname))) + continue; + return rpki_vrf; + } + return NULL; +} + +static struct cache *find_cache(const uint8_t preference, + struct list *cache_list) { struct listnode *cache_node; struct cache *cache; + if (!cache_list) + return NULL; for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { if (cache->preference == preference) return cache; @@ -304,13 +337,14 @@ static void print_record_cb(const struct pfx_record *record, void *data) print_record(record, vty); } -static struct rtr_mgr_group *get_groups(void) +static struct rtr_mgr_group *get_groups(struct list *cache_list) { struct listnode *cache_node; struct rtr_mgr_group *rtr_mgr_groups; struct cache *cache; + int group_count; - int group_count = listcount(cache_list); + group_count = listcount(cache_list); if (group_count == 0) return NULL; @@ -333,14 +367,15 @@ static struct rtr_mgr_group *get_groups(void) return rtr_mgr_groups; } -inline int is_synchronized(void) +inline int is_synchronized(struct rpki_vrf *rpki_vrf) { - return rtr_is_running && rtr_mgr_conf_in_sync(rtr_config); + return rpki_vrf->rtr_is_running && + rtr_mgr_conf_in_sync(rpki_vrf->rtr_config); } -inline int is_running(void) +inline int is_running(struct rpki_vrf *rpki_vrf) { - return rtr_is_running; + return rpki_vrf->rtr_is_running; } static struct prefix *pfx_record_to_prefix(struct pfx_record *record) @@ -367,24 +402,27 @@ static int bgpd_sync_callback(struct thread *thread) struct listnode *node; struct prefix *prefix; struct pfx_record rec; + struct rpki_vrf *rpki_vrf = THREAD_ARG(thread); - thread_add_read(bm->master, bgpd_sync_callback, NULL, - rpki_sync_socket_bgpd, NULL); + thread_add_read(bm->master, bgpd_sync_callback, rpki_vrf, + rpki_vrf->rpki_sync_socket_bgpd, NULL); - if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) { - while (read(rpki_sync_socket_bgpd, &rec, + if (atomic_load_explicit(&rpki_vrf->rtr_update_overflow, + memory_order_seq_cst)) { + while (read(rpki_vrf->rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)) != -1) ; - atomic_store_explicit(&rtr_update_overflow, 0, + atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 0, memory_order_seq_cst); revalidate_all_routes(); return 0; } int retval = - read(rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)); + read(rpki_vrf->rpki_sync_socket_bgpd, &rec, + sizeof(struct pfx_record)); if (retval != sizeof(struct pfx_record)) { RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd"); return retval; @@ -486,21 +524,33 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)), const struct pfx_record rec, const bool added __attribute__((unused))) { - if (rtr_is_stopping - || atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) - return; + struct rpki_vrf *rpki_vrf; + const char *msg; + rpki_vrf = find_rpki_vrf(NULL); + if (!rpki_vrf) { + msg = "could not find rpki_vrf"; + goto err; + } + if (rpki_vrf->rtr_is_stopping + || atomic_load_explicit(&rpki_vrf->rtr_update_overflow, + memory_order_seq_cst)) + return; int retval = - write(rpki_sync_socket_rtr, &rec, sizeof(struct pfx_record)); + write(rpki_vrf->rpki_sync_socket_rtr, &rec, + sizeof(struct pfx_record)); if (retval == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) - atomic_store_explicit(&rtr_update_overflow, 1, + atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 1, memory_order_seq_cst); else if (retval != sizeof(struct pfx_record)) RPKI_DEBUG("Could not write to rpki_sync_socket_rtr"); + return; +err: + zlog_err("RPKI: %s", msg); } -static void rpki_init_sync_socket(void) +static void rpki_init_sync_socket(struct rpki_vrf *rpki_vrf) { int fds[2]; const char *msg; @@ -510,22 +560,22 @@ static void rpki_init_sync_socket(void) msg = "could not open rpki sync socketpair"; goto err; } - rpki_sync_socket_rtr = fds[0]; - rpki_sync_socket_bgpd = fds[1]; + rpki_vrf->rpki_sync_socket_rtr = fds[0]; + rpki_vrf->rpki_sync_socket_bgpd = fds[1]; - if (set_nonblocking(rpki_sync_socket_rtr) != 0) { + if (set_nonblocking(rpki_vrf->rpki_sync_socket_rtr) != 0) { msg = "could not set rpki_sync_socket_rtr to non blocking"; goto err; } - if (set_nonblocking(rpki_sync_socket_bgpd) != 0) { + if (set_nonblocking(rpki_vrf->rpki_sync_socket_bgpd) != 0) { msg = "could not set rpki_sync_socket_bgpd to non blocking"; goto err; } - thread_add_read(bm->master, bgpd_sync_callback, NULL, - rpki_sync_socket_bgpd, NULL); + thread_add_read(bm->master, bgpd_sync_callback, rpki_vrf, + rpki_vrf->rpki_sync_socket_bgpd, NULL); return; @@ -537,29 +587,47 @@ err: static int bgp_rpki_init(struct thread_master *master) { + struct rpki_vrf *def_rpki_vrf; + rpki_debug_conf = 0; rpki_debug_term = 0; - rtr_is_running = 0; - rtr_is_stopping = 0; - cache_list = list_new(); - cache_list->del = (void (*)(void *)) & free_cache; + rpki_vrf_list = list_new(); + /* initialise default vrf cache list */ + def_rpki_vrf = XCALLOC(MTYPE_BGP_RPKI_CACHE, + sizeof(struct rpki_vrf)); + listnode_add(rpki_vrf_list, def_rpki_vrf); + + def_rpki_vrf->rtr_is_running = 0; + def_rpki_vrf->rtr_is_stopping = 0; + def_rpki_vrf->cache_list = list_new(); + def_rpki_vrf->cache_list->del = (void (*)(void *)) & free_cache; + def_rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; + def_rpki_vrf->expire_interval = EXPIRE_INTERVAL_DEFAULT; + def_rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; + + QOBJ_REG(def_rpki_vrf, rpki_vrf); - polling_period = POLLING_PERIOD_DEFAULT; - expire_interval = EXPIRE_INTERVAL_DEFAULT; - retry_interval = RETRY_INTERVAL_DEFAULT; install_cli_commands(); - rpki_init_sync_socket(); + + rpki_init_sync_socket(def_rpki_vrf); return 0; } static int bgp_rpki_fini(void) { - stop(); - list_delete(&cache_list); + struct rpki_vrf *rpki_vrf; - close(rpki_sync_socket_rtr); - close(rpki_sync_socket_bgpd); + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (!rpki_vrf) + return 0; + + stop(rpki_vrf); + list_delete(&rpki_vrf->cache_list); + + close(rpki_vrf->rpki_sync_socket_rtr); + close(rpki_vrf->rpki_sync_socket_bgpd); return 0; } @@ -575,83 +643,94 @@ static int bgp_rpki_module_init(void) return 0; } -static int start(void) +static int start(struct rpki_vrf *rpki_vrf) { int ret; + struct list *cache_list = NULL; - rtr_is_stopping = 0; - rtr_update_overflow = 0; + cache_list = rpki_vrf->cache_list; + rpki_vrf->rtr_is_stopping = 0; + rpki_vrf->rtr_update_overflow = 0; - if (list_isempty(cache_list)) { - RPKI_DEBUG( - "No caches were found in config. Prefix validation is off."); + if (!cache_list || list_isempty(cache_list)) { + RPKI_DEBUG("No caches were found in config." + "Prefix validation is off."); return ERROR; } RPKI_DEBUG("Init rtr_mgr."); int groups_len = listcount(cache_list); - struct rtr_mgr_group *groups = get_groups(); + struct rtr_mgr_group *groups = get_groups(rpki_vrf->cache_list); - RPKI_DEBUG("Polling period: %d", polling_period); - ret = rtr_mgr_init(&rtr_config, groups, groups_len, polling_period, - expire_interval, retry_interval, - rpki_update_cb_sync_rtr, NULL, NULL, NULL); + RPKI_DEBUG("Polling period: %d", rpki_vrf->polling_period); + ret = rtr_mgr_init(&rpki_vrf->rtr_config, groups, groups_len, + rpki_vrf->polling_period, rpki_vrf->expire_interval, + rpki_vrf->retry_interval, rpki_update_cb_sync_rtr, + NULL, NULL, NULL); if (ret == RTR_ERROR) { RPKI_DEBUG("Init rtr_mgr failed."); return ERROR; } RPKI_DEBUG("Starting rtr_mgr."); - ret = rtr_mgr_start(rtr_config); + ret = rtr_mgr_start(rpki_vrf->rtr_config); if (ret == RTR_ERROR) { RPKI_DEBUG("Starting rtr_mgr failed."); - rtr_mgr_free(rtr_config); + rtr_mgr_free(rpki_vrf->rtr_config); return ERROR; } - rtr_is_running = 1; + rpki_vrf->rtr_is_running = 1; XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups); return SUCCESS; } -static void stop(void) +static void stop(struct rpki_vrf *rpki_vrf) { - rtr_is_stopping = 1; - if (rtr_is_running) { - rtr_mgr_stop(rtr_config); - rtr_mgr_free(rtr_config); - rtr_is_running = 0; + rpki_vrf->rtr_is_stopping = 1; + if (rpki_vrf->rtr_is_running) { + rtr_mgr_stop(rpki_vrf->rtr_config); + rtr_mgr_free(rpki_vrf->rtr_config); + rpki_vrf->rtr_is_running = 0; } } -static int reset(bool force) +static int reset(bool force, struct rpki_vrf *rpki_vrf) { - if (rtr_is_running && !force) + if (rpki_vrf->rtr_is_running && !force) return SUCCESS; RPKI_DEBUG("Resetting RPKI Session"); - stop(); - return start(); + stop(rpki_vrf); + return start(rpki_vrf); } -static struct rtr_mgr_group *get_connected_group(void) +static struct rtr_mgr_group *get_connected_group(struct rpki_vrf *rpki_vrf) { + struct list *cache_list; + + if (!rpki_vrf) + return NULL; + cache_list = rpki_vrf->cache_list; if (!cache_list || list_isempty(cache_list)) return NULL; - return rtr_mgr_get_first_group(rtr_config); + return rtr_mgr_get_first_group(rpki_vrf->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, struct rpki_vrf *rpki_vrf) { unsigned int number_of_ipv4_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(rpki_vrf); struct rpki_for_each_record_arg arg; arg.vty = vty; arg.as = as; + if (!rpki_vrf) + return; + if (!group) { vty_out(vty, "Cannot find a connected group.\n"); return; @@ -672,14 +751,17 @@ static void print_prefix_table_by_asn(struct vty *vty, as_t as) vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes); } -static void print_prefix_table(struct vty *vty) +static void print_prefix_table(struct vty *vty, struct rpki_vrf *rpki_vrf) { 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(); + struct rtr_mgr_group *group; + if (!rpki_vrf) + return; + group = get_connected_group(rpki_vrf); arg.vty = vty; if (!group) @@ -709,8 +791,20 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr, enum pfxv_state result; char buf[BUFSIZ]; const char *prefix_string; + struct bgp *bgp = peer->bgp; + struct vrf *vrf; + struct rpki_vrf *rpki_vrf; - if (!is_synchronized()) + if (!bgp) + return 0; + vrf = vrf_lookup_by_id(bgp->vrf_id); + if (!vrf) + return 0; + if (vrf->vrf_id == VRF_DEFAULT) + rpki_vrf = find_rpki_vrf(NULL); + else + rpki_vrf = find_rpki_vrf(vrf->name); + if (!rpki_vrf || !is_synchronized(rpki_vrf)) return 0; // No aspath means route comes from iBGP @@ -755,7 +849,7 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr, } // Do the actual validation - rtr_mgr_validate(rtr_config, as_number, &ip_addr_prefix, + rtr_mgr_validate(rpki_vrf->rtr_config, as_number, &ip_addr_prefix, prefix->prefixlen, &result); // Print Debug output @@ -785,19 +879,27 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr, return 0; } -static int add_cache(struct cache *cache) +static int add_cache(struct cache *cache, struct rpki_vrf *rpki_vrf) { uint8_t preference = cache->preference; struct rtr_mgr_group group; + struct list *cache_list; + + /* assume default vrf */ group.preference = preference; group.sockets_len = 1; group.sockets = &cache->rtr_socket; - if (rtr_is_running) { + cache_list = rpki_vrf->cache_list; + if (!cache_list) + return ERROR; + + if (rpki_vrf->rtr_is_running) { init_tr_socket(cache); - if (rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) { + if (rtr_mgr_add_group(rpki_vrf->rtr_config, &group) + != RTR_SUCCESS) { free_tr_socket(cache); return ERROR; } @@ -808,16 +910,19 @@ static int add_cache(struct cache *cache) return SUCCESS; } -static int add_tcp_cache(const char *host, const char *port, - const uint8_t preference) +static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host, + const char *port, const uint8_t preference) { struct rtr_socket *rtr_socket; - struct tr_tcp_config *tcp_config = - XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_tcp_config)); - struct tr_socket *tr_socket = - XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_socket)); - struct cache *cache = - XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct cache)); + struct tr_tcp_config *tcp_config; + struct tr_socket *tr_socket; + struct cache *cache; + int ret; + + tcp_config = XCALLOC(MTYPE_BGP_RPKI_CACHE, + sizeof(struct tr_tcp_config)); + tr_socket = XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_socket)); + cache = XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct cache)); tcp_config->host = XSTRDUP(MTYPE_BGP_RPKI_CACHE, host); tcp_config->port = XSTRDUP(MTYPE_BGP_RPKI_CACHE, port); @@ -831,28 +936,32 @@ static int add_tcp_cache(const char *host, const char *port, cache->rtr_socket = rtr_socket; cache->preference = preference; - int ret = add_cache(cache); + ret = add_cache(cache, rpki_vrf); if (ret != SUCCESS) { free_cache(cache); } - return ret; } #if defined(FOUND_SSH) -static int add_ssh_cache(const char *host, const unsigned int port, +static int add_ssh_cache(struct rpki_vrf *rpki_vrf, + const char *host, + const unsigned int port, const char *username, const char *client_privkey_path, const char *client_pubkey_path, const char *server_pubkey_path, const uint8_t preference) { - struct tr_ssh_config *ssh_config = - XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_ssh_config)); - struct cache *cache = - XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct cache)); - struct tr_socket *tr_socket = - XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_socket)); + struct tr_ssh_config *ssh_config; + struct cache *cache; + struct tr_socket *tr_socket; struct rtr_socket *rtr_socket; + int ret; + + ssh_config = XCALLOC(MTYPE_BGP_RPKI_CACHE, + sizeof(struct tr_ssh_config)); + cache = XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct cache)); + tr_socket = XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_socket)); ssh_config->port = port; ssh_config->host = XSTRDUP(MTYPE_BGP_RPKI_CACHE, host); @@ -875,7 +984,7 @@ static int add_ssh_cache(const char *host, const unsigned int port, cache->rtr_socket = rtr_socket; cache->preference = preference; - int ret = add_cache(cache); + ret = add_cache(cache, rpki_vrf); if (ret != SUCCESS) { free_cache(cache); } @@ -909,13 +1018,15 @@ static void free_cache(struct cache *cache) } /* return true if config changed from default */ -static bool config_changed(void) +static bool config_changed(struct rpki_vrf *rpki_vrf) { - if (polling_period != POLLING_PERIOD_DEFAULT) + if (rpki_vrf->cache_list && listcount(rpki_vrf->cache_list)) return true; - if (retry_interval != RETRY_INTERVAL_DEFAULT) + if (rpki_vrf->polling_period != POLLING_PERIOD_DEFAULT) return true; - if (expire_interval != EXPIRE_INTERVAL_DEFAULT) + if (rpki_vrf->retry_interval != RETRY_INTERVAL_DEFAULT) + return true; + if (rpki_vrf->expire_interval != EXPIRE_INTERVAL_DEFAULT) return true; return false; } @@ -937,16 +1048,25 @@ static int config_write(struct vty *vty) { struct listnode *cache_node; struct cache *cache; + struct rpki_vrf *rpki_vrf; + struct list *cache_list; - if (listcount(cache_list) && config_changed()) { + rpki_vrf = find_rpki_vrf(NULL); + if (!rpki_vrf) + return ERROR; + if (config_changed(rpki_vrf)) { vty_out(vty, "!\n"); vty_out(vty, "rpki\n"); - if (polling_period != POLLING_PERIOD_DEFAULT) - vty_out(vty, " rpki polling_period %d\n", polling_period); - if (retry_interval != RETRY_INTERVAL_DEFAULT) - vty_out(vty, " rpki retry-interval %d\n", retry_interval); - if (expire_interval != EXPIRE_INTERVAL_DEFAULT) - vty_out(vty, " rpki expire_interval %d\n", expire_interval); + if (rpki_vrf->polling_period != POLLING_PERIOD_DEFAULT) + vty_out(vty, " rpki polling_period %d\n", + rpki_vrf->polling_period); + if (rpki_vrf->retry_interval != RETRY_INTERVAL_DEFAULT) + vty_out(vty, " rpki retry-interval %d\n", + rpki_vrf->retry_interval); + if (rpki_vrf->expire_interval != EXPIRE_INTERVAL_DEFAULT) + vty_out(vty, " rpki expire_interval %d\n", + rpki_vrf->expire_interval); + for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { switch (cache->type) { struct tr_tcp_config *tcp_config; @@ -962,12 +1082,13 @@ static int config_write(struct vty *vty) case SSH: ssh_config = cache->tr_config.ssh_config; vty_out(vty, " rpki cache %s %u %s %s %s ", - ssh_config->host, ssh_config->port, + ssh_config->host, + ssh_config->port, ssh_config->username, ssh_config->client_privkey_path, ssh_config->server_hostkey_path != NULL ? ssh_config - ->server_hostkey_path + ->server_hostkey_path : ""); break; #endif @@ -989,7 +1110,13 @@ DEFUN_NOSH (rpki, "rpki", "Enable rpki and enter rpki configuration mode\n") { + struct rpki_vrf *rpki_vrf; + vty->node = RPKI_NODE; + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (rpki_vrf) + VTY_PUSH_CONTEXT(RPKI_NODE, rpki_vrf); return CMD_SUCCESS; } @@ -999,12 +1126,19 @@ DEFUN (bgp_rpki_start, RPKI_OUTPUT_STRING "start rpki support\n") { - if (listcount(cache_list) == 0) - vty_out(vty, - "Could not start rpki because no caches are configured\n"); + struct list *cache_list = NULL; + struct rpki_vrf *rpki_vrf; - if (!is_running()) { - if (start() == ERROR) { + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (rpki_vrf) + cache_list = rpki_vrf->cache_list; + if (!rpki_vrf || !cache_list || listcount(cache_list) == 0) + vty_out(vty, "Could not start rpki" + " because no caches are configured\n"); + + if (!is_running(rpki_vrf)) { + if (start(rpki_vrf) == ERROR) { RPKI_DEBUG("RPKI failed to start"); return CMD_WARNING; } @@ -1018,8 +1152,12 @@ DEFUN (bgp_rpki_stop, RPKI_OUTPUT_STRING "start rpki support\n") { - if (is_running()) - stop(); + struct rpki_vrf *rpki_vrf; + + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (rpki_vrf && is_running(rpki_vrf)) + stop(rpki_vrf); return CMD_SUCCESS; } @@ -1031,7 +1169,9 @@ DEFPY (rpki_polling_period, "Set polling period\n" "Polling period value\n") { - polling_period = pp; + VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + + rpki_vrf->polling_period = pp; return CMD_SUCCESS; } @@ -1042,7 +1182,9 @@ DEFUN (no_rpki_polling_period, RPKI_OUTPUT_STRING "Set polling period back to default\n") { - polling_period = POLLING_PERIOD_DEFAULT; + VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + + rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; return CMD_SUCCESS; } @@ -1053,8 +1195,10 @@ DEFPY (rpki_expire_interval, "Set expire interval\n" "Expire interval value\n") { - if ((unsigned int)tmp >= polling_period) { - expire_interval = tmp; + VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + + if ((unsigned int)tmp >= rpki_vrf->polling_period) { + rpki_vrf->expire_interval = tmp; return CMD_SUCCESS; } @@ -1069,7 +1213,9 @@ DEFUN (no_rpki_expire_interval, RPKI_OUTPUT_STRING "Set expire interval back to default\n") { - expire_interval = polling_period * 2; + VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + + rpki_vrf->expire_interval = rpki_vrf->polling_period * 2; return CMD_SUCCESS; } @@ -1080,7 +1226,9 @@ DEFPY (rpki_retry_interval, "Set retry interval\n" "retry interval value\n") { - retry_interval = tmp; + VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + + rpki_vrf->retry_interval = tmp; return CMD_SUCCESS; } @@ -1091,7 +1239,9 @@ DEFUN (no_rpki_retry_interval, RPKI_OUTPUT_STRING "Set retry interval back to default\n") { - retry_interval = RETRY_INTERVAL_DEFAULT; + VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + + rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; return CMD_SUCCESS; } @@ -1178,16 +1328,20 @@ DEFPY (rpki_cache, struct cache *current_cache; char *pub = NULL; - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, current_cache)) { + VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + + if (!rpki_vrf->cache_list) + return CMD_WARNING; + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + current_cache)) { if (current_cache->preference == preference) { - vty_out(vty, - "Cache with preference %ld is already configured\n", + vty_out(vty, "Cache with preference %ld " + "is already configured\n", preference); return CMD_WARNING; } } - // use ssh connection if (ssh_uname) { #if defined(FOUND_SSH) @@ -1203,8 +1357,8 @@ DEFPY (rpki_cache, } } return_value = - add_ssh_cache(cache, sshport, ssh_uname, ssh_privkey, - pub, server_pubkey, preference); + add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname, ssh_privkey, + pub, server_pubkey, preference); if (pub) XFREE(MTYPE_BGP_RPKI_CACHE, pub); #else @@ -1215,7 +1369,8 @@ DEFPY (rpki_cache, "If you want to use it\n"); #endif } else { // use tcp connection - return_value = add_tcp_cache(cache, tcpport, preference); + return_value = add_tcp_cache(rpki_vrf, cache, tcpport, + preference); } if (return_value == ERROR) { @@ -1238,17 +1393,23 @@ DEFPY (no_rpki_cache, "Preference of the cache server\n" "Preference value\n") { - struct cache *cache_p = find_cache(preference); + struct cache *cache_p; + struct list *cache_list = NULL; - if (!cache_p) { + VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + + cache_list = rpki_vrf->cache_list; + cache_p = find_cache(preference, cache_list); + if (!rpki_vrf || !cache_p) { vty_out(vty, "Could not find cache %ld\n", preference); return CMD_WARNING; } - if (rtr_is_running && listcount(cache_list) == 1) { - stop(); - } else if (rtr_is_running) { - if (rtr_mgr_remove_group(rtr_config, preference) == RTR_ERROR) { + if (rpki_vrf->rtr_is_running && listcount(rpki_vrf->cache_list) == 1) { + stop(rpki_vrf); + } else if (rpki_vrf->rtr_is_running) { + if (rtr_mgr_remove_group(rpki_vrf->rtr_config, preference) + == RTR_ERROR) { vty_out(vty, "Could not remove cache %ld", preference); vty_out(vty, "\n"); @@ -1271,8 +1432,13 @@ DEFUN (show_rpki_prefix_table, { struct listnode *cache_node; struct cache *cache; + struct rpki_vrf *rpki_vrf; - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (!rpki_vrf) + return CMD_SUCCESS; + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { if (cache->type == TCP) vty_out(vty, "host: %s port: %s\n", cache->tr_config.tcp_config->host, @@ -1282,8 +1448,8 @@ DEFUN (show_rpki_prefix_table, cache->tr_config.ssh_config->host, cache->tr_config.ssh_config->port); } - if (is_synchronized()) - print_prefix_table(vty); + if (is_synchronized(rpki_vrf)) + print_prefix_table(vty, rpki_vrf); else vty_out(vty, "No connection to RPKI cache server.\n"); @@ -1296,12 +1462,17 @@ DEFPY(show_rpki_as_number, show_rpki_as_number_cmd, "Lookup by ASN in prefix table\n" "AS Number\n") { - if (!is_synchronized()) { + struct rpki_vrf *rpki_vrf; + + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + + if (!is_synchronized(rpki_vrf)) { vty_out(vty, "No Connection to RPKI cache server.\n"); return CMD_WARNING; } - print_prefix_table_by_asn(vty, by_asn); + print_prefix_table_by_asn(vty, by_asn, rpki_vrf); return CMD_SUCCESS; } @@ -1315,8 +1486,12 @@ DEFPY (show_rpki_prefix, "IPv6 prefix\n" "AS Number\n") { + struct rpki_vrf *rpki_vrf; - if (!is_synchronized()) { + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + + if (!rpki_vrf || !is_synchronized(rpki_vrf)) { vty_out(vty, "No Connection to RPKI cache server.\n"); return CMD_WARNING; } @@ -1337,8 +1512,9 @@ DEFPY (show_rpki_prefix, unsigned int match_count = 0; enum pfxv_state result; - if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count, - asn, &addr, prefix->prefixlen, &result) + if (pfx_table_validate_r(rpki_vrf->rtr_config->pfx_table, &matches, + &match_count, asn, &addr, + prefix->prefixlen, &result) != PFX_SUCCESS) { vty_out(vty, "Prefix lookup failed"); return CMD_WARNING; @@ -1367,8 +1543,14 @@ DEFUN (show_rpki_cache_server, { struct listnode *cache_node; struct cache *cache; + struct rpki_vrf *rpki_vrf; - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (!rpki_vrf) + return CMD_SUCCESS; + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { if (cache->type == TCP) { vty_out(vty, "host: %s port: %s\n", cache->tr_config.tcp_config->host, @@ -1400,17 +1582,25 @@ DEFUN (show_rpki_cache_connection, RPKI_OUTPUT_STRING "Show to which RPKI Cache Servers we have a connection\n") { - if (is_synchronized()) { + struct rpki_vrf *rpki_vrf; + + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (!rpki_vrf) + return CMD_SUCCESS; + + if (is_synchronized(rpki_vrf)) { struct listnode *cache_node; struct cache *cache; - struct rtr_mgr_group *group = get_connected_group(); + struct rtr_mgr_group *group = get_connected_group(rpki_vrf); - if (!group) { + if (!group || !rpki_vrf->cache_list) { vty_out(vty, "Cannot find a connected group.\n"); return CMD_SUCCESS; } vty_out(vty, "Connected to group %d\n", group->preference); - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, + cache_node, cache)) { if (cache->preference == group->preference) { struct tr_tcp_config *tcp_config; #if defined(FOUND_SSH) @@ -1459,21 +1649,30 @@ DEFUN (show_rpki_configuration, RPKI_OUTPUT_STRING "Show RPKI configuration\n") { - vty_out(vty, "rpki is %s", - listcount(cache_list) ? "Enabled" : "Disabled"); - if (!listcount(cache_list)) + struct rpki_vrf *rpki_vrf; + + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (!rpki_vrf) return CMD_SUCCESS; - vty_out(vty, " (%d cache servers configured)", listcount(cache_list)); + vty_out(vty, "rpki is %s", + listcount(rpki_vrf->cache_list) ? "Enabled" : "Disabled"); + if (!listcount(rpki_vrf->cache_list)) + return CMD_SUCCESS; + vty_out(vty, " (%d cache servers configured)", + listcount(rpki_vrf->cache_list)); vty_out(vty, "\n"); - vty_out(vty, "\tpolling period %d\n", polling_period); - vty_out(vty, "\tretry interval %d\n", retry_interval); - vty_out(vty, "\texpire interval %d\n", expire_interval); + vty_out(vty, "\tpolling period %d\n", rpki_vrf->polling_period); + vty_out(vty, "\tretry interval %d\n", rpki_vrf->retry_interval); + vty_out(vty, "\texpire interval %d\n", rpki_vrf->expire_interval); return CMD_SUCCESS; } static int config_on_exit(struct vty *vty) { - reset(false); + VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + + reset(false, rpki_vrf); return 1; } @@ -1483,7 +1682,13 @@ DEFUN (rpki_reset, RPKI_OUTPUT_STRING "reset rpki\n") { - return reset(true) == SUCCESS ? CMD_SUCCESS : CMD_WARNING; + struct rpki_vrf *rpki_vrf; + + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (!rpki_vrf) + return CMD_SUCCESS; + return reset(true, rpki_vrf) == SUCCESS ? CMD_SUCCESS : CMD_WARNING; } DEFUN (debug_rpki, From 38bf60cb2392a5178880ab1f775d87891de8742d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 16:41:12 +0200 Subject: [PATCH 10/22] bgpd: suppress availability from rpki command under enable node this command may conflict with the same command available under vrf subnode. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 1 - 1 file changed, 1 deletion(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index a357eb5e6d..8ecc227461 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1785,7 +1785,6 @@ static void install_cli_commands(void) install_node(&rpki_node); install_default(RPKI_NODE); install_element(CONFIG_NODE, &rpki_cmd); - install_element(ENABLE_NODE, &rpki_cmd); install_element(ENABLE_NODE, &bgp_rpki_start_cmd); install_element(ENABLE_NODE, &bgp_rpki_stop_cmd); From dde9d0e43b1415e126412d493ade174ee2b6edde Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 20 Sep 2019 12:05:45 +0200 Subject: [PATCH 11/22] lib, vtysh: bgp rpki constistent changes with rpki_node rpki_node is a node under configure terminal. as such, align with other nodes that are similar. Note that this change is important, since the location where show running-config from vtysh displays rpki configuration is changed in the middle of the configuration instead of at the top, before authentication. Signed-off-by: Philippe Guibert --- vtysh/vtysh_config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index abbb111f9d..44ec08b61a 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -402,6 +402,8 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(MPLS_NODE, line); else if (strncmp(line, "bfd", strlen("bfd")) == 0) config = config_get(BFD_NODE, line); + else if (strncmp(line, "rpki", strlen("rpki")) == 0) + config = config_get(RPKI_NODE, line); else { if (strncmp(line, "log", strlen("log")) == 0 || strncmp(line, "hostname", strlen("hostname")) From 157f6f486111bac2505695fd6edc42efb55dc290 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 08:22:26 +0200 Subject: [PATCH 12/22] bgpd: ability to remove rpki contexts from vty rpki context can be removed by doing 'no rpki' command from configure node. this work allows to allocate the associated rpki_vrf context when entering in rpki node, instead of at the initialisation step. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 86 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 25 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 8ecc227461..ec09483acf 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -585,35 +585,55 @@ err: } +static struct rpki_vrf *bgp_rpki_allocate(const char *vrfname) +{ + struct rpki_vrf *rpki_vrf; + + rpki_vrf = XCALLOC(MTYPE_BGP_RPKI_CACHE, + sizeof(struct rpki_vrf)); + + rpki_vrf->rtr_is_running = 0; + rpki_vrf->rtr_is_stopping = 0; + rpki_vrf->cache_list = list_new(); + rpki_vrf->cache_list->del = (void (*)(void *)) & free_cache; + rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; + rpki_vrf->expire_interval = EXPIRE_INTERVAL_DEFAULT; + rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; + + if (vrfname && !strmatch(vrfname, VRF_DEFAULT_NAME)) + rpki_vrf->vrfname = XSTRDUP(MTYPE_BGP_RPKI_CACHE, + vrfname); + QOBJ_REG(rpki_vrf, rpki_vrf); + listnode_add(rpki_vrf_list, rpki_vrf); + return rpki_vrf; +} + static int bgp_rpki_init(struct thread_master *master) { - struct rpki_vrf *def_rpki_vrf; - rpki_debug_conf = 0; rpki_debug_term = 0; rpki_vrf_list = list_new(); - /* initialise default vrf cache list */ - def_rpki_vrf = XCALLOC(MTYPE_BGP_RPKI_CACHE, - sizeof(struct rpki_vrf)); - listnode_add(rpki_vrf_list, def_rpki_vrf); - - def_rpki_vrf->rtr_is_running = 0; - def_rpki_vrf->rtr_is_stopping = 0; - def_rpki_vrf->cache_list = list_new(); - def_rpki_vrf->cache_list->del = (void (*)(void *)) & free_cache; - def_rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; - def_rpki_vrf->expire_interval = EXPIRE_INTERVAL_DEFAULT; - def_rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; - - QOBJ_REG(def_rpki_vrf, rpki_vrf); - install_cli_commands(); - rpki_init_sync_socket(def_rpki_vrf); return 0; } +static void bgp_rpki_finish(struct rpki_vrf *rpki_vrf) +{ + stop(rpki_vrf); + list_delete(&rpki_vrf->cache_list); + + close(rpki_vrf->rpki_sync_socket_rtr); + close(rpki_vrf->rpki_sync_socket_bgpd); + + listnode_delete(rpki_vrf_list, rpki_vrf); + QOBJ_UNREG(rpki_vrf); + if (rpki_vrf->vrfname) + XFREE(MTYPE_BGP_RPKI_CACHE, rpki_vrf->vrfname); + XFREE(MTYPE_BGP_RPKI_CACHE, rpki_vrf); +} + static int bgp_rpki_fini(void) { struct rpki_vrf *rpki_vrf; @@ -622,12 +642,7 @@ static int bgp_rpki_fini(void) rpki_vrf = find_rpki_vrf(NULL); if (!rpki_vrf) return 0; - - stop(rpki_vrf); - list_delete(&rpki_vrf->cache_list); - - close(rpki_vrf->rpki_sync_socket_rtr); - close(rpki_vrf->rpki_sync_socket_bgpd); + bgp_rpki_finish(rpki_vrf); return 0; } @@ -1115,8 +1130,28 @@ DEFUN_NOSH (rpki, vty->node = RPKI_NODE; /* assume default vrf */ rpki_vrf = find_rpki_vrf(NULL); + if (!rpki_vrf) { + rpki_vrf = bgp_rpki_allocate(NULL); + + rpki_init_sync_socket(rpki_vrf); + } + VTY_PUSH_CONTEXT(RPKI_NODE, rpki_vrf); + return CMD_SUCCESS; +} + +DEFUN_NOSH (no_rpki, + no_rpki_cmd, + "no rpki", + NO_STR + "Enable rpki and enter rpki configuration mode\n") +{ + struct rpki_vrf *rpki_vrf; + + /* assume default vrf */ + rpki_vrf = find_rpki_vrf(NULL); + if (rpki_vrf) - VTY_PUSH_CONTEXT(RPKI_NODE, rpki_vrf); + bgp_rpki_finish(rpki_vrf); return CMD_SUCCESS; } @@ -1785,6 +1820,7 @@ static void install_cli_commands(void) install_node(&rpki_node); install_default(RPKI_NODE); install_element(CONFIG_NODE, &rpki_cmd); + install_element(CONFIG_NODE, &no_rpki_cmd); install_element(ENABLE_NODE, &bgp_rpki_start_cmd); install_element(ENABLE_NODE, &bgp_rpki_stop_cmd); From 044307285ba23da01177db02d25e84c35e0bcdac Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 29 Oct 2019 17:52:52 +0100 Subject: [PATCH 13/22] bgpd: add a hook to inform a vrf is enabled/disabled this hook can be used by plugins like rpki. Signed-off-by: Philippe Guibert --- bgpd/bgp_main.c | 5 +++++ bgpd/bgpd.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 33eaf9ae74..a5826527c8 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -65,6 +65,9 @@ #include "bgpd/rfapi/rfapi_backend.h" #endif +DEFINE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled), + (vrf, enabled)) + /* bgpd options, we use GNU getopt library. */ static const struct option longopts[] = { {"bgp_port", required_argument, NULL, 'p'}, @@ -302,6 +305,7 @@ static int bgp_vrf_enable(struct vrf *vrf) if (old_vrf_id != bgp->vrf_id) bgp_redistribute_redo(bgp); bgp_instance_up(bgp); + hook_call(bgp_hook_vrf_update, vrf, true); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, @@ -351,6 +355,7 @@ static int bgp_vrf_disable(struct vrf *vrf) if (old_vrf_id != bgp->vrf_id) bgp_unset_redist_vrf_bitmaps(bgp, old_vrf_id); bgp_instance_down(bgp); + hook_call(bgp_hook_vrf_update, vrf, false); } /* Note: This is a callback, the VRF will be deleted by the caller. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 4a5772a53b..d0ba87e687 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -677,6 +677,8 @@ DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)) DECLARE_HOOK(bgp_inst_config_write, (struct bgp *bgp, struct vty *vty), (bgp, vty)) +DECLARE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled), + (vrf, enabled)) /* Thread callback information */ struct afi_safi_info { From c06cad2bd6213d314ab4d7e4a84aaf8bd6c0b27d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 29 Oct 2019 17:56:47 +0100 Subject: [PATCH 14/22] bgpd: use rtrlib callback for socket creation this commit change introduces a callback function pointer that rtrlib calls. this permits to create the socket and initialising the socket with the right information, in the right vrf. Adding to this, rpki uses a hook to be triggered when a vrf is enabled/disabled. in this way, start mechanisms will be triggered only when vrf is available, and stop mechanism will be done upon vrf disable event. Adding to this, the cache structure contains a back pointer to the rpki vrf structure. this is done to retrieve the vrf where the cache points to. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 238 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index ec09483acf..841a6efbf9 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -62,6 +62,7 @@ #include "bgpd/bgp_rpki_clippy.c" #endif +DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_TEMP, "BGP RPKI Intermediate Buffer") DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server") DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group") @@ -89,10 +90,13 @@ struct cache { } tr_config; struct rtr_socket *rtr_socket; uint8_t preference; + struct rpki_vrf *rpki_vrf; }; enum return_values { SUCCESS = 0, ERROR = -1 }; +extern struct zebra_privs_t bgpd_privs; + struct rpki_for_each_record_arg { struct vty *vty; unsigned int *prefix_amount; @@ -111,10 +115,11 @@ struct rpki_vrf { int rpki_sync_socket_rtr; int rpki_sync_socket_bgpd; char *vrfname; - QOBJ_FIELDS }; +static struct rpki_vrf *find_rpki_vrf(const char *vrfname); +static int bgp_rpki_vrf_update(struct vrf *vrf, bool enabled); static int bgp_rpki_write_debug(struct vty *vty, bool running); static int start(struct rpki_vrf *rpki_vrf); static void stop(struct rpki_vrf *rpki_vrf); @@ -276,6 +281,103 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket) return rtr_socket; } +static int bgp_rpki_vrf_update(struct vrf *vrf, bool enabled) +{ + struct rpki_vrf *rpki; + + if (vrf->vrf_id == VRF_DEFAULT) + rpki = find_rpki_vrf(NULL); + else + rpki = find_rpki_vrf(vrf->name); + if (!rpki) + return 0; + + if (enabled) + start(rpki); + else + stop(rpki); + return 1; +} + +/* tcp identifier : : + * ssh identifier : @: + */ +static struct rpki_vrf *find_rpki_vrf_from_ident(const char *ident) +{ + char *ptr; + unsigned int port; + char *endptr; + struct listnode *rpki_vrf_nnode; + struct rpki_vrf *rpki_vrf; + struct listnode *cache_node; + struct cache *cache; + char *buf, *host; + bool is_tcp = true; + size_t host_len; + + /* extract the */ + ptr = strrchr(ident, ':'); + if (!ptr) + return NULL; + ptr++; + /* extract port */ + port = atoi(ptr); + if (port == 0) + /* not ours */ + return NULL; + /* extract host */ + ptr--; + host_len = (size_t)(ptr - ident); + buf = XCALLOC(MTYPE_BGP_RPKI_TEMP, host_len + 1); + memcpy(buf, ident, host_len); + buf[host_len] = '\0'; + endptr = strrchr(buf, '@'); + /* ssh session */ + if (endptr) { + host = XCALLOC(MTYPE_BGP_RPKI_TEMP, (size_t)(buf + host_len - endptr) + 1); + memcpy(host, endptr + 1, (size_t)(buf + host_len - endptr) + 1); + is_tcp = false; + } else { + host = buf; + buf = NULL; + } + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf_list, rpki_vrf_nnode, rpki_vrf)) { + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, + cache_node, cache)) { + if ((cache->type == TCP && !is_tcp) || + (cache->type == SSH && is_tcp)) + continue; + if (is_tcp) { + struct tr_tcp_config *tcp_config = cache->tr_config.tcp_config; + unsigned int cache_port; + + cache_port = atoi(tcp_config->port); + if (cache_port != port) + continue; + if (strlen(tcp_config->host) != strlen(host)) + continue; + if (0 == memcmp(tcp_config->host, host, host_len)) + break; + } else { + struct tr_ssh_config *ssh_config = cache->tr_config.ssh_config; + + if (port != ssh_config->port) + continue; + if (strmatch(ssh_config->host, host)) + break; + } + } + if (cache) + break; + } + if (host) + XFREE(MTYPE_BGP_RPKI_TEMP, host); + if (buf) + XFREE(MTYPE_BGP_RPKI_TEMP, buf); + return rpki_vrf; +} + static struct rpki_vrf *find_rpki_vrf(const char *vrfname) { struct listnode *rpki_vrf_nnode; @@ -345,7 +447,6 @@ static struct rtr_mgr_group *get_groups(struct list *cache_list) int group_count; group_count = listcount(cache_list); - if (group_count == 0) return NULL; @@ -526,8 +627,26 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)), { struct rpki_vrf *rpki_vrf; const char *msg; + struct rtr_socket *rtr = rec.socket; + struct tr_socket *tr; + const char *ident; + int retval; - rpki_vrf = find_rpki_vrf(NULL); + if (!rtr) { + msg = "could not find rtr_socket from cb_sync_rtr"; + goto err; + } + tr = rtr->tr_socket; + if (!tr) { + msg = "could not find tr_socket from cb_sync_rtr"; + goto err; + } + ident = tr->ident_fp(tr->socket); + if (!ident) { + msg = "could not find rpki_vrf ident"; + goto err; + } + rpki_vrf = find_rpki_vrf_from_ident(ident); if (!rpki_vrf) { msg = "could not find rpki_vrf"; goto err; @@ -536,7 +655,7 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)), || atomic_load_explicit(&rpki_vrf->rtr_update_overflow, memory_order_seq_cst)) return; - int retval = + retval = write(rpki_vrf->rpki_sync_socket_rtr, &rec, sizeof(struct pfx_record)); if (retval == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) @@ -654,6 +773,7 @@ static int bgp_rpki_module_init(void) hook_register(frr_late_init, bgp_rpki_init); hook_register(frr_early_fini, &bgp_rpki_fini); hook_register(bgp_hook_config_write_debug, &bgp_rpki_write_debug); + hook_register(bgp_hook_vrf_update, &bgp_rpki_vrf_update); return 0; } @@ -662,6 +782,7 @@ static int start(struct rpki_vrf *rpki_vrf) { int ret; struct list *cache_list = NULL; + struct vrf *vrf; cache_list = rpki_vrf->cache_list; rpki_vrf->rtr_is_stopping = 0; @@ -672,6 +793,17 @@ static int start(struct rpki_vrf *rpki_vrf) "Prefix validation is off."); return ERROR; } + + if (rpki_vrf->vrfname) + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + else + vrf = vrf_lookup_by_id(VRF_DEFAULT); + if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) { + RPKI_DEBUG("VRF %s not present or disabled", + rpki_vrf->vrfname); + return ERROR; + } + RPKI_DEBUG("Init rtr_mgr."); int groups_len = listcount(cache_list); struct rtr_mgr_group *groups = get_groups(rpki_vrf->cache_list); @@ -894,13 +1026,16 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr, return 0; } -static int add_cache(struct cache *cache, struct rpki_vrf *rpki_vrf) +static int add_cache(struct cache *cache) { uint8_t preference = cache->preference; struct rtr_mgr_group group; struct list *cache_list; + struct rpki_vrf *rpki_vrf; - /* assume default vrf */ + rpki_vrf = cache->rpki_vrf; + if (!rpki_vrf) + return ERROR; group.preference = preference; group.sockets_len = 1; @@ -925,6 +1060,95 @@ static int add_cache(struct cache *cache, struct rpki_vrf *rpki_vrf) return SUCCESS; } +static int rpki_create_socket(struct cache *cache) +{ + struct vrf *vrf; + int socket; + struct addrinfo hints; + struct addrinfo *res = NULL; + char *host, *port; + struct rpki_vrf *rpki_vrf = cache->rpki_vrf; + int ret; + + if (rpki_vrf->vrfname == NULL) + vrf = vrf_lookup_by_id(VRF_DEFAULT); + else + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + if (!vrf) + return 0; + + if (!CHECK_FLAG(vrf->status, VRF_ACTIVE) || + vrf->vrf_id == VRF_UNKNOWN) + return 0; + + bzero(&hints, sizeof(hints)); + + if (cache->type == TCP) { + struct tr_tcp_config *tcp_config; + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; + + tcp_config = cache->tr_config.tcp_config; + host = tcp_config->host; + port = tcp_config->port; + } else { + char s_port[10]; + struct tr_ssh_config *ssh_config; + + ssh_config = cache->tr_config.ssh_config; + host = ssh_config->host; + snprintf(s_port, sizeof(s_port), "%hu", + ssh_config->port); + port = s_port; + + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + } + frr_with_privs(&bgpd_privs) { + ret = vrf_getaddrinfo(host, port, + &hints, &res, vrf->vrf_id); + } + if (ret != 0) { + zlog_err("getaddrinfo error, %u", errno); + return 0; + } + frr_with_privs(&bgpd_privs) { + socket = vrf_socket(res->ai_family, res->ai_socktype, + res->ai_protocol, vrf->vrf_id, NULL); + } + if (socket <= 0) { + zlog_err("vrf socket error, %u", errno); + return 0; + } + + if (connect(socket, res->ai_addr, res->ai_addrlen) == -1) { + zlog_err("Couldn't establish TCP connection, %s", strerror(errno)); + if (res) + freeaddrinfo(res); + return 0; + } + if (res) + freeaddrinfo(res); + return socket; +} + +static int rpki_get_socket(void *_cache) +{ + int sock; + struct cache *cache = (struct cache *)_cache; + + if (!cache) + return -1; + sock = rpki_create_socket(cache); + if (sock <= 0) + return -1; + return sock; +} + static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host, const char *port, const uint8_t preference) { @@ -942,16 +1166,18 @@ static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host, tcp_config->host = XSTRDUP(MTYPE_BGP_RPKI_CACHE, host); tcp_config->port = XSTRDUP(MTYPE_BGP_RPKI_CACHE, port); tcp_config->bindaddr = NULL; - + tcp_config->data = cache; + tcp_config->new_socket = rpki_get_socket; rtr_socket = create_rtr_socket(tr_socket); + cache->rpki_vrf = rpki_vrf; cache->type = TCP; cache->tr_socket = tr_socket; cache->tr_config.tcp_config = tcp_config; cache->rtr_socket = rtr_socket; cache->preference = preference; - ret = add_cache(cache, rpki_vrf); + ret = add_cache(cache); if (ret != SUCCESS) { free_cache(cache); } @@ -981,6 +1207,8 @@ static int add_ssh_cache(struct rpki_vrf *rpki_vrf, ssh_config->port = port; ssh_config->host = XSTRDUP(MTYPE_BGP_RPKI_CACHE, host); ssh_config->bindaddr = NULL; + ssh_config->data = cache; + ssh_config->new_socket = rpki_get_socket; ssh_config->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username); /* public key path is derived from private key path @@ -993,13 +1221,14 @@ static int add_ssh_cache(struct rpki_vrf *rpki_vrf, rtr_socket = create_rtr_socket(tr_socket); + cache->rpki_vrf = rpki_vrf; cache->type = SSH; cache->tr_socket = tr_socket; cache->tr_config.ssh_config = ssh_config; cache->rtr_socket = rtr_socket; cache->preference = preference; - ret = add_cache(cache, rpki_vrf); + ret = add_cache(cache); if (ret != SUCCESS) { free_cache(cache); } From 2224b36a30b49fe8bbd85d9b8eb2e42c8358448c Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 11:42:46 +0200 Subject: [PATCH 15/22] bgpd: rpki show commande equipped with vrfname parameter it is possible to dump rpki commands per vrf context. also, rpki start/stop commands are also appended with vrfname parameter. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 148 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 115 insertions(+), 33 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 841a6efbf9..0c23e9f535 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1386,18 +1386,29 @@ DEFUN_NOSH (no_rpki, DEFUN (bgp_rpki_start, bgp_rpki_start_cmd, - "rpki start", + "rpki start [vrf NAME]", RPKI_OUTPUT_STRING - "start rpki support\n") + "start rpki support\n" + VRF_CMD_HELP_STR) { struct list *cache_list = NULL; struct rpki_vrf *rpki_vrf; + int idx_vrf = 3; + struct vrf *vrf; + char *vrfname = NULL; - /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); - if (rpki_vrf) - cache_list = rpki_vrf->cache_list; - if (!rpki_vrf || !cache_list || listcount(cache_list) == 0) + if (argc == 4) { + vrf = vrf_lookup_by_name(argv[idx_vrf]->arg); + if (!vrf) + return CMD_SUCCESS; + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + rpki_vrf = find_rpki_vrf(vrfname); + if (!rpki_vrf) + return CMD_SUCCESS; + cache_list = rpki_vrf->cache_list; + if (!cache_list || listcount(cache_list) == 0) vty_out(vty, "Could not start rpki" " because no caches are configured\n"); @@ -1412,14 +1423,24 @@ DEFUN (bgp_rpki_start, DEFUN (bgp_rpki_stop, bgp_rpki_stop_cmd, - "rpki stop", + "rpki stop [vrf NAME]", RPKI_OUTPUT_STRING - "start rpki support\n") + "start rpki support\n" + VRF_CMD_HELP_STR) { + int idx_vrf = 3; + struct vrf *vrf; + char *vrfname = NULL; struct rpki_vrf *rpki_vrf; - /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); + if (argc == 4) { + vrf = vrf_lookup_by_name(argv[idx_vrf]->arg); + if (!vrf) + return CMD_SUCCESS; + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + rpki_vrf = find_rpki_vrf(vrfname); if (rpki_vrf && is_running(rpki_vrf)) stop(rpki_vrf); @@ -1689,17 +1710,28 @@ DEFPY (no_rpki_cache, DEFUN (show_rpki_prefix_table, show_rpki_prefix_table_cmd, - "show rpki prefix-table", + "show rpki prefix-table [vrf NAME]", 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" + VRF_CMD_HELP_STR) { struct listnode *cache_node; struct cache *cache; struct rpki_vrf *rpki_vrf; + int idx_vrf = 4; + struct vrf *vrf; + char *vrfname = NULL; - /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); + if (argc == 5) { + vrf = vrf_lookup_by_name(argv[idx_vrf]->arg); + if (!vrf) + return CMD_SUCCESS; + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrfname); if (!rpki_vrf) return CMD_SUCCESS; for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { @@ -1721,15 +1753,23 @@ DEFUN (show_rpki_prefix_table, } DEFPY(show_rpki_as_number, show_rpki_as_number_cmd, - "show rpki as-number (1-4294967295)$by_asn", + "show rpki as-number (1-4294967295)$by_asn [vrf NAME$vrfname]", SHOW_STR RPKI_OUTPUT_STRING "Lookup by ASN in prefix table\n" "AS Number\n") { struct rpki_vrf *rpki_vrf; + char *vrf_name = NULL; + struct vrf *vrf; + if (vrfname && !strmatch(vrfname, VRF_DEFAULT_NAME)) { + vrf = vrf_lookup_by_name(vrfname); + if (!vrf) + return CMD_SUCCESS; + vrf_name = vrf->name; + } /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); + rpki_vrf = find_rpki_vrf(vrf_name); if (!is_synchronized(rpki_vrf)) { vty_out(vty, "No Connection to RPKI cache server.\n"); @@ -1742,18 +1782,27 @@ DEFPY(show_rpki_as_number, show_rpki_as_number_cmd, DEFPY (show_rpki_prefix, show_rpki_prefix_cmd, - "show rpki prefix [(1-4294967295)$asn]", + "show rpki prefix [(1-4294967295)$asn] [vrf NAME$vrfname]", 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" + VRF_CMD_HELP_STR) { struct rpki_vrf *rpki_vrf; + struct vrf *vrf; + char *vrf_name = NULL; - /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); + if (vrfname && !strmatch(vrfname, VRF_DEFAULT_NAME)) { + vrf = vrf_lookup_by_name(vrfname); + if (!vrf) + return CMD_SUCCESS; + vrf_name = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrf_name); if (!rpki_vrf || !is_synchronized(rpki_vrf)) { vty_out(vty, "No Connection to RPKI cache server.\n"); @@ -1800,17 +1849,28 @@ DEFPY (show_rpki_prefix, DEFUN (show_rpki_cache_server, show_rpki_cache_server_cmd, - "show rpki cache-server", + "show rpki cache-server [vrf NAME]", SHOW_STR RPKI_OUTPUT_STRING - "SHOW configured cache server\n") + "SHOW configured cache server\n" + VRF_CMD_HELP_STR) { struct listnode *cache_node; struct cache *cache; struct rpki_vrf *rpki_vrf; + int idx_vrf = 4; + struct vrf *vrf; + char *vrfname = NULL; - /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); + if (argc == 5) { + vrf = vrf_lookup_by_name(argv[idx_vrf]->arg); + if (!vrf) + return CMD_SUCCESS; + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrfname); if (!rpki_vrf) return CMD_SUCCESS; @@ -1841,15 +1901,26 @@ DEFUN (show_rpki_cache_server, DEFUN (show_rpki_cache_connection, show_rpki_cache_connection_cmd, - "show rpki cache-connection", + "show rpki cache-connection [vrf NAME]", SHOW_STR RPKI_OUTPUT_STRING - "Show to which RPKI Cache Servers we have a connection\n") + "Show to which RPKI Cache Servers we have a connection\n" + VRF_CMD_HELP_STR) { struct rpki_vrf *rpki_vrf; + int idx_vrf = 4; + struct vrf *vrf; + char *vrfname = NULL; - /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); + if (argc == 5) { + vrf = vrf_lookup_by_name(argv[idx_vrf]->arg); + if (!vrf) + return CMD_SUCCESS; + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrfname); if (!rpki_vrf) return CMD_SUCCESS; @@ -1908,15 +1979,26 @@ DEFUN (show_rpki_cache_connection, DEFUN (show_rpki_configuration, show_rpki_configuration_cmd, - "show rpki configuration", + "show rpki configuration [vrf NAME]", SHOW_STR RPKI_OUTPUT_STRING - "Show RPKI configuration\n") + "Show RPKI configuration\n" + VRF_CMD_HELP_STR) { struct rpki_vrf *rpki_vrf; + int idx_vrf = 4; + struct vrf *vrf; + char *vrfname = NULL; - /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); + if (argc == 5) { + vrf = vrf_lookup_by_name(argv[idx_vrf]->arg); + if (!vrf) + return CMD_SUCCESS; + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrfname); if (!rpki_vrf) return CMD_SUCCESS; vty_out(vty, "rpki is %s", From 4a42034fa877dadbab0ab0675936fe6b32adcec7 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 14:13:57 +0200 Subject: [PATCH 16/22] bgpd: duplicate config commands into rpki-vrf subnode rpki vrf subnode is instantiated under the vrf subnode. It it to be noted that this commit contains a change in vtysh. Actually, the output of bgp daemon from show running-config is extracted in vtysh, and reengineered ( hence the vtysh_config.c change done). This permits having a subnode under vrf sub node. Also, add vrf node support to bgpd, as rpki command can not be found under vrf node. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 143 +++++++++++++++++++++++++++++++++++++------ lib/command.c | 3 + lib/command.h | 1 + vtysh/vtysh.c | 17 ++++- vtysh/vtysh.h | 2 +- vtysh/vtysh_config.c | 11 +++- 6 files changed, 154 insertions(+), 23 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 0c23e9f535..c9e01ddbf7 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -172,6 +172,16 @@ static struct cmd_node rpki_node = { .config_write = config_write, .node_exit = config_on_exit, }; + +static struct cmd_node rpki_vrf_node = { + .name = "rpki", + .node = RPKI_VRF_NODE, + .parent_node = VRF_NODE, + .prompt = "%s(config-vrf-rpki)# ", + .config_write = config_write, + .node_exit = config_on_exit, +}; + static const struct route_map_rule_cmd route_match_rpki_cmd = { "rpki", route_match, route_match_compile, route_match_free}; @@ -627,7 +637,7 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)), { struct rpki_vrf *rpki_vrf; const char *msg; - struct rtr_socket *rtr = rec.socket; + const struct rtr_socket *rtr = rec.socket; struct tr_socket *tr; const char *ident; int retval; @@ -1355,16 +1365,28 @@ DEFUN_NOSH (rpki, "Enable rpki and enter rpki configuration mode\n") { struct rpki_vrf *rpki_vrf; + char *vrfname = NULL; - vty->node = RPKI_NODE; + if (vty->node == CONFIG_NODE) + vty->node = RPKI_NODE; + else { + struct vrf *vrf = VTY_GET_CONTEXT(vrf); + + vty->node = RPKI_VRF_NODE; + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); + rpki_vrf = find_rpki_vrf(vrfname); if (!rpki_vrf) { - rpki_vrf = bgp_rpki_allocate(NULL); + rpki_vrf = bgp_rpki_allocate(vrfname); rpki_init_sync_socket(rpki_vrf); } - VTY_PUSH_CONTEXT(RPKI_NODE, rpki_vrf); + if (vty->node == RPKI_VRF_NODE) + VTY_PUSH_CONTEXT_SUB(vty->node, rpki_vrf); + else + VTY_PUSH_CONTEXT(vty->node, rpki_vrf); return CMD_SUCCESS; } @@ -1375,9 +1397,16 @@ DEFUN_NOSH (no_rpki, "Enable rpki and enter rpki configuration mode\n") { struct rpki_vrf *rpki_vrf; + char *vrfname = NULL; - /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); + if (vty->node == VRF_NODE) { + VTY_DECLVAR_CONTEXT(vrf, vrf); + + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrfname); if (rpki_vrf) bgp_rpki_finish(rpki_vrf); @@ -1454,7 +1483,12 @@ DEFPY (rpki_polling_period, "Set polling period\n" "Polling period value\n") { - VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); rpki_vrf->polling_period = pp; return CMD_SUCCESS; @@ -1467,7 +1501,12 @@ DEFUN (no_rpki_polling_period, RPKI_OUTPUT_STRING "Set polling period back to default\n") { - VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; return CMD_SUCCESS; @@ -1480,7 +1519,12 @@ DEFPY (rpki_expire_interval, "Set expire interval\n" "Expire interval value\n") { - VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); if ((unsigned int)tmp >= rpki_vrf->polling_period) { rpki_vrf->expire_interval = tmp; @@ -1498,7 +1542,12 @@ DEFUN (no_rpki_expire_interval, RPKI_OUTPUT_STRING "Set expire interval back to default\n") { - VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); rpki_vrf->expire_interval = rpki_vrf->polling_period * 2; return CMD_SUCCESS; @@ -1511,7 +1560,12 @@ DEFPY (rpki_retry_interval, "Set retry interval\n" "retry interval value\n") { - VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); rpki_vrf->retry_interval = tmp; return CMD_SUCCESS; @@ -1524,7 +1578,12 @@ DEFUN (no_rpki_retry_interval, RPKI_OUTPUT_STRING "Set retry interval back to default\n") { - VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; return CMD_SUCCESS; @@ -1612,8 +1671,12 @@ DEFPY (rpki_cache, struct listnode *cache_node; struct cache *current_cache; char *pub = NULL; + struct rpki_vrf *rpki_vrf; - VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); if (!rpki_vrf->cache_list) return CMD_WARNING; @@ -1680,8 +1743,12 @@ DEFPY (no_rpki_cache, { struct cache *cache_p; struct list *cache_list = NULL; + struct rpki_vrf *rpki_vrf; - VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); cache_list = rpki_vrf->cache_list; cache_p = find_cache(preference, cache_list); @@ -2016,8 +2083,12 @@ DEFUN (show_rpki_configuration, static int config_on_exit(struct vty *vty) { - VTY_DECLVAR_CONTEXT(rpki_vrf, rpki_vrf); + struct rpki_vrf *rpki_vrf; + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); reset(false, rpki_vrf); return 1; } @@ -2030,10 +2101,10 @@ DEFUN (rpki_reset, { struct rpki_vrf *rpki_vrf; - /* assume default vrf */ - rpki_vrf = find_rpki_vrf(NULL); - if (!rpki_vrf) - return CMD_SUCCESS; + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); return reset(true, rpki_vrf) == SUCCESS ? CMD_SUCCESS : CMD_WARNING; } @@ -2130,6 +2201,8 @@ static void install_cli_commands(void) // TODO: make config write work install_node(&rpki_node); install_default(RPKI_NODE); + install_node(&rpki_vrf_node); + install_default(RPKI_VRF_NODE); install_element(CONFIG_NODE, &rpki_cmd); install_element(CONFIG_NODE, &no_rpki_cmd); @@ -2163,6 +2236,36 @@ static void install_cli_commands(void) install_element(RPKI_NODE, &rpki_cache_cmd); install_element(RPKI_NODE, &no_rpki_cache_cmd); + /* RPKI_VRF_NODE commands */ + install_element(VRF_NODE, &rpki_cmd); + install_element(VRF_NODE, &no_rpki_cmd); + /* Install rpki reset command */ + install_element(RPKI_VRF_NODE, &rpki_reset_cmd); + + /* Install rpki polling period commands */ + install_element(RPKI_VRF_NODE, &rpki_polling_period_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_polling_period_cmd); + + /* Install rpki expire interval commands */ + install_element(RPKI_VRF_NODE, &rpki_expire_interval_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_expire_interval_cmd); + + /* Install rpki retry interval commands */ + install_element(RPKI_VRF_NODE, &rpki_retry_interval_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_retry_interval_cmd); + + /* Install rpki timeout commands */ + install_element(RPKI_VRF_NODE, &rpki_timeout_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_timeout_cmd); + + /* Install rpki synchronisation timeout commands */ + install_element(RPKI_VRF_NODE, &rpki_synchronisation_timeout_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_synchronisation_timeout_cmd); + + /* Install rpki cache commands */ + install_element(RPKI_VRF_NODE, &rpki_cache_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd); + /* Install show commands */ install_element(VIEW_NODE, &show_rpki_prefix_table_cmd); install_element(VIEW_NODE, &show_rpki_cache_connection_cmd); diff --git a/lib/command.c b/lib/command.c index 80b75d9b23..fc43cce189 100644 --- a/lib/command.c +++ b/lib/command.c @@ -841,6 +841,9 @@ enum node_type node_parent(enum node_type node) case BFD_PROFILE_NODE: ret = BFD_NODE; break; + case RPKI_VRF_NODE: + ret = VRF_NODE; + break; default: ret = CONFIG_NODE; break; diff --git a/lib/command.h b/lib/command.h index 21bb613540..9e0fc783c7 100644 --- a/lib/command.h +++ b/lib/command.h @@ -159,6 +159,7 @@ enum node_type { OPENFABRIC_NODE, /* OpenFabric router configuration node */ VRRP_NODE, /* VRRP node */ BMP_NODE, /* BMP config under router bgp */ + RPKI_VRF_NODE, /* RPKI node for VRF */ NODE_TYPE_MAX, /* maximum */ }; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 29e0842daf..aa9306aac9 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1478,6 +1478,13 @@ static struct cmd_node rpki_node = { .prompt = "%s(config-rpki)# ", }; +static struct cmd_node rpki_vrf_node = { + .name = "rpki", + .node = RPKI_VRF_NODE, + .parent_node = VRF_NODE, + .prompt = "%s(config-vrf-rpki)# ", +}; + #if HAVE_BFDD > 0 static struct cmd_node bfd_node = { .name = "bfd", @@ -1665,7 +1672,10 @@ DEFUNSH(VTYSH_BGPD, "rpki", "Enable rpki and enter rpki configuration mode\n") { - vty->node = RPKI_NODE; + if (vty->node == CONFIG_NODE) + vty->node = RPKI_NODE; + else + vty->node = RPKI_VRF_NODE; return CMD_SUCCESS; } @@ -3815,6 +3825,7 @@ void vtysh_init_vty(void) install_node(&vty_node); install_node(&rpki_node); install_node(&bmp_node); + install_node(&rpki_vrf_node); #if HAVE_BFDD > 0 install_node(&bfd_node); install_node(&bfd_peer_node); @@ -4059,9 +4070,13 @@ void vtysh_init_vty(void) install_element(BMP_NODE, &vtysh_end_all_cmd); install_element(CONFIG_NODE, &rpki_cmd); + install_element(VRF_NODE, &rpki_cmd); install_element(RPKI_NODE, &rpki_exit_cmd); install_element(RPKI_NODE, &rpki_quit_cmd); install_element(RPKI_NODE, &vtysh_end_all_cmd); + install_element(RPKI_VRF_NODE, &rpki_exit_cmd); + install_element(RPKI_VRF_NODE, &rpki_quit_cmd); + install_element(RPKI_VRF_NODE, &vtysh_end_all_cmd); /* EVPN commands */ install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index d0edbb2710..97ae8b4890 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -54,7 +54,7 @@ DECLARE_MGROUP(MVTYSH) #define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD|VTYSH_FABRICD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD -#define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_STATICD +#define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_STATICD|VTYSH_BGPD #define VTYSH_KEYS VTYSH_RIPD|VTYSH_EIGRPD /* Daemons who can process nexthop-group configs */ #define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 44ec08b61a..afc7a007e2 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -264,13 +264,22 @@ void vtysh_config_parse_line(void *arg, const char *line) config_add_line(config->line, line); } else if (!strncmp(line, " ip mroute", strlen(" ip mroute"))) { config_add_line_uniq_end(config->line, line); + } else if ((strncmp(line, " rpki", strlen(" rpki")) == 0) + && config->index == VRF_NODE) { + config_add_line(config->line, line); + config->index = RPKI_VRF_NODE; } else if (config->index == RMAP_NODE || config->index == INTERFACE_NODE || config->index == VTY_NODE || config->index == VRF_NODE || config->index == NH_GROUP_NODE) config_add_line_uniq(config->line, line); - else + else if (config->index == RPKI_VRF_NODE + && strncmp(line, " exit", + strlen(" exit")) == 0) { + config_add_line(config->line, line); + config->index = VRF_NODE; + } else config_add_line(config->line, line); } else config_add_line(config_top, line); From fd1be68353b7cf3077f6a2b905d73ec5355db644 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 16:37:14 +0200 Subject: [PATCH 17/22] bgpd: add hook for running-config per vrf rpki config rpki config can be displayed in the 'show running-config'. there is a fix to be done yet, this is related to the order of rpki per vrf configuration. actually, the output is not saveable in the running-config since the rpki commands are swapped. this prevents from running rpki config at startup. That commit also changes the identation, since rpki configure node was with one extra space. reducing this, and add the changes for vrf configuration too. Signed-off-by: Philippe Guibert --- bgpd/bgp_main.c | 23 ++++++++ bgpd/bgp_rpki.c | 143 +++++++++++++++++++++++++++++++----------------- bgpd/bgpd.h | 3 + 3 files changed, 118 insertions(+), 51 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index a5826527c8..ebf2328a71 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -61,6 +61,9 @@ #include "bgpd/bgp_network.h" #include "bgpd/bgp_errors.h" +DEFINE_HOOK(bgp_hook_config_write_vrf, (struct vty *vty, struct vrf *vrf), + (vty, vrf)) + #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" #endif @@ -362,10 +365,30 @@ static int bgp_vrf_disable(struct vrf *vrf) return 0; } +static int bgp_vrf_config_write(struct vty *vty) +{ + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (vrf->vrf_id == VRF_DEFAULT) { + vty_out(vty, "!\n"); + continue; + } + vty_out(vty, "vrf %s\n", vrf->name); + + hook_call(bgp_hook_config_write_vrf, vty, vrf); + + vty_out(vty, " exit-vrf\n!\n"); + } + + return 0; +} + static void bgp_vrf_init(void) { vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, bgp_vrf_delete, bgp_vrf_enable); + vrf_cmd_init(bgp_vrf_config_write, &bgpd_privs); } static void bgp_vrf_terminate(void) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index c9e01ddbf7..b4b210116e 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -70,6 +70,8 @@ DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group") #define RPKI_NOTFOUND 2 #define RPKI_INVALID 3 +#define STR_SEPARATOR 10 + #define POLLING_PERIOD_DEFAULT 3600 #define EXPIRE_INTERVAL_DEFAULT 7200 #define RETRY_INTERVAL_DEFAULT 600 @@ -120,6 +122,8 @@ struct rpki_vrf { static struct rpki_vrf *find_rpki_vrf(const char *vrfname); static int bgp_rpki_vrf_update(struct vrf *vrf, bool enabled); +static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf); +static int bgp_rpki_hook_write_vrf(struct vty *vty, struct vrf *vrf); static int bgp_rpki_write_debug(struct vty *vty, bool running); static int start(struct rpki_vrf *rpki_vrf); static void stop(struct rpki_vrf *rpki_vrf); @@ -784,6 +788,7 @@ static int bgp_rpki_module_init(void) hook_register(frr_early_fini, &bgp_rpki_fini); hook_register(bgp_hook_config_write_debug, &bgp_rpki_write_debug); hook_register(bgp_hook_vrf_update, &bgp_rpki_vrf_update); + hook_register(bgp_hook_config_write_vrf, &bgp_rpki_hook_write_vrf); return 0; } @@ -1298,65 +1303,101 @@ static int bgp_rpki_write_debug(struct vty *vty, bool running) return 0; } -static int config_write(struct vty *vty) +static int bgp_rpki_hook_write_vrf(struct vty *vty, struct vrf *vrf) +{ + int ret; + + ret = bgp_rpki_write_vrf(vty, vrf); + if (ret == ERROR) + return 0; + return ret; +} + +static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf) { struct listnode *cache_node; struct cache *cache; - struct rpki_vrf *rpki_vrf; - struct list *cache_list; + struct rpki_vrf *rpki_vrf = NULL; + char sep[STR_SEPARATOR]; + vrf_id_t vrf_id = VRF_DEFAULT; + char *host_key_pub = NULL; + int len_host_key_pub; - rpki_vrf = find_rpki_vrf(NULL); + if (!vrf) { + rpki_vrf = find_rpki_vrf(NULL); + snprintf(sep, sizeof(sep), "%s", ""); + } else if (vrf->vrf_id != VRF_DEFAULT) { + rpki_vrf = find_rpki_vrf(vrf->name); + snprintf(sep, sizeof(sep), "%s", " "); + vrf_id = vrf->vrf_id; + } else + return ERROR; if (!rpki_vrf) return ERROR; - if (config_changed(rpki_vrf)) { - vty_out(vty, "!\n"); - vty_out(vty, "rpki\n"); - if (rpki_vrf->polling_period != POLLING_PERIOD_DEFAULT) - vty_out(vty, " rpki polling_period %d\n", - rpki_vrf->polling_period); - if (rpki_vrf->retry_interval != RETRY_INTERVAL_DEFAULT) - vty_out(vty, " rpki retry-interval %d\n", - rpki_vrf->retry_interval); - if (rpki_vrf->expire_interval != EXPIRE_INTERVAL_DEFAULT) - vty_out(vty, " rpki expire_interval %d\n", - rpki_vrf->expire_interval); - - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { - switch (cache->type) { - struct tr_tcp_config *tcp_config; -#if defined(FOUND_SSH) - struct tr_ssh_config *ssh_config; -#endif - case TCP: - tcp_config = cache->tr_config.tcp_config; - vty_out(vty, " rpki cache %s %s ", - tcp_config->host, tcp_config->port); - break; -#if defined(FOUND_SSH) - case SSH: - ssh_config = cache->tr_config.ssh_config; - vty_out(vty, " rpki cache %s %u %s %s %s ", - ssh_config->host, - ssh_config->port, - ssh_config->username, - ssh_config->client_privkey_path, - ssh_config->server_hostkey_path != NULL - ? ssh_config - ->server_hostkey_path - : ""); - break; -#endif - default: - break; - } - - vty_out(vty, "preference %hhu\n", cache->preference); - } - vty_out(vty, " exit\n"); - return 1; - } else { + if (!config_changed(rpki_vrf)) return 0; + if (vrf_id == VRF_DEFAULT) + vty_out(vty, "%s!\n", sep); + vty_out(vty, "%srpki\n", sep); + if (rpki_vrf->polling_period != POLLING_PERIOD_DEFAULT) + vty_out(vty, "%s rpki polling_period %d\n", + sep, rpki_vrf->polling_period); + if (rpki_vrf->retry_interval != RETRY_INTERVAL_DEFAULT) + vty_out(vty, "%s rpki retry-interval %d\n", + sep, rpki_vrf->retry_interval); + if (rpki_vrf->expire_interval != EXPIRE_INTERVAL_DEFAULT) + vty_out(vty, "%s rpki expire_interval %d\n", + sep, rpki_vrf->expire_interval); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { + switch (cache->type) { + struct tr_tcp_config *tcp_config; +#if defined(FOUND_SSH) + struct tr_ssh_config *ssh_config; +#endif + case TCP: + tcp_config = cache->tr_config.tcp_config; + vty_out(vty, "%s rpki cache %s %s ", sep, + tcp_config->host, tcp_config->port); + break; +#if defined(FOUND_SSH) + case SSH: + ssh_config = cache->tr_config.ssh_config; + if (ssh_config->client_privkey_path) { + len_host_key_pub = strlen(ssh_config->client_privkey_path) + 4 /* strlen(".pub")*/ + 1; + host_key_pub = XCALLOC(MTYPE_BGP_RPKI_CACHE, len_host_key_pub); + snprintf(host_key_pub, len_host_key_pub, "%s.pub", ssh_config->client_privkey_path); + } + vty_out(vty, "%s rpki cache %s %u %s %s %s %s ", + sep, ssh_config->host, + ssh_config->port, + ssh_config->username, + ssh_config->client_privkey_path, + host_key_pub ? host_key_pub : "", + ssh_config->server_hostkey_path != NULL + ? ssh_config + ->server_hostkey_path + : ""); + if (host_key_pub) { + XFREE(MTYPE_BGP_RPKI_CACHE, host_key_pub); + host_key_pub = NULL; + } + break; +#endif + default: + break; + } + + vty_out(vty, "preference %hhu\n", cache->preference); } + vty_out(vty, "%s exit\n%s", sep, + vrf_id == VRF_DEFAULT ? "!\n" : ""); + return 1; +} + +static int config_write(struct vty *vty) +{ + return bgp_rpki_write_vrf(vty, NULL); } DEFUN_NOSH (rpki, diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d0ba87e687..8b4f0315d8 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -43,6 +43,9 @@ #include "bgp_labelpool.h" #include "bgp_addpath_types.h" +DECLARE_HOOK(bgp_hook_config_write_vrf, (struct vty *vty, struct vrf *vrf), + (vty, vrf)) + #define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */ #define BGP_PEER_MAX_HASH_SIZE 16384 From 1f8d139ffd22917016c7257c2326a29c7fd14ca0 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 16:39:24 +0200 Subject: [PATCH 18/22] bgpd: no rpki command available this command permits to stop and flush the rpki contexts for a specific vrf. Signed-off-by: Philippe Guibert --- vtysh/vtysh.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index aa9306aac9..f1c82d3182 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1666,6 +1666,16 @@ DEFUNSH(VTYSH_BGPD, address_family_ipv6_labeled_unicast, return CMD_SUCCESS; } +DEFUNSH(VTYSH_BGPD, + no_rpki, + no_rpki_cmd, + "no rpki", + NO_STR + "rpki\n") +{ + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_BGPD, rpki, rpki_cmd, @@ -4070,7 +4080,9 @@ void vtysh_init_vty(void) install_element(BMP_NODE, &vtysh_end_all_cmd); install_element(CONFIG_NODE, &rpki_cmd); + install_element(CONFIG_NODE, &no_rpki_cmd); install_element(VRF_NODE, &rpki_cmd); + install_element(VRF_NODE, &no_rpki_cmd); install_element(RPKI_NODE, &rpki_exit_cmd); install_element(RPKI_NODE, &rpki_quit_cmd); install_element(RPKI_NODE, &vtysh_end_all_cmd); From 0feaf6478530e2244a1bc6ab50b3d7b7f447410c Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 3 Feb 2020 13:36:58 +0100 Subject: [PATCH 19/22] bgpd: validation of bgp routes with rpki done on according vrf the validation of rpki routes will impact the matching bgp instance. Until now, the rpki was triggering validation of all bgp entries. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index b4b210116e..608542e87f 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -159,7 +159,7 @@ static enum route_map_cmd_result_t route_match(void *rule, void *object); static void *route_match_compile(const char *arg); static void revalidate_bgp_node(struct bgp_dest *dest, afi_t afi, safi_t safi); -static void revalidate_all_routes(void); +static void revalidate_all_routes(struct rpki_vrf *rpki_vrf); static int rpki_debug_conf, rpki_debug_term; @@ -518,6 +518,7 @@ static int bgpd_sync_callback(struct thread *thread) struct prefix *prefix; struct pfx_record rec; struct rpki_vrf *rpki_vrf = THREAD_ARG(thread); + struct vrf *vrf = NULL; thread_add_read(bm->master, bgpd_sync_callback, rpki_vrf, rpki_vrf->rpki_sync_socket_bgpd, NULL); @@ -531,7 +532,7 @@ static int bgpd_sync_callback(struct thread *thread) atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 0, memory_order_seq_cst); - revalidate_all_routes(); + revalidate_all_routes(rpki_vrf); return 0; } @@ -546,10 +547,24 @@ static int bgpd_sync_callback(struct thread *thread) afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; + if (rpki_vrf->vrfname) { + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + if (!vrf) { + zlog_err("%s(): vrf for rpki %s not found", + __func__, rpki_vrf->vrfname); + return 0; + } + } + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { struct peer *peer; struct listnode *peer_listnode; + if (!vrf && bgp->vrf_id != VRF_DEFAULT) + continue; + if (vrf && bgp->vrf_id != vrf->vrf_id) + continue; + for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) { safi_t safi; @@ -608,15 +623,30 @@ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, } } -static void revalidate_all_routes(void) +static void revalidate_all_routes(struct rpki_vrf *rpki_vrf) { struct bgp *bgp; struct listnode *node; + struct vrf *vrf = NULL; + + if (rpki_vrf->vrfname) { + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + if (!vrf) { + zlog_err("%s(): vrf for rpki %s not found", + __func__, rpki_vrf->vrfname); + return; + } + } for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { struct peer *peer; struct listnode *peer_listnode; + if (!vrf && bgp->vrf_id != VRF_DEFAULT) + continue; + if (vrf && bgp->vrf_id != vrf->vrf_id) + continue; + for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) { for (size_t i = 0; i < 2; i++) { From 9dcfdf2c4fedb1d800746f8888a46760099aaa37 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 3 Feb 2020 13:41:09 +0100 Subject: [PATCH 20/22] bgpd: add vrf name on some logs from rpki this extra trace will help to understand which rpki context is triggered. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 608542e87f..55bc04e5ce 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -849,7 +849,7 @@ static int start(struct rpki_vrf *rpki_vrf) return ERROR; } - RPKI_DEBUG("Init rtr_mgr."); + RPKI_DEBUG("Init rtr_mgr (%s).", vrf->name); int groups_len = listcount(cache_list); struct rtr_mgr_group *groups = get_groups(rpki_vrf->cache_list); @@ -859,14 +859,14 @@ static int start(struct rpki_vrf *rpki_vrf) rpki_vrf->retry_interval, rpki_update_cb_sync_rtr, NULL, NULL, NULL); if (ret == RTR_ERROR) { - RPKI_DEBUG("Init rtr_mgr failed."); + RPKI_DEBUG("Init rtr_mgr failed (%s).", vrf->name); return ERROR; } - RPKI_DEBUG("Starting rtr_mgr."); + RPKI_DEBUG("Starting rtr_mgr (%s).", vrf->name); ret = rtr_mgr_start(rpki_vrf->rtr_config); if (ret == RTR_ERROR) { - RPKI_DEBUG("Starting rtr_mgr failed."); + RPKI_DEBUG("Starting rtr_mgr failed (%s).", vrf->name); rtr_mgr_free(rpki_vrf->rtr_config); return ERROR; } From 0ba6afa5fc13c74d024006cb7fe673064a7731c0 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Sep 2019 16:52:45 +0200 Subject: [PATCH 21/22] doc: add rpki information for rpki per vrf commands rpki per vrf documentation is being added. Signed-off-by: Philippe Guibert --- doc/user/rpki.rst | 82 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index f8ec98c964..77cadb6ae7 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -60,8 +60,9 @@ Enabling RPKI This command enables the RPKI configuration mode. Most commands that start with *rpki* can only be used in this mode. - When it is used in a telnet session, leaving of this mode cause rpki to be - initialized. + This command is available either in *configure node* for default *vrf* or + in *vrf node* for specific *vrf*. When it is used in a telnet session, + leaving of this mode cause rpki to be initialized. Executing this command alone does not activate prefix validation. You need to configure at least one reachable cache server. See section @@ -91,6 +92,9 @@ Examples of the error:: router(config)# rpki % [BGP] Unknown command: rpki + router(config-vrf)# rpki + % [BGP] Unknown command: rpki + Note that the RPKI commands will be available in vtysh when running ``find rpki`` regardless of whether the module is loaded. @@ -99,7 +103,14 @@ Note that the RPKI commands will be available in vtysh when running Configuring RPKI/RTR Cache Servers ---------------------------------- -The following commands are independent of a specific cache server. +RPKI/RTR can be configured independently, either in configure node, or in *vrf* +sub context. If configured in configure node, the core *bgp* instance of default +*vrf* is impacted by the configuration. + +Each RPKI/RTR context is mapped to a *vrf* and can be made up of a specific list +of cache-servers, and specific settings. + +The following commands are available for independent of a specific cache server. .. index:: rpki polling_period (1-3600) .. clicmd:: rpki polling_period (1-3600) @@ -200,27 +211,27 @@ Debugging Displaying RPKI --------------- -.. index:: show rpki prefix [(1-4294967295)] -.. clicmd:: show rpki prefix [(1-4294967295)] +.. index:: show rpki prefix [(1-4294967295)] [vrf NAME] +.. clicmd:: show rpki prefix [(1-4294967295)] [vrf NAME] Display validated prefixes received from the cache servers filtered by the specified prefix. -.. index:: show rpki as-number ASN -.. clicmd:: show rpki as-number ASN +.. index:: show rpki as-number ASN [vrf NAME] +.. clicmd:: show rpki as-number ASN [vrf NAME] Display validated prefixes received from the cache servers filtered by ASN. -.. index:: show rpki prefix-table -.. clicmd:: show rpki prefix-table +.. index:: show rpki prefix-table [vrf NAME] +.. clicmd:: show rpki prefix-table [vrf NAME] 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, the router validates BGP Updates. -.. index:: show rpki cache-connection -.. clicmd:: show rpki cache-connection +.. index:: show rpki cache-connection [vrf NAME] +.. clicmd:: show rpki cache-connection [vrf NAME] Display all configured cache servers, whether active or not. @@ -271,5 +282,54 @@ RPKI Configuration Example route-map rpki permit 40 ! +RPKI Configuration Example with VRF +----------------------------------- + +.. code-block:: frr + + hostname bgpd1 + password zebra + ! log stdout + debug bgp updates + debug bgp keepalives + debug rpki + ! + vrf vrf_connect + rpki + rpki polling_period 1000 + rpki timeout 10 + ! SSH Example: + rpki cache example.com 22 rtr-ssh ./ssh_key/id_rsa ./ssh_key/id_rsa.pub preference 1 + ! TCP Example: + rpki cache rpki-validator.realmv6.org 8282 preference 2 + exit + ! + exit-vrf + router bgp 60001 vrf vrf_connect + bgp router-id 141.22.28.223 + network 192.168.0.0/16 + neighbor 123.123.123.0 remote-as 60002 + neighbor 123.123.123.0 route-map rpki in + ! + address-family ipv6 + neighbor 123.123.123.0 activate + neighbor 123.123.123.0 route-map rpki in + exit-address-family + ! + route-map rpki permit 10 + match rpki invalid + set local-preference 10 + ! + route-map rpki permit 20 + match rpki notfound + set local-preference 20 + ! + route-map rpki permit 30 + match rpki valid + set local-preference 30 + ! + route-map rpki permit 40 + ! + .. [Securing-BGP] Geoff Huston, Randy Bush: Securing BGP, In: The Internet Protocol Journal, Volume 14, No. 2, 2011. .. [Resource-Certification] Geoff Huston: Resource Certification, In: The Internet Protocol Journal, Volume 12, No.1, 2009. From 76ddd87e88089e40b0de868c456e2dd086839911 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 29 Jun 2020 18:14:22 +0200 Subject: [PATCH 22/22] bgpd: change rtr_is_ integer to bool format bool format suits better for rtr_is_running and rtr_is_stopped values. Signed-off-by: Philippe Guibert --- bgpd/bgp_rpki.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 55bc04e5ce..4e0642dce2 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -108,8 +108,8 @@ struct rpki_for_each_record_arg { struct rpki_vrf { struct rtr_mgr_config *rtr_config; struct list *cache_list; - int rtr_is_running; - int rtr_is_stopping; + bool rtr_is_running; + bool rtr_is_stopping; _Atomic int rtr_update_overflow; unsigned int polling_period; unsigned int expire_interval; @@ -755,8 +755,8 @@ static struct rpki_vrf *bgp_rpki_allocate(const char *vrfname) rpki_vrf = XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct rpki_vrf)); - rpki_vrf->rtr_is_running = 0; - rpki_vrf->rtr_is_stopping = 0; + rpki_vrf->rtr_is_running = false; + rpki_vrf->rtr_is_stopping = false; rpki_vrf->cache_list = list_new(); rpki_vrf->cache_list->del = (void (*)(void *)) & free_cache; rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; @@ -830,7 +830,7 @@ static int start(struct rpki_vrf *rpki_vrf) struct vrf *vrf; cache_list = rpki_vrf->cache_list; - rpki_vrf->rtr_is_stopping = 0; + rpki_vrf->rtr_is_stopping = false; rpki_vrf->rtr_update_overflow = 0; if (!cache_list || list_isempty(cache_list)) { @@ -870,7 +870,7 @@ static int start(struct rpki_vrf *rpki_vrf) rtr_mgr_free(rpki_vrf->rtr_config); return ERROR; } - rpki_vrf->rtr_is_running = 1; + rpki_vrf->rtr_is_running = true; XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups); @@ -879,11 +879,11 @@ static int start(struct rpki_vrf *rpki_vrf) static void stop(struct rpki_vrf *rpki_vrf) { - rpki_vrf->rtr_is_stopping = 1; + rpki_vrf->rtr_is_stopping = true; if (rpki_vrf->rtr_is_running) { rtr_mgr_stop(rpki_vrf->rtr_config); rtr_mgr_free(rpki_vrf->rtr_config); - rpki_vrf->rtr_is_running = 0; + rpki_vrf->rtr_is_running = false; } }