summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDonatas Abraitis <donatas@opensourcerouting.org>2024-01-22 15:16:34 +0100
committerGitHub <noreply@github.com>2024-01-22 15:16:34 +0100
commit20ec72d7ca84c38894ac8799c4f86bc0fe914a3d (patch)
tree6c334245401005892300049742ce31930ba2f3ec
parentMerge pull request #15176 from LabNConsulting/chopps/mgmtd-northbound-fixes (diff)
parenttopotests: add vrf test to bgp_rpki_topo1 (diff)
downloadfrr-20ec72d7ca84c38894ac8799c4f86bc0fe914a3d.tar.xz
frr-20ec72d7ca84c38894ac8799c4f86bc0fe914a3d.zip
Merge pull request #15052 from louis-6wind/rpki-vrf-92
bgpd: add VRF support to RPKI
-rw-r--r--bgpd/bgp_main.c28
-rw-r--r--bgpd/bgp_rpki.c1161
-rw-r--r--bgpd/bgp_rpki.h2
-rw-r--r--bgpd/bgpd.h5
-rw-r--r--doc/user/rpki.rst80
-rw-r--r--lib/command.h1
-rw-r--r--tests/topotests/bgp_rpki_topo1/r2/staticd.conf4
-rw-r--r--tests/topotests/bgp_rpki_topo1/r2/zebra.conf3
-rw-r--r--tests/topotests/bgp_rpki_topo1/r3/bgpd.conf14
l---------tests/topotests/bgp_rpki_topo1/r3/rtrd.py1
-rw-r--r--tests/topotests/bgp_rpki_topo1/r3/staticd.conf1
l---------tests/topotests/bgp_rpki_topo1/r3/vrps.csv1
-rw-r--r--tests/topotests/bgp_rpki_topo1/r3/zebra.conf5
-rw-r--r--tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py147
-rw-r--r--vtysh/vtysh.c19
-rw-r--r--vtysh/vtysh.h2
-rw-r--r--vtysh/vtysh_config.c11
17 files changed, 1221 insertions, 264 deletions
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index e8d5a0307..1666d654c 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -51,10 +51,16 @@
#include "bgpd/bgp_routemap_nb.h"
#include "bgpd/bgp_community_alias.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
+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' },
@@ -287,6 +293,7 @@ static int bgp_vrf_enable(struct vrf *vrf)
bgp_handle_socket(bgp, vrf, old_vrf_id, true);
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_zebra_vrf_sid_update(bgp, AFI_IP);
@@ -333,15 +340,36 @@ static int bgp_vrf_disable(struct vrf *vrf)
* "down". */
bgp_instance_down(bgp);
bgp_vrf_unlink(bgp, vrf);
+ hook_call(bgp_hook_vrf_update, vrf, false);
}
/* Note: This is a callback, the VRF will be deleted by the caller. */
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);
+ vrf_cmd_init(bgp_vrf_config_write);
}
static void bgp_vrf_terminate(void)
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 78083a83a..219cb2998 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -44,18 +44,19 @@
#include "bgpd/bgp_rpki_clippy.c"
+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");
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_RTRLIB, "BGP RPKI RTRLib");
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_REVALIDATE, "BGP RPKI Revalidation");
+#define STR_SEPARATOR 10
+
#define POLLING_PERIOD_DEFAULT 3600
#define EXPIRE_INTERVAL_DEFAULT 7200
#define RETRY_INTERVAL_DEFAULT 600
#define BGP_RPKI_CACHE_SERVER_SYNC_RETRY_TIMEOUT 3
-static struct event *t_rpki_sync;
-
#define RPKI_DEBUG(...) \
if (rpki_debug_conf || rpki_debug_term) { \
zlog_debug("RPKI: " __VA_ARGS__); \
@@ -77,6 +78,7 @@ struct cache {
} tr_config;
struct rtr_socket *rtr_socket;
uint8_t preference;
+ struct rpki_vrf *rpki_vrf;
};
enum return_values { SUCCESS = 0, ERROR = -1 };
@@ -89,33 +91,59 @@ struct rpki_for_each_record_arg {
enum asnotation_mode asnotation;
};
+struct rpki_vrf {
+ struct rtr_mgr_config *rtr_config;
+ struct list *cache_list;
+ bool rtr_is_running;
+ bool rtr_is_stopping;
+ bool rtr_is_synced;
+ _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;
+ struct event *t_rpki_sync;
+
+ 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_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(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, json_object *json);
+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,
+ json_object *json, bool count_only);
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,
- const char *username, const char *client_privkey_path,
+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 *server_pubkey_path,
const uint8_t preference, const char *bindaddr);
#endif
static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket);
-static struct cache *find_cache(const uint8_t preference);
-static void rpki_delete_all_cache_nodes(void);
-static int add_tcp_cache(const char *host, const char *port,
- const uint8_t preference, const char *bindaddr);
+static struct cache *find_cache(const uint8_t preference,
+ struct list *cache_list);
+static void rpki_delete_all_cache_nodes(struct rpki_vrf *rpki_vrf);
+static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host,
+ const char *port, const uint8_t preference,
+ const char *bindaddr);
static void print_record(const struct pfx_record *record, struct vty *vty,
json_object *json, enum asnotation_mode asnotation);
-static bool is_synchronized(void);
-static bool is_running(void);
-static bool is_stopping(void);
+static bool is_synchronized(struct rpki_vrf *rpki_vrf);
+static bool is_running(struct rpki_vrf *rpki_vrf);
+static bool is_stopping(struct rpki_vrf *rpki_vrf);
static void route_match_free(void *rule);
static enum route_map_cmd_result_t route_match(void *rule,
const struct prefix *prefix,
@@ -123,20 +151,14 @@ 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 struct rtr_mgr_config *rtr_config;
-static struct list *cache_list;
-static bool rtr_is_running;
-static bool rtr_is_stopping;
-static bool rtr_is_synced;
-static _Atomic int rtr_update_overflow;
+static void revalidate_all_routes(struct rpki_vrf *rpki_vrf);
+
static bool 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",
@@ -146,6 +168,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 = NULL,
+ .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};
@@ -253,11 +285,142 @@ 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 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 : <HOST>:<PORT>
+ * ssh identifier : <user>@<HOST>:<PORT>
+ */
+static struct rpki_vrf *find_rpki_vrf_from_ident(const char *ident)
+{
+#if defined(FOUND_SSH)
+ struct tr_ssh_config *ssh_config;
+#endif
+ struct tr_tcp_config *tcp_config;
+ struct listnode *rpki_vrf_nnode;
+ unsigned int cache_port, port;
+ struct listnode *cache_node;
+ struct rpki_vrf *rpki_vrf;
+ struct cache *cache;
+ bool is_tcp = true;
+ size_t host_len;
+ char *endptr;
+ char *host;
+ char *ptr;
+ char *buf;
+
+ /* extract the <SOCKET> */
+ 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)
+#if defined(FOUND_SSH)
+ || (cache->type == SSH && is_tcp)
+#endif
+ )
+ continue;
+
+ if (is_tcp) {
+ tcp_config = cache->tr_config.tcp_config;
+ cache_port = atoi(tcp_config->port);
+ if (cache_port != port)
+ continue;
+ if (strlen(tcp_config->host) != strlen(host))
+ continue;
+ if (memcmp(tcp_config->host, host, host_len) ==
+ 0)
+ break;
+ }
+#if defined(FOUND_SSH)
+ else {
+ ssh_config = cache->tr_config.ssh_config;
+ if (port != ssh_config->port)
+ continue;
+ if (strmatch(ssh_config->host, host))
+ break;
+ }
+#endif
+ }
+ 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;
+ struct rpki_vrf *rpki_vrf;
+
+ for (ALL_LIST_ELEMENTS_RO(rpki_vrf_list, rpki_vrf_nnode, rpki_vrf)) {
+ if (!vrfname && !rpki_vrf->vrfname)
+ /* rpki_vrf struct of the default VRF */
+ return rpki_vrf;
+ if (vrfname && rpki_vrf->vrfname &&
+ strmatch(vrfname, rpki_vrf->vrfname))
+ 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;
@@ -265,14 +428,15 @@ static struct cache *find_cache(const uint8_t preference)
return NULL;
}
-static void rpki_delete_all_cache_nodes(void)
+static void rpki_delete_all_cache_nodes(struct rpki_vrf *rpki_vrf)
{
struct listnode *cache_node, *cache_next;
struct cache *cache;
- for (ALL_LIST_ELEMENTS(cache_list, cache_node, cache_next, cache)) {
- rtr_mgr_remove_group(rtr_config, cache->preference);
- listnode_delete(cache_list, cache);
+ for (ALL_LIST_ELEMENTS(rpki_vrf->cache_list, cache_node, cache_next,
+ cache)) {
+ rtr_mgr_remove_group(rpki_vrf->rtr_config, cache->preference);
+ listnode_delete(rpki_vrf->cache_list, cache);
}
}
@@ -322,7 +486,14 @@ static void print_record_cb(const struct pfx_record *record, void *data)
print_record(record, vty, arg->json, arg->asnotation);
}
-static struct rtr_mgr_group *get_groups(void)
+static void count_record_cb(const struct pfx_record *record, void *data)
+{
+ struct rpki_for_each_record_arg *arg = data;
+
+ (*arg->prefix_amount)++;
+}
+
+static struct rtr_mgr_group *get_groups(struct list *cache_list)
{
struct listnode *cache_node;
struct rtr_mgr_group *rtr_mgr_groups;
@@ -351,19 +522,19 @@ static struct rtr_mgr_group *get_groups(void)
return rtr_mgr_groups;
}
-inline bool is_synchronized(void)
+inline bool is_synchronized(struct rpki_vrf *rpki_vrf)
{
- return rtr_is_synced;
+ return rpki_vrf->rtr_is_synced;
}
-inline bool is_running(void)
+inline bool is_running(struct rpki_vrf *rpki_vrf)
{
- return rtr_is_running;
+ return rpki_vrf->rtr_is_running;
}
-inline bool is_stopping(void)
+inline bool is_stopping(struct rpki_vrf *rpki_vrf)
{
- return rtr_is_stopping;
+ return rpki_vrf->rtr_is_stopping;
}
static void pfx_record_to_prefix(struct pfx_record *record,
@@ -415,23 +586,26 @@ static void bgpd_sync_callback(struct event *thread)
struct listnode *node;
struct prefix prefix;
struct pfx_record rec;
+ struct rpki_vrf *rpki_vrf = EVENT_ARG(thread);
+ struct vrf *vrf = NULL;
- event_add_read(bm->master, bgpd_sync_callback, NULL,
- rpki_sync_socket_bgpd, NULL);
+ event_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();
+ revalidate_all_routes(rpki_vrf);
return;
}
- int retval =
- read(rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record));
+ int retval = 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;
@@ -440,9 +614,23 @@ static void bgpd_sync_callback(struct event *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;
+ }
+ }
+
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
safi_t safi;
+ if (!vrf && bgp->vrf_id != VRF_DEFAULT)
+ continue;
+ if (vrf && bgp->vrf_id != vrf->vrf_id)
+ continue;
+
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
struct bgp_table *table = bgp->rib[afi][safi];
struct rpki_revalidate_prefix *rrp;
@@ -508,15 +696,30 @@ static void bgp_rpki_revalidate_peer(struct event *thread)
XFREE(MTYPE_BGP_RPKI_REVALIDATE, rvp);
}
-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)) {
afi_t afi;
safi_t safi;
@@ -549,21 +752,49 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)),
const struct pfx_record rec,
const bool added __attribute__((unused)))
{
- if (is_stopping() ||
- atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst))
+ struct rpki_vrf *rpki_vrf;
+ const char *msg;
+ const struct rtr_socket *rtr = rec.socket;
+ const char *ident;
+
+ if (!rtr) {
+ msg = "could not find rtr_socket from cb_sync_rtr";
+ goto err;
+ }
+ if (!rtr->tr_socket) {
+ msg = "could not find tr_socket from cb_sync_rtr";
+ goto err;
+ }
+ ident = rtr->tr_socket->ident_fp(rtr->tr_socket->socket);
+ if (!ident) {
+ msg = "could not find ident from cb_sync_rtr";
+ goto err;
+ }
+ rpki_vrf = find_rpki_vrf_from_ident(ident);
+ if (!rpki_vrf) {
+ msg = "could not find rpki_vrf";
+ goto err;
+ }
+
+ if (is_stopping(rpki_vrf) ||
+ 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));
+ int retval = 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;
@@ -573,22 +804,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;
}
- event_add_read(bm->master, bgpd_sync_callback, NULL,
- rpki_sync_socket_bgpd, NULL);
+ event_add_read(bm->master, bgpd_sync_callback, rpki_vrf,
+ rpki_vrf->rpki_sync_socket_bgpd, NULL);
return;
@@ -598,32 +829,57 @@ err:
}
+static struct rpki_vrf *bgp_rpki_allocate(const char *vrfname)
+{
+ struct rpki_vrf *rpki_vrf;
+
+ /* initialise default vrf cache list */
+ rpki_vrf = XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct rpki_vrf));
+
+ 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 event_loop *master)
{
rpki_debug_conf = false;
rpki_debug_term = false;
- rtr_is_running = false;
- rtr_is_stopping = false;
- rtr_is_synced = false;
- cache_list = list_new();
- cache_list->del = (void (*)(void *)) & free_cache;
+ rpki_vrf_list = list_new();
- polling_period = POLLING_PERIOD_DEFAULT;
- expire_interval = EXPIRE_INTERVAL_DEFAULT;
- retry_interval = RETRY_INTERVAL_DEFAULT;
install_cli_commands();
- rpki_init_sync_socket();
+
return 0;
}
static int bgp_rpki_fini(void)
{
- stop();
- list_delete(&cache_list);
+ struct listnode *node, *nnode;
+ struct rpki_vrf *rpki_vrf;
+
+ for (ALL_LIST_ELEMENTS(rpki_vrf_list, node, nnode, rpki_vrf)) {
+ stop(rpki_vrf);
+ list_delete(&rpki_vrf->cache_list);
- close(rpki_sync_socket_rtr);
- close(rpki_sync_socket_bgpd);
+ 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);
+ }
return 0;
}
@@ -636,103 +892,130 @@ 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);
+ hook_register(bgp_hook_config_write_vrf, &bgp_rpki_hook_write_vrf);
return 0;
}
static void sync_expired(struct event *thread)
{
- if (!rtr_mgr_conf_in_sync(rtr_config)) {
+ struct rpki_vrf *rpki_vrf = EVENT_ARG(thread);
+
+ if (!rtr_mgr_conf_in_sync(rpki_vrf->rtr_config)) {
RPKI_DEBUG("rtr_mgr is not synced, retrying.");
- event_add_timer(bm->master, sync_expired, NULL,
+ event_add_timer(bm->master, sync_expired, rpki_vrf,
BGP_RPKI_CACHE_SERVER_SYNC_RETRY_TIMEOUT,
- &t_rpki_sync);
+ &rpki_vrf->t_rpki_sync);
return;
}
RPKI_DEBUG("rtr_mgr sync is done.");
- rtr_is_synced = true;
+ rpki_vrf->rtr_is_synced = true;
}
-static int start(void)
+static int start(struct rpki_vrf *rpki_vrf)
{
+ struct list *cache_list = NULL;
+ struct vrf *vrf;
int ret;
- rtr_is_stopping = false;
- rtr_is_synced = false;
- rtr_update_overflow = 0;
+ rpki_vrf->rtr_is_stopping = false;
+ rpki_vrf->rtr_is_synced = false;
+ rpki_vrf->rtr_update_overflow = 0;
+ cache_list = rpki_vrf->cache_list;
+ rpki_vrf->rtr_update_overflow = 0;
- if (list_isempty(cache_list)) {
+ 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.");
+
+ 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 (%s).", vrf->name);
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.");
+ RPKI_DEBUG("Init rtr_mgr failed (%s).", vrf->name);
return ERROR;
}
- RPKI_DEBUG("Starting rtr_mgr.");
- ret = rtr_mgr_start(rtr_config);
+ 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.");
- rtr_mgr_free(rtr_config);
+ RPKI_DEBUG("Starting rtr_mgr failed (%s).", vrf->name);
+ rtr_mgr_free(rpki_vrf->rtr_config);
return ERROR;
}
- event_add_timer(bm->master, sync_expired, NULL, 0, &t_rpki_sync);
+ event_add_timer(bm->master, sync_expired, rpki_vrf, 0,
+ &rpki_vrf->t_rpki_sync);
XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups);
- rtr_is_running = true;
+ rpki_vrf->rtr_is_running = true;
return SUCCESS;
}
-static void stop(void)
+static void stop(struct rpki_vrf *rpki_vrf)
{
- rtr_is_stopping = true;
- if (is_running()) {
- EVENT_OFF(t_rpki_sync);
- rtr_mgr_stop(rtr_config);
- rtr_mgr_free(rtr_config);
- rtr_is_running = false;
+ rpki_vrf->rtr_is_stopping = true;
+ if (is_running(rpki_vrf)) {
+ EVENT_OFF(rpki_vrf->t_rpki_sync);
+ rtr_mgr_stop(rpki_vrf->rtr_config);
+ rtr_mgr_free(rpki_vrf->rtr_config);
+ rpki_vrf->rtr_is_running = false;
}
}
-static int reset(bool force)
+static int reset(bool force, struct rpki_vrf *rpki_vrf)
{
- if (is_running() && !force)
+ if (is_running(rpki_vrf) && !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,
+ struct rpki_vrf *rpki_vrf,
json_object *json)
{
unsigned int number_of_ipv4_prefixes = 0;
unsigned int number_of_ipv6_prefixes = 0;
- struct rtr_mgr_group *group = get_connected_group();
+ struct rtr_mgr_group *group = get_connected_group(rpki_vrf);
struct rpki_for_each_record_arg arg;
json_object *json_records = NULL;
@@ -741,6 +1024,9 @@ static void print_prefix_table_by_asn(struct vty *vty, as_t as,
arg.json = NULL;
arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT));
+ if (!rpki_vrf)
+ return;
+
if (!group) {
if (json) {
json_object_string_add(json, "error", "Cannot find a connected group.");
@@ -784,15 +1070,20 @@ static void print_prefix_table_by_asn(struct vty *vty, as_t as,
vty_json(vty, json);
}
-static void print_prefix_table(struct vty *vty, json_object *json)
+static void print_prefix_table(struct vty *vty, struct rpki_vrf *rpki_vrf,
+ json_object *json, bool count_only)
{
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 = get_connected_group(rpki_vrf);
json_object *json_records = NULL;
+ if (!rpki_vrf)
+ return;
+
+ group = get_connected_group(rpki_vrf);
arg.vty = vty;
arg.json = NULL;
arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT));
@@ -808,21 +1099,29 @@ static void print_prefix_table(struct vty *vty, json_object *json)
struct pfx_table *pfx_table = group->sockets[0]->pfx_table;
- if (!json) {
- vty_out(vty, "RPKI/RTR prefix table\n");
- vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
- "Origin-AS");
- } else {
- json_records = json_object_new_array();
- json_object_object_add(json, "prefixes", json_records);
- arg.json = json_records;
+ if (!count_only) {
+ if (!json) {
+ vty_out(vty, "RPKI/RTR prefix table\n");
+ vty_out(vty, "%-40s %s %s\n", "Prefix",
+ "Prefix Length", "Origin-AS");
+ } else {
+ json_records = json_object_new_array();
+ json_object_object_add(json, "prefixes", json_records);
+ arg.json = json_records;
+ }
}
arg.prefix_amount = &number_of_ipv4_prefixes;
- pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg);
+ if (count_only)
+ pfx_table_for_each_ipv4_record(pfx_table, count_record_cb, &arg);
+ else
+ pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg);
arg.prefix_amount = &number_of_ipv6_prefixes;
- pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg);
+ if (count_only)
+ pfx_table_for_each_ipv6_record(pfx_table, count_record_cb, &arg);
+ else
+ pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg);
if (!json) {
vty_out(vty, "Number of IPv4 Prefixes: %u\n",
@@ -847,8 +1146,25 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
as_t as_number = 0;
struct lrtr_ip_addr ip_addr_prefix;
enum pfxv_state result;
+ 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;
+
+ if (!is_synchronized(rpki_vrf))
return RPKI_NOT_BEING_USED;
// No aspath means route comes from iBGP
@@ -893,7 +1209,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
@@ -926,15 +1242,26 @@ 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;
+
+ rpki_vrf = cache->rpki_vrf;
+ if (!rpki_vrf)
+ return ERROR;
group.preference = preference;
group.sockets_len = 1;
group.sockets = &cache->rtr_socket;
- if (is_running()) {
+ cache_list = rpki_vrf->cache_list;
+ if (!cache_list)
+ return ERROR;
+
+ if (is_running(rpki_vrf)) {
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;
}
@@ -945,8 +1272,108 @@ static int add_cache(struct cache *cache)
return SUCCESS;
}
-static int add_tcp_cache(const char *host, const char *port,
- const uint8_t preference, const char *bindaddr)
+static int rpki_create_socket(void *_cache)
+{
+ struct timeval prev_snd_tmout, prev_rcv_tmout, timeout;
+ struct cache *cache = (struct cache *)_cache;
+ struct rpki_vrf *rpki_vrf = cache->rpki_vrf;
+ struct tr_tcp_config *tcp_config;
+ struct addrinfo *res = NULL;
+ struct addrinfo hints = {};
+ socklen_t optlen;
+ char *host, *port;
+ struct vrf *vrf;
+ int cancel_state;
+ int socket;
+ int ret;
+#if defined(FOUND_SSH)
+ struct tr_ssh_config *ssh_config;
+ char s_port[10];
+#endif
+
+ if (!cache)
+ return -1;
+
+ if (rpki_vrf->vrfname == NULL)
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ else
+ vrf = vrf_lookup_by_name(rpki_vrf->vrfname);
+ if (!vrf)
+ return -1;
+
+ if (!CHECK_FLAG(vrf->status, VRF_ACTIVE) || vrf->vrf_id == VRF_UNKNOWN)
+ return -1;
+
+ if (cache->type == TCP) {
+ 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;
+ }
+#if defined(FOUND_SSH)
+ else {
+ 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;
+ }
+#endif
+
+ frr_with_privs (&bgpd_privs) {
+ ret = vrf_getaddrinfo(host, port, &hints, &res, vrf->vrf_id);
+ }
+ if (ret != 0)
+ return -1;
+
+ frr_with_privs (&bgpd_privs) {
+ socket = vrf_socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol, vrf->vrf_id, NULL);
+ }
+ if (socket < 0)
+ return -1;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancel_state);
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+
+ optlen = sizeof(prev_rcv_tmout);
+ getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &prev_rcv_tmout, &optlen);
+ getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &prev_snd_tmout, &optlen);
+
+ setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+ setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+
+ if (connect(socket, res->ai_addr, res->ai_addrlen) == -1) {
+ if (res)
+ freeaddrinfo(res);
+ close(socket);
+ pthread_setcancelstate(cancel_state, NULL);
+ return -1;
+ }
+
+ if (res)
+ freeaddrinfo(res);
+ pthread_setcancelstate(cancel_state, NULL);
+
+ setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &prev_rcv_tmout,
+ sizeof(prev_rcv_tmout));
+ setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &prev_snd_tmout,
+ sizeof(prev_snd_tmout));
+
+ return socket;
+}
+
+static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host,
+ const char *port, const uint8_t preference,
+ const char *bindaddr)
{
struct rtr_socket *rtr_socket;
struct tr_tcp_config *tcp_config =
@@ -963,8 +1390,11 @@ static int add_tcp_cache(const char *host, const char *port,
else
tcp_config->bindaddr = NULL;
+ tcp_config->data = cache;
+ tcp_config->new_socket = rpki_create_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;
@@ -973,15 +1403,16 @@ static int add_tcp_cache(const char *host, const char *port,
int ret = add_cache(cache);
if (ret != SUCCESS) {
+ tcp_config->data = NULL;
free_cache(cache);
}
-
return ret;
}
#if defined(FOUND_SSH)
-static int add_ssh_cache(const char *host, const unsigned int port,
- const char *username, const char *client_privkey_path,
+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 *server_pubkey_path,
const uint8_t preference, const char *bindaddr)
{
@@ -999,6 +1430,8 @@ static int add_ssh_cache(const char *host, const unsigned int port,
ssh_config->bindaddr = XSTRDUP(MTYPE_BGP_RPKI_CACHE, bindaddr);
else
ssh_config->bindaddr = NULL;
+ ssh_config->data = cache;
+ ssh_config->new_socket = rpki_create_socket;
ssh_config->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username);
ssh_config->client_privkey_path =
@@ -1008,6 +1441,7 @@ static int add_ssh_cache(const char *host, const unsigned int port,
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;
@@ -1016,6 +1450,7 @@ static int add_ssh_cache(const char *host, const unsigned int port,
int ret = add_cache(cache);
if (ret != SUCCESS) {
+ ssh_config->data = NULL;
free_cache(cache);
}
@@ -1064,29 +1499,59 @@ 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 = NULL;
+ char sep[STR_SEPARATOR];
+ vrf_id_t vrf_id = VRF_DEFAULT;
+
+ 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 (list_isempty(cache_list) &&
- polling_period == POLLING_PERIOD_DEFAULT &&
- retry_interval == RETRY_INTERVAL_DEFAULT &&
- expire_interval == EXPIRE_INTERVAL_DEFAULT)
+ if (rpki_vrf->cache_list && list_isempty(rpki_vrf->cache_list) &&
+ rpki_vrf->polling_period == POLLING_PERIOD_DEFAULT &&
+ rpki_vrf->retry_interval == RETRY_INTERVAL_DEFAULT &&
+ rpki_vrf->expire_interval == EXPIRE_INTERVAL_DEFAULT)
/* do not display the default config values */
return 0;
- 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);
-
- for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
+ 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)
@@ -1094,8 +1559,8 @@ static int config_write(struct vty *vty)
#endif
case TCP:
tcp_config = cache->tr_config.tcp_config;
- vty_out(vty, " rpki cache %s %s ", tcp_config->host,
- tcp_config->port);
+ vty_out(vty, "%s rpki cache %s %s ", sep,
+ tcp_config->host, tcp_config->port);
if (tcp_config->bindaddr)
vty_out(vty, "source %s ",
tcp_config->bindaddr);
@@ -1103,7 +1568,7 @@ static int config_write(struct vty *vty)
#if defined(FOUND_SSH)
case SSH:
ssh_config = cache->tr_config.ssh_config;
- vty_out(vty, " rpki cache %s %u %s %s %s ",
+ vty_out(vty, "%s rpki cache %s %u %s %s %s ", sep,
ssh_config->host, ssh_config->port,
ssh_config->username,
ssh_config->client_privkey_path,
@@ -1121,17 +1586,62 @@ static int config_write(struct vty *vty)
vty_out(vty, "preference %hhu\n", cache->preference);
}
- vty_out(vty, "exit\n");
+
+ vty_out(vty, "%sexit\n%s", sep, vrf_id == VRF_DEFAULT ? "!\n" : "");
return 1;
}
+static int config_write(struct vty *vty)
+{
+ return bgp_rpki_write_vrf(vty, NULL);
+}
+
+static struct rpki_vrf *get_rpki_vrf(const char *vrfname)
+{
+ struct rpki_vrf *rpki_vrf = NULL;
+ struct vrf *vrf = NULL;
+
+ if (vrfname && !strmatch(vrfname, VRF_DEFAULT_NAME)) {
+ vrf = vrf_lookup_by_name(vrfname);
+ if (!vrf)
+ return NULL;
+ rpki_vrf = find_rpki_vrf(vrf->name);
+ } else
+ /* default VRF */
+ rpki_vrf = find_rpki_vrf(NULL);
+
+ return rpki_vrf;
+}
+
DEFUN_NOSH (rpki,
rpki_cmd,
"rpki",
"Enable rpki and enter rpki configuration mode\n")
{
- vty->node = RPKI_NODE;
+ struct rpki_vrf *rpki_vrf;
+ char *vrfname = NULL;
+
+ 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;
+ }
+
+ rpki_vrf = find_rpki_vrf(vrfname);
+ if (!rpki_vrf) {
+ rpki_vrf = bgp_rpki_allocate(vrfname);
+
+ rpki_init_sync_socket(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;
}
@@ -1141,27 +1651,49 @@ DEFPY (no_rpki,
NO_STR
"Enable rpki and enter rpki configuration mode\n")
{
- rpki_delete_all_cache_nodes();
- stop();
- polling_period = POLLING_PERIOD_DEFAULT;
- expire_interval = EXPIRE_INTERVAL_DEFAULT;
- retry_interval = RETRY_INTERVAL_DEFAULT;
+ struct rpki_vrf *rpki_vrf;
+ char *vrfname = 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);
+
+ rpki_delete_all_cache_nodes(rpki_vrf);
+ stop(rpki_vrf);
+ rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT;
+ rpki_vrf->expire_interval = EXPIRE_INTERVAL_DEFAULT;
+ rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT;
return CMD_SUCCESS;
}
-DEFUN (bgp_rpki_start,
+DEFPY (bgp_rpki_start,
bgp_rpki_start_cmd,
- "rpki start",
+ "rpki start [vrf NAME$vrfname]",
RPKI_OUTPUT_STRING
- "start rpki support\n")
+ "start rpki support\n"
+ VRF_CMD_HELP_STR)
{
- if (listcount(cache_list) == 0)
+ struct list *cache_list = NULL;
+ struct rpki_vrf *rpki_vrf;
+
+ rpki_vrf = get_rpki_vrf(vrfname);
+
+ if (!rpki_vrf)
+ return CMD_WARNING;
+
+ 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");
- if (!is_running()) {
- if (start() == ERROR) {
+ if (!is_running(rpki_vrf)) {
+ if (start(rpki_vrf) == ERROR) {
RPKI_DEBUG("RPKI failed to start");
return CMD_WARNING;
}
@@ -1169,14 +1701,19 @@ DEFUN (bgp_rpki_start,
return CMD_SUCCESS;
}
-DEFUN (bgp_rpki_stop,
+DEFPY (bgp_rpki_stop,
bgp_rpki_stop_cmd,
- "rpki stop",
+ "rpki stop [vrf NAME$vrfname]",
RPKI_OUTPUT_STRING
- "start rpki support\n")
+ "start rpki support\n"
+ VRF_CMD_HELP_STR)
{
- if (is_running())
- stop();
+ struct rpki_vrf *rpki_vrf;
+
+ rpki_vrf = get_rpki_vrf(vrfname);
+
+ if (rpki_vrf && is_running(rpki_vrf))
+ stop(rpki_vrf);
return CMD_SUCCESS;
}
@@ -1188,7 +1725,14 @@ DEFPY (rpki_polling_period,
"Set polling period\n"
"Polling period value\n")
{
- polling_period = pp;
+ 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;
}
@@ -1200,7 +1744,14 @@ DEFUN (no_rpki_polling_period,
"Set polling period back to default\n"
"Polling period value\n")
{
- polling_period = POLLING_PERIOD_DEFAULT;
+ 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;
}
@@ -1211,8 +1762,15 @@ DEFPY (rpki_expire_interval,
"Set expire interval\n"
"Expire interval value\n")
{
- if ((unsigned int)tmp >= polling_period) {
- expire_interval = tmp;
+ 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;
return CMD_SUCCESS;
}
@@ -1228,7 +1786,14 @@ DEFUN (no_rpki_expire_interval,
"Set expire interval back to default\n"
"Expire interval value\n")
{
- expire_interval = polling_period * 2;
+ 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;
}
@@ -1239,7 +1804,14 @@ DEFPY (rpki_retry_interval,
"Set retry interval\n"
"retry interval value\n")
{
- retry_interval = tmp;
+ 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;
}
@@ -1251,7 +1823,14 @@ DEFUN (no_rpki_retry_interval,
"Set retry interval back to default\n"
"retry interval value\n")
{
- retry_interval = RETRY_INTERVAL_DEFAULT;
+ 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;
}
@@ -1274,9 +1853,21 @@ DEFPY(rpki_cache, rpki_cache_cmd,
int return_value;
struct listnode *cache_node;
struct cache *current_cache;
- bool init = !!list_isempty(cache_list);
+ struct rpki_vrf *rpki_vrf;
+ bool init;
+
+ 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 || !rpki_vrf->cache_list)
+ return CMD_WARNING;
+
+ init = !!list_isempty(rpki_vrf->cache_list);
- for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, current_cache)) {
+ 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",
@@ -1285,21 +1876,20 @@ DEFPY(rpki_cache, rpki_cache_cmd,
}
}
-
// use ssh connection
if (ssh_uname) {
#if defined(FOUND_SSH)
- return_value =
- add_ssh_cache(cache, sshport, ssh_uname, ssh_privkey,
- server_pubkey, preference, bindaddr_str);
+ return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname,
+ ssh_privkey, server_pubkey,
+ preference, bindaddr_str);
#else
return_value = SUCCESS;
vty_out(vty,
"ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n");
#endif
} else { // use tcp connection
- return_value =
- add_tcp_cache(cache, tcpport, preference, bindaddr_str);
+ return_value = add_tcp_cache(rpki_vrf, cache, tcpport,
+ preference, bindaddr_str);
}
if (return_value == ERROR) {
@@ -1308,7 +1898,7 @@ DEFPY(rpki_cache, rpki_cache_cmd,
}
if (init)
- start();
+ start(rpki_vrf);
return CMD_SUCCESS;
}
@@ -1331,18 +1921,28 @@ 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;
+ 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 (!cache_p) {
+ 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 with preference %ld\n",
preference);
return CMD_WARNING;
}
- if (is_running() && listcount(cache_list) == 1) {
- stop();
- } else if (is_running()) {
- if (rtr_mgr_remove_group(rtr_config, preference) == RTR_ERROR) {
+ if (is_running(rpki_vrf) && listcount(cache_list) == 1) {
+ stop(rpki_vrf);
+ } else if (is_running(rpki_vrf)) {
+ if (rtr_mgr_remove_group(rpki_vrf->rtr_config, preference) ==
+ RTR_ERROR) {
vty_out(vty,
"Could not remove cache with preference %ld\n",
preference);
@@ -1358,18 +1958,33 @@ DEFPY (no_rpki_cache,
DEFPY (show_rpki_prefix_table,
show_rpki_prefix_table_cmd,
- "show rpki prefix-table [json$uj]",
+ "show rpki <prefix-table|prefix-count>$prefixkind [vrf NAME$vrfname] [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Show validated prefixes which were received from RPKI Cache\n"
+ "Show prefixes count which were received from RPKI Cache\n"
+ VRF_CMD_HELP_STR
JSON_STR)
{
struct json_object *json = NULL;
+ struct rpki_vrf *rpki_vrf;
if (uj)
json = json_object_new_object();
- if (!is_synchronized()) {
+ rpki_vrf = get_rpki_vrf(vrfname);
+ if (!rpki_vrf) {
+ if (uj)
+ vty_json(vty, json);
+ return CMD_SUCCESS;
+ }
+
+ if (is_synchronized(rpki_vrf)) {
+ if (strmatch(prefixkind, "prefix-count"))
+ print_prefix_table(vty, rpki_vrf, json, true);
+ else
+ print_prefix_table(vty, rpki_vrf, json, false);
+ } else {
if (json) {
json_object_string_add(json, "error", "No Connection to RPKI cache server.");
vty_json(vty, json);
@@ -1378,25 +1993,33 @@ DEFPY (show_rpki_prefix_table,
return CMD_WARNING;
}
- print_prefix_table(vty, json);
return CMD_SUCCESS;
}
DEFPY (show_rpki_as_number,
show_rpki_as_number_cmd,
- "show rpki as-number ASNUM$by_asn [json$uj]",
+ "show rpki as-number ASNUM$by_asn [vrf NAME$vrfname] [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Lookup by ASN in prefix table\n"
"AS Number\n"
+ VRF_CMD_HELP_STR
JSON_STR)
{
struct json_object *json = NULL;
+ struct rpki_vrf *rpki_vrf;
if (uj)
json = json_object_new_object();
- if (!is_synchronized()) {
+ rpki_vrf = get_rpki_vrf(vrfname);
+ if (!rpki_vrf) {
+ if (uj)
+ vty_json(vty, json);
+ return CMD_SUCCESS;
+ }
+
+ if (!is_synchronized(rpki_vrf)) {
if (json) {
json_object_string_add(json, "error", "No Connection to RPKI cache server.");
vty_json(vty, json);
@@ -1405,29 +2028,33 @@ DEFPY (show_rpki_as_number,
return CMD_WARNING;
}
- print_prefix_table_by_asn(vty, by_asn, json);
+ print_prefix_table_by_asn(vty, by_asn, rpki_vrf, json);
return CMD_SUCCESS;
}
DEFPY (show_rpki_prefix,
show_rpki_prefix_cmd,
- "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [ASNUM$asn] [json$uj]",
+ "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [ASNUM$asn] [vrf NAME$vrfname] [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Lookup IP prefix and optionally ASN in prefix table\n"
"IPv4 prefix\n"
"IPv6 prefix\n"
"AS Number\n"
+ VRF_CMD_HELP_STR
JSON_STR)
{
json_object *json = NULL;
json_object *json_records = NULL;
enum asnotation_mode asnotation;
+ struct rpki_vrf *rpki_vrf;
if (uj)
json = json_object_new_object();
- if (!is_synchronized()) {
+ rpki_vrf = get_rpki_vrf(vrfname);
+
+ if (!rpki_vrf || !is_synchronized(rpki_vrf)) {
if (json) {
json_object_string_add(json, "error", "No Connection to RPKI cache server.");
vty_json(vty, json);
@@ -1456,8 +2083,8 @@ 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,
+ if (pfx_table_validate_r(rpki_vrf->rtr_config->pfx_table, &matches,
+ &match_count, asn, &addr, prefix->prefixlen,
&result) != PFX_SUCCESS) {
if (json) {
json_object_string_add(json, "error", "Prefix lookup failed.");
@@ -1495,10 +2122,11 @@ DEFPY (show_rpki_prefix,
DEFPY (show_rpki_cache_server,
show_rpki_cache_server_cmd,
- "show rpki cache-server [json$uj]",
+ "show rpki cache-server [vrf NAME$vrfname] [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Show configured cache server\n"
+ VRF_CMD_HELP_STR
JSON_STR)
{
struct json_object *json = NULL;
@@ -1506,6 +2134,7 @@ DEFPY (show_rpki_cache_server,
struct json_object *json_servers = NULL;
struct listnode *cache_node;
struct cache *cache;
+ struct rpki_vrf *rpki_vrf;
if (uj) {
json = json_object_new_object();
@@ -1513,7 +2142,14 @@ DEFPY (show_rpki_cache_server,
json_object_object_add(json, "servers", json_servers);
}
- for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
+ rpki_vrf = get_rpki_vrf(vrfname);
+ if (!rpki_vrf) {
+ if (json)
+ vty_json(vty, json);
+ return CMD_SUCCESS;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) {
if (cache->type == TCP) {
if (!json) {
vty_out(vty,
@@ -1588,10 +2224,11 @@ DEFPY (show_rpki_cache_server,
DEFPY (show_rpki_cache_connection,
show_rpki_cache_connection_cmd,
- "show rpki cache-connection [json$uj]",
+ "show rpki cache-connection [vrf NAME$vrfname] [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Show to which RPKI Cache Servers we have a connection\n"
+ VRF_CMD_HELP_STR
JSON_STR)
{
struct json_object *json = NULL;
@@ -1600,11 +2237,19 @@ DEFPY (show_rpki_cache_connection,
struct listnode *cache_node;
struct cache *cache;
struct rtr_mgr_group *group;
+ struct rpki_vrf *rpki_vrf;
if (uj)
json = json_object_new_object();
- if (!is_synchronized()) {
+ rpki_vrf = get_rpki_vrf(vrfname);
+ if (!rpki_vrf) {
+ if (json)
+ vty_json(vty, json);
+ return CMD_SUCCESS;
+ }
+
+ if (!is_synchronized(rpki_vrf)) {
if (json) {
json_object_string_add(json, "error", "No connection to RPKI cache server.");
vty_json(vty, json);
@@ -1614,7 +2259,7 @@ DEFPY (show_rpki_cache_connection,
return CMD_SUCCESS;
}
- group = get_connected_group();
+ group = get_connected_group(rpki_vrf);
if (!group) {
if (json) {
json_object_string_add(json, "error", "Cannot find a connected group.");
@@ -1633,7 +2278,7 @@ DEFPY (show_rpki_cache_connection,
json_object_object_add(json, "connections", json_conns);
}
- for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
+ for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) {
struct tr_tcp_config *tcp_config;
#if defined(FOUND_SSH)
struct tr_ssh_config *ssh_config;
@@ -1715,24 +2360,36 @@ DEFPY (show_rpki_cache_connection,
}
DEFPY(show_rpki_configuration, show_rpki_configuration_cmd,
- "show rpki configuration [json$uj]",
+ "show rpki configuration [vrf NAME$vrfname] [json$uj]",
SHOW_STR RPKI_OUTPUT_STRING
"Show RPKI configuration\n"
+ VRF_CMD_HELP_STR
JSON_STR)
{
struct json_object *json = NULL;
+ struct rpki_vrf *rpki_vrf;
- if (uj) {
+ if (uj)
json = json_object_new_object();
+
+ rpki_vrf = find_rpki_vrf(vrfname);
+ if (!rpki_vrf) {
+ if (uj)
+ vty_json(vty, json);
+ return CMD_SUCCESS;
+ }
+
+ if (uj) {
json_object_boolean_add(json, "enabled",
- !!listcount(cache_list));
- json_object_int_add(json, "serversCount", listcount(cache_list));
+ !!listcount(rpki_vrf->cache_list));
+ json_object_int_add(json, "serversCount",
+ listcount(rpki_vrf->cache_list));
json_object_int_add(json, "pollingPeriodSeconds",
- polling_period);
+ rpki_vrf->polling_period);
json_object_int_add(json, "retryIntervalSeconds",
- retry_interval);
+ rpki_vrf->retry_interval);
json_object_int_add(json, "expireIntervalSeconds",
- expire_interval);
+ rpki_vrf->expire_interval);
vty_json(vty, json);
@@ -1740,35 +2397,64 @@ DEFPY(show_rpki_configuration, show_rpki_configuration_cmd,
}
vty_out(vty, "rpki is %s",
- listcount(cache_list) ? "Enabled" : "Disabled");
+ listcount(rpki_vrf->cache_list) ? "Enabled" : "Disabled");
- if (list_isempty(cache_list)) {
+ if (list_isempty(rpki_vrf->cache_list)) {
vty_out(vty, "\n");
return CMD_SUCCESS;
}
- vty_out(vty, " (%d cache servers configured)", listcount(cache_list));
+ 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);
+ 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;
}
-DEFUN (rpki_reset,
+DEFPY(rpki_reset,
rpki_reset_cmd,
+ "rpki reset [vrf NAME$vrfname]",
+ RPKI_OUTPUT_STRING
+ "reset rpki\n"
+ VRF_CMD_HELP_STR)
+{
+ struct rpki_vrf *rpki_vrf;
+
+ rpki_vrf = find_rpki_vrf(vrfname);
+ if (!rpki_vrf)
+ return CMD_WARNING;
+
+ return reset(true, rpki_vrf) == SUCCESS ? CMD_SUCCESS : CMD_WARNING;
+}
+
+DEFPY (rpki_reset_config_mode,
+ rpki_reset_config_mode_cmd,
"rpki reset",
RPKI_OUTPUT_STRING
"reset rpki\n")
{
- return reset(true) == SUCCESS ? CMD_SUCCESS : CMD_WARNING;
+ 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);
+ return reset(true, rpki_vrf) == SUCCESS ? CMD_SUCCESS : CMD_WARNING;
}
DEFUN (debug_rpki,
@@ -1841,8 +2527,9 @@ 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(ENABLE_NODE, &rpki_cmd);
install_element(CONFIG_NODE, &no_rpki_cmd);
@@ -1851,7 +2538,7 @@ static void install_cli_commands(void)
/* Install rpki reset command */
install_element(ENABLE_NODE, &rpki_reset_cmd);
- install_element(RPKI_NODE, &rpki_reset_cmd);
+ install_element(RPKI_NODE, &rpki_reset_config_mode_cmd);
/* Install rpki polling period commands */
install_element(RPKI_NODE, &rpki_polling_period_cmd);
@@ -1869,6 +2556,28 @@ 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_config_mode_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 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/bgpd/bgp_rpki.h b/bgpd/bgp_rpki.h
index de28715d1..4f2f87d2e 100644
--- a/bgpd/bgp_rpki.h
+++ b/bgpd/bgp_rpki.h
@@ -8,6 +8,8 @@
#ifndef __BGP_RPKI_H__
#define __BGP_RPKI_H__
+extern struct zebra_privs_t bgpd_privs;
+
enum rpki_states {
RPKI_NOT_BEING_USED,
RPKI_VALID,
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 4c12872ee..1cc82748b 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -34,6 +34,9 @@
#include "lib/bfd.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
@@ -839,6 +842,8 @@ DECLARE_HOOK(bgp_inst_config_write,
(bgp, vty));
DECLARE_HOOK(bgp_snmp_traps_config_write, (struct vty *vty), (vty));
DECLARE_HOOK(bgp_config_end, (struct bgp *bgp), (bgp));
+DECLARE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled),
+ (vrf, enabled));
/* Thread callback information */
struct afi_safi_info {
diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst
index 06fb3c2f2..76910ee7b 100644
--- a/doc/user/rpki.rst
+++ b/doc/user/rpki.rst
@@ -62,8 +62,9 @@ otherwise ``bgpd`` daemon won't startup.
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
@@ -90,6 +91,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.
@@ -98,7 +102,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.
.. clicmd:: rpki polling_period (1-3600)
@@ -166,7 +177,7 @@ Validating BGP Updates
.. code-block:: frr
! Allow for invalid routes in route selection process
- route bgp 60001
+ route bgp 65001
!
! Set local preference of invalid prefixes to 10
route-map rpki permit 10
@@ -200,39 +211,39 @@ Debugging
Displaying RPKI
---------------
-.. clicmd:: show rpki configuration [json]
+.. clicmd:: show rpki configuration [vrf NAME] [json]
Display RPKI configuration state including timers values.
-.. clicmd:: show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)] [json]
+.. clicmd:: show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)] [vrf NAME] [json]
Display validated prefixes received from the cache servers filtered
by the specified prefix.
-.. clicmd:: show rpki as-number ASN [json]
+.. clicmd:: show rpki as-number ASN [vrf NAME] [json]
Display validated prefixes received from the cache servers filtered
by ASN.
-.. clicmd:: show rpki prefix-table [json]
+.. clicmd:: show rpki prefix-table [vrf NAME] [json]
Display all validated prefix to origin AS mappings/records which have been
received from the cache servers and stored in the router. Based on this data,
the router validates BGP Updates.
-.. clicmd:: show rpki cache-server [json]
+.. clicmd:: show rpki cache-server [vrf NAME] [json]
Display all configured cache servers, whether active or not.
-.. clicmd:: show rpki cache-connection [json]
+.. clicmd:: show rpki cache-connection [vrf NAME] [json]
Display all cache connections, and show which is connected or not.
-.. clicmd:: show bgp [afi] [safi] <A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> rpki <valid|invalid|notfound>
+.. clicmd:: show bgp [vrf NAME] [afi] [safi] <A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> rpki <valid|invalid|notfound>
Display for the specified prefix or address the bgp paths that match the given rpki state.
-.. clicmd:: show bgp [afi] [safi] rpki <valid|invalid|notfound>
+.. clicmd:: show bgp [vrf NAME] [afi] [safi] rpki <valid|invalid|notfound>
Display all prefixes that match the given rpki state.
@@ -248,25 +259,52 @@ RPKI Configuration Example
debug bgp keepalives
debug rpki
!
+ vrf VRF1
+ rpki
+ rpki polling_period 1000
+ rpki timeout 10
+ ! SSH Example:
+ rpki cache example.com 22 rtr-ssh ./ssh_key/id_rsa preference 1
+ ! TCP Example:
+ rpki cache rpki-validator.realmv6.org 8282 preference 2
+ exit
+ !
+ exit-vrf
+ !
rpki
rpki polling_period 1000
rpki timeout 10
! SSH Example:
- rpki cache example.com source 141.22.28.223 22 rtr-ssh ./ssh_key/id_rsa ./ssh_key/id_rsa.pub preference 1
+ rpki cache example.com source 198.51.100.223 22 rtr-ssh ./ssh_key/id_rsa preference 1
! TCP Example:
rpki cache rpki-validator.realmv6.org 8282 preference 2
exit
!
- router bgp 60001
- 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
- neighbor 123.123.123.0 update-source 141.22.28.223
+ router bgp 65001
+ bgp router-id 198.51.100.223
+ neighbor 203.0.113.1 remote-as 65002
+ neighbor 203.0.113.1 update-source 198.51.100.223
+ address-family ipv4
+ network 192.0.2.0/24
+ neighbor 203.0.113.1 route-map rpki in
+ exit-address-family
+ !
+ address-family ipv6
+ neighbor 203.0.113.1 activate
+ neighbor 203.0.113.1 route-map rpki in
+ exit-address-family
+ !
+ router bgp 65001 vrf VRF1
+ bgp router-id 198.51.100.223
+ neighbor 203.0.113.1 remote-as 65002
+ address-family ipv4
+ network 192.0.2.0/24
+ neighbor 203.0.113.1 route-map rpki in
+ exit-address-family
!
address-family ipv6
- neighbor 123.123.123.0 activate
- neighbor 123.123.123.0 route-map rpki in
+ neighbor 203.0.113.1 activate
+ neighbor 203.0.113.1 route-map rpki in
exit-address-family
!
route-map rpki permit 10
diff --git a/lib/command.h b/lib/command.h
index b6419e6fe..4886b4bc4 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -178,6 +178,7 @@ enum node_type {
ISIS_SRV6_NODE, /* ISIS SRv6 node */
ISIS_SRV6_NODE_MSD_NODE, /* ISIS SRv6 Node MSDs node */
MGMTD_NODE, /* MGMTD node. */
+ RPKI_VRF_NODE, /* RPKI node for VRF */
NODE_TYPE_MAX, /* maximum */
};
/* clang-format on */
diff --git a/tests/topotests/bgp_rpki_topo1/r2/staticd.conf b/tests/topotests/bgp_rpki_topo1/r2/staticd.conf
index e3f5d7dba..de58ddef6 100644
--- a/tests/topotests/bgp_rpki_topo1/r2/staticd.conf
+++ b/tests/topotests/bgp_rpki_topo1/r2/staticd.conf
@@ -1 +1,5 @@
ip route 192.0.2.1/32 192.168.1.1
+!
+vrf vrf10
+ ip route 192.0.2.3/32 192.168.2.3
+!
diff --git a/tests/topotests/bgp_rpki_topo1/r2/zebra.conf b/tests/topotests/bgp_rpki_topo1/r2/zebra.conf
index 96865f0b6..d44a8a908 100644
--- a/tests/topotests/bgp_rpki_topo1/r2/zebra.conf
+++ b/tests/topotests/bgp_rpki_topo1/r2/zebra.conf
@@ -7,3 +7,6 @@ interface vrf10 vrf vrf10
interface r2-eth0
ip address 192.168.1.2/24
!
+interface r2-eth1 vrf vrf10
+ ip address 192.168.2.2/24
+!
diff --git a/tests/topotests/bgp_rpki_topo1/r3/bgpd.conf b/tests/topotests/bgp_rpki_topo1/r3/bgpd.conf
new file mode 100644
index 000000000..596dc20d3
--- /dev/null
+++ b/tests/topotests/bgp_rpki_topo1/r3/bgpd.conf
@@ -0,0 +1,14 @@
+router bgp 65530
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.0.2.2 remote-as 65002
+ neighbor 192.0.2.2 timers 1 3
+ neighbor 192.0.2.2 timers connect 1
+ neighbor 192.0.2.2 ebgp-multihop 3
+ neighbor 192.0.2.2 update-source 192.0.2.3
+ address-family ipv4 unicast
+ network 198.51.100.0/24
+ network 203.0.113.0/24
+ network 10.0.0.0/24
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_rpki_topo1/r3/rtrd.py b/tests/topotests/bgp_rpki_topo1/r3/rtrd.py
new file mode 120000
index 000000000..1c5871a2a
--- /dev/null
+++ b/tests/topotests/bgp_rpki_topo1/r3/rtrd.py
@@ -0,0 +1 @@
+../r1/rtrd.py \ No newline at end of file
diff --git a/tests/topotests/bgp_rpki_topo1/r3/staticd.conf b/tests/topotests/bgp_rpki_topo1/r3/staticd.conf
new file mode 100644
index 000000000..6822f7ec0
--- /dev/null
+++ b/tests/topotests/bgp_rpki_topo1/r3/staticd.conf
@@ -0,0 +1 @@
+ip route 192.0.2.2/32 192.168.2.2
diff --git a/tests/topotests/bgp_rpki_topo1/r3/vrps.csv b/tests/topotests/bgp_rpki_topo1/r3/vrps.csv
new file mode 120000
index 000000000..8daa27f13
--- /dev/null
+++ b/tests/topotests/bgp_rpki_topo1/r3/vrps.csv
@@ -0,0 +1 @@
+../r1/vrps.csv \ No newline at end of file
diff --git a/tests/topotests/bgp_rpki_topo1/r3/zebra.conf b/tests/topotests/bgp_rpki_topo1/r3/zebra.conf
new file mode 100644
index 000000000..097511476
--- /dev/null
+++ b/tests/topotests/bgp_rpki_topo1/r3/zebra.conf
@@ -0,0 +1,5 @@
+interface lo
+ ip address 192.0.2.3/32
+!
+interface r3-eth0
+ ip address 192.168.2.3/24 \ No newline at end of file
diff --git a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py
index 36bc0b720..0416148b2 100644
--- a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py
+++ b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py
@@ -22,13 +22,17 @@ pytestmark = [pytest.mark.bgpd]
def build_topo(tgen):
- for routern in range(1, 3):
+ for routern in range(1, 4):
tgen.add_router("r{}".format(routern))
switch = tgen.add_switch("s1")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
def setup_module(mod):
tgen = Topogen(build_topo, mod.__name__)
@@ -49,25 +53,34 @@ def setup_module(mod):
" -M bgpd_rpki" if rname == "r2" else "",
)
+ tgen.gears["r2"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["r2"].run("ip link set vrf10 up")
+
+ tgen.gears["r2"].run("ip link set r2-eth1 master vrf10")
+
tgen.start_router()
global rtrd_process
+ rtrd_process = {}
- rname = "r1"
-
- rtr_path = os.path.join(CWD, rname)
- log_dir = os.path.join(tgen.logdir, rname)
- log_file = os.path.join(log_dir, "rtrd.log")
+ for rname in ["r1", "r3"]:
+ rtr_path = os.path.join(CWD, rname)
+ log_dir = os.path.join(tgen.logdir, rname)
+ log_file = os.path.join(log_dir, "rtrd.log")
- tgen.gears[rname].cmd("chmod u+x {}/rtrd.py".format(rtr_path))
- rtrd_process = tgen.gears[rname].popen("{}/rtrd.py {}".format(rtr_path, log_file))
+ tgen.gears[rname].cmd("chmod u+x {}/rtrd.py".format(rtr_path))
+ rtrd_process[rname] = tgen.gears[rname].popen(
+ "{}/rtrd.py {}".format(rtr_path, log_file)
+ )
def teardown_module(mod):
tgen = get_topogen()
- logger.info("r1: sending SIGTERM to rtrd RPKI server")
- rtrd_process.kill()
+ for rname in ["r1", "r3"]:
+ logger.info("{}: sending SIGTERM to rtrd RPKI server".format(rname))
+ rtrd_process[rname].kill()
+
tgen.stop_topology()
@@ -114,7 +127,7 @@ def test_show_bgp_rpki_prefixes():
for rname in ["r1", "r3"]:
logger.info("{}: checking if rtrd is running".format(rname))
- if rtrd_process.poll() is not None:
+ if rtrd_process[rname].poll() is not None:
pytest.skip(tgen.errors)
rname = "r2"
@@ -156,7 +169,7 @@ def test_show_bgp_rpki_prefixes_no_rpki_cache():
for rname in ["r1", "r3"]:
logger.info("{}: checking if rtrd is running".format(rname))
- if rtrd_process.poll() is not None:
+ if rtrd_process[rname].poll() is not None:
pytest.skip(tgen.errors)
def _show_rpki_no_connection(rname):
@@ -192,7 +205,7 @@ def test_show_bgp_rpki_prefixes_reconnect():
for rname in ["r1", "r3"]:
logger.info("{}: checking if rtrd is running".format(rname))
- if rtrd_process.poll() is not None:
+ if rtrd_process[rname].poll() is not None:
pytest.skip(tgen.errors)
step("Restore RPKI server configuration")
@@ -241,7 +254,7 @@ def test_show_bgp_rpki_route_map():
for rname in ["r1", "r3"]:
logger.info("{}: checking if rtrd is running".format(rname))
- if rtrd_process.poll() is not None:
+ if rtrd_process[rname].poll() is not None:
pytest.skip(tgen.errors)
step("Apply RPKI valid route-map on neighbor")
@@ -283,6 +296,112 @@ router bgp 65002
assert result is None, "Unexpected prefixes RPKI state on {}".format(rname)
+def test_show_bgp_rpki_prefixes_vrf():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r3"]:
+ logger.info("{}: checking if rtrd is running".format(rname))
+ if rtrd_process[rname].poll() is not None:
+ pytest.skip(tgen.errors)
+
+ step("Configure RPKI cache server on vrf10")
+
+ rname = "r2"
+ tgen.gears[rname].vtysh_cmd(
+ """
+configure
+vrf vrf10
+ rpki
+ rpki cache 192.0.2.3 15432 preference 1
+ exit
+exit
+"""
+ )
+
+ step("Check vrf10 RPKI prefix table")
+
+ expected = open(os.path.join(CWD, "{}/rpki_prefix_table.json".format(rname))).read()
+ expected_json = json.loads(expected)
+ test_func = functools.partial(show_rpki_prefixes, rname, expected_json, vrf="vrf10")
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see RPKI prefixes on {}".format(rname)
+
+ for rpki_state in ["valid", "notfound", None]:
+ if rpki_state:
+ step(
+ "Check RPKI state of prefixes in vrf10 BGP table: {}".format(rpki_state)
+ )
+ else:
+ step("Check prefixes in vrf10 BGP table")
+ expected = open(
+ os.path.join(
+ CWD,
+ "{}/bgp_table_rpki_{}.json".format(
+ rname, rpki_state if rpki_state else "any"
+ ),
+ )
+ ).read()
+ expected_json = json.loads(expected)
+ test_func = functools.partial(
+ show_bgp_ipv4_table_rpki, rname, rpki_state, expected_json, vrf="vrf10"
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Unexpected prefixes RPKI state on {}".format(rname)
+
+
+def test_show_bgp_rpki_route_map_vrf():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r3"]:
+ logger.info("{}: checking if rtrd is running".format(rname))
+ if rtrd_process[rname].poll() is not None:
+ pytest.skip(tgen.errors)
+
+ step("Apply RPKI valid route-map on vrf10 neighbor")
+
+ rname = "r2"
+ tgen.gears[rname].vtysh_cmd(
+ """
+configure
+router bgp 65002 vrf vrf10
+ address-family ipv4 unicast
+ neighbor 192.0.2.3 route-map RPKI in
+"""
+ )
+
+ for rpki_state in ["valid", "notfound", None]:
+ if rpki_state:
+ step(
+ "Check RPKI state of prefixes in vrf10 BGP table: {}".format(rpki_state)
+ )
+ else:
+ step("Check prefixes in vrf10 BGP table")
+ expected = open(
+ os.path.join(
+ CWD,
+ "{}/bgp_table_rmap_rpki_{}.json".format(
+ rname, rpki_state if rpki_state else "any"
+ ),
+ )
+ ).read()
+ expected_json = json.loads(expected)
+ test_func = functools.partial(
+ show_bgp_ipv4_table_rpki,
+ rname,
+ rpki_state,
+ expected_json,
+ vrf="vrf10",
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Unexpected prefixes RPKI state on {}".format(rname)
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index d5ac87eb3..3109f1510 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1625,6 +1625,14 @@ static struct cmd_node rpki_node = {
.parent_node = CONFIG_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)# ",
+};
+
#endif /* HAVE_BGPD */
#if HAVE_BFDD > 0
@@ -1855,7 +1863,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;
}
@@ -5071,6 +5082,12 @@ void vtysh_init_vty(void)
install_element(VRF_NODE, &vtysh_exit_vrf_cmd);
install_element(VRF_NODE, &vtysh_quit_vrf_cmd);
+ install_node(&rpki_vrf_node);
+ install_element(VRF_NODE, &rpki_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);
+
install_element(CONFIG_NODE, &vtysh_affinity_map_cmd);
install_element(CONFIG_NODE, &vtysh_no_affinity_map_cmd);
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 11751d027..f63d4be6e 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -58,7 +58,7 @@ extern struct event_loop *master;
VTYSH_EIGRPD | VTYSH_BABELD | VTYSH_PBRD | VTYSH_FABRICD | \
VTYSH_VRRPD | VTYSH_MGMTD
#define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD
-#define VTYSH_VRF VTYSH_INTERFACE_SUBSET
+#define VTYSH_VRF VTYSH_INTERFACE_SUBSET | RPKI_VRF_NODE
#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D | VTYSH_OSPFD
/* 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 c02f27c87..888f6a8c2 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -315,11 +315,20 @@ void vtysh_config_parse_line(void *arg, const char *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_add_line_uniq(config->line, line);
- else if (config->index == NH_GROUP_NODE) {
+ else if (config->index == RPKI_VRF_NODE &&
+ strncmp(line, " exit", strlen(" exit")) == 0) {
+ config_add_line(config->line, line);
+ config->index = VRF_NODE;
+ } else if (config->index == NH_GROUP_NODE) {
if (strncmp(line, " resilient",
strlen(" resilient")) == 0)
config_add_line_head(config->line,