]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_rpki.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgp_rpki.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
dabecd7c
MR
2/*
3 * BGP RPKI
4 * Copyright (C) 2013 Michael Mester (m.mester@fu-berlin.de), for FU Berlin
996c9314
LB
5 * Copyright (C) 2014-2017 Andreas Reuter (andreas.reuter@fu-berlin.de), for FU
6 * Berlin
7 * Copyright (C) 2016-2017 Colin Sames (colin.sames@haw-hamburg.de), for HAW
8 * Hamburg
e4234602
MR
9 * Copyright (C) 2017-2018 Marcel Röthke (marcel.roethke@haw-hamburg.de),
10 * for HAW Hamburg
dabecd7c
MR
11 */
12
45c0beda
AK
13/* If rtrlib compiled with ssh support, don`t fail build */
14#define LIBSSH_LEGACY_0_4
15
dabecd7c
MR
16#include <zebra.h>
17#include <pthread.h>
18#include <time.h>
19#include <stdbool.h>
20#include <stdlib.h>
21#include "prefix.h"
22#include "log.h"
23#include "command.h"
24#include "linklist.h"
25#include "memory.h"
26#include "thread.h"
27#include "filter.h"
28#include "bgpd/bgpd.h"
29#include "bgpd/bgp_table.h"
30#include "bgp_advertise.h"
31#include "bgpd/bgp_debug.h"
32#include "bgpd/bgp_attr.h"
33#include "bgpd/bgp_aspath.h"
34#include "bgpd/bgp_route.h"
fdeb5a81 35#include "bgpd/bgp_rpki.h"
0d951156 36#include "northbound_cli.h"
fdeb5a81 37
4ce82676 38#include "lib/network.h"
1dacdd8b 39#include "lib/thread.h"
dabecd7c 40#include "rtrlib/rtrlib.h"
dabecd7c
MR
41#include "hook.h"
42#include "libfrr.h"
09781197 43#include "lib/version.h"
dabecd7c 44
2e4c2296 45#include "bgpd/bgp_rpki_clippy.c"
dabecd7c 46
bf8d3d6a
DL
47DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server");
48DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group");
94ff78a7 49DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_RTRLIB, "BGP RPKI RTRLib");
7651f277 50DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_REVALIDATE, "BGP RPKI Revalidation");
dabecd7c 51
dabecd7c
MR
52#define POLLING_PERIOD_DEFAULT 3600
53#define EXPIRE_INTERVAL_DEFAULT 7200
54#define RETRY_INTERVAL_DEFAULT 600
1b2095d1 55#define BGP_RPKI_CACHE_SERVER_SYNC_RETRY_TIMEOUT 3
dabecd7c 56
d67485c6
DA
57static struct thread *t_rpki_sync;
58
dabecd7c
MR
59#define RPKI_DEBUG(...) \
60 if (rpki_debug) { \
61 zlog_debug("RPKI: " __VA_ARGS__); \
62 }
63
64#define RPKI_OUTPUT_STRING "Control rpki specific settings\n"
65
66struct cache {
996c9314
LB
67 enum { TCP, SSH } type;
68 struct tr_socket *tr_socket;
69 union {
dabecd7c
MR
70 struct tr_tcp_config *tcp_config;
71 struct tr_ssh_config *ssh_config;
996c9314
LB
72 } tr_config;
73 struct rtr_socket *rtr_socket;
74 uint8_t preference;
dabecd7c
MR
75};
76
77enum return_values { SUCCESS = 0, ERROR = -1 };
78
79struct rpki_for_each_record_arg {
80 struct vty *vty;
81 unsigned int *prefix_amount;
02334bb2 82 as_t as;
dff41cc8 83 json_object *json;
6ccfd103 84 enum asnotation_mode asnotation;
dabecd7c
MR
85};
86
87static int start(void);
88static void stop(void);
89static int reset(bool force);
90static struct rtr_mgr_group *get_connected_group(void);
dff41cc8 91static void print_prefix_table(struct vty *vty, json_object *json);
dabecd7c
MR
92static void install_cli_commands(void);
93static int config_write(struct vty *vty);
791ded4a 94static int config_on_exit(struct vty *vty);
dabecd7c
MR
95static void free_cache(struct cache *cache);
96static struct rtr_mgr_group *get_groups(void);
97#if defined(FOUND_SSH)
996c9314
LB
98static int add_ssh_cache(const char *host, const unsigned int port,
99 const char *username, const char *client_privkey_path,
dabecd7c 100 const char *server_pubkey_path,
7253a7bc 101 const uint8_t preference, const char *bindaddr);
dabecd7c
MR
102#endif
103static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket);
104static struct cache *find_cache(const uint8_t preference);
8156765a 105static void rpki_delete_all_cache_nodes(void);
996c9314 106static int add_tcp_cache(const char *host, const char *port,
7253a7bc 107 const uint8_t preference, const char *bindaddr);
dff41cc8 108static void print_record(const struct pfx_record *record, struct vty *vty,
6ccfd103 109 json_object *json, enum asnotation_mode asnotation);
d67485c6 110static bool is_synchronized(void);
0e3d96bf
DA
111static bool is_running(void);
112static bool is_stopping(void);
dabecd7c 113static void route_match_free(void *rule);
b68885f9
LK
114static enum route_map_cmd_result_t route_match(void *rule,
115 const struct prefix *prefix,
1782514f 116
b68885f9 117 void *object);
dabecd7c 118static void *route_match_compile(const char *arg);
9bcb3eef 119static void revalidate_bgp_node(struct bgp_dest *dest, afi_t afi, safi_t safi);
4ce82676 120static void revalidate_all_routes(void);
dabecd7c
MR
121
122static struct rtr_mgr_config *rtr_config;
123static struct list *cache_list;
0e3d96bf
DA
124static bool rtr_is_running;
125static bool rtr_is_stopping;
d67485c6 126static bool rtr_is_synced;
4ce82676 127static _Atomic int rtr_update_overflow;
0e3d96bf 128static bool rpki_debug;
dabecd7c
MR
129static unsigned int polling_period;
130static unsigned int expire_interval;
131static unsigned int retry_interval;
1dacdd8b
MR
132static int rpki_sync_socket_rtr;
133static int rpki_sync_socket_bgpd;
dabecd7c 134
62b346ee 135static struct cmd_node rpki_node = {
f4b8291f 136 .name = "rpki",
62b346ee 137 .node = RPKI_NODE,
24389580 138 .parent_node = CONFIG_NODE,
62b346ee 139 .prompt = "%s(config-rpki)# ",
612c2c15 140 .config_write = config_write,
791ded4a 141 .node_exit = config_on_exit,
62b346ee 142};
364deb04 143static const struct route_map_rule_cmd route_match_rpki_cmd = {
996c9314 144 "rpki", route_match, route_match_compile, route_match_free};
dabecd7c
MR
145
146static void *malloc_wrapper(size_t size)
147{
94ff78a7 148 return XMALLOC(MTYPE_BGP_RPKI_RTRLIB, size);
dabecd7c
MR
149}
150
151static void *realloc_wrapper(void *ptr, size_t size)
152{
94ff78a7 153 return XREALLOC(MTYPE_BGP_RPKI_RTRLIB, ptr, size);
dabecd7c
MR
154}
155
156static void free_wrapper(void *ptr)
157{
94ff78a7 158 XFREE(MTYPE_BGP_RPKI_RTRLIB, ptr);
dabecd7c
MR
159}
160
92110aab
MR
161static void init_tr_socket(struct cache *cache)
162{
163 if (cache->type == TCP)
164 tr_tcp_init(cache->tr_config.tcp_config,
165 cache->tr_socket);
166#if defined(FOUND_SSH)
167 else
168 tr_ssh_init(cache->tr_config.ssh_config,
169 cache->tr_socket);
170#endif
171}
172
173static void free_tr_socket(struct cache *cache)
174{
175 if (cache->type == TCP)
176 tr_tcp_init(cache->tr_config.tcp_config,
177 cache->tr_socket);
178#if defined(FOUND_SSH)
179 else
180 tr_ssh_init(cache->tr_config.ssh_config,
181 cache->tr_socket);
182#endif
183}
184
dabecd7c 185static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
898c4e66 186 const struct prefix *prefix);
dabecd7c 187
1dacdd8b
MR
188static void ipv6_addr_to_network_byte_order(const uint32_t *src, uint32_t *dest)
189{
190 int i;
191
192 for (i = 0; i < 4; i++)
193 dest[i] = htonl(src[i]);
194}
195
e4234602
MR
196static void ipv6_addr_to_host_byte_order(const uint32_t *src, uint32_t *dest)
197{
198 int i;
199
200 for (i = 0; i < 4; i++)
201 dest[i] = ntohl(src[i]);
202}
203
b68885f9
LK
204static enum route_map_cmd_result_t route_match(void *rule,
205 const struct prefix *prefix,
b68885f9 206 void *object)
dabecd7c
MR
207{
208 int *rpki_status = rule;
9b6d8fcf 209 struct bgp_path_info *path;
dabecd7c 210
1782514f 211 path = object;
dabecd7c 212
1782514f
DS
213 if (rpki_validate_prefix(path->peer, path->attr, prefix)
214 == *rpki_status) {
215 return RMAP_MATCH;
dabecd7c 216 }
1782514f 217
dabecd7c
MR
218 return RMAP_NOMATCH;
219}
220
221static void *route_match_compile(const char *arg)
222{
223 int *rpki_status;
224
0b2c4b35 225 rpki_status = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(int));
dabecd7c
MR
226
227 if (strcmp(arg, "valid") == 0)
228 *rpki_status = RPKI_VALID;
229 else if (strcmp(arg, "invalid") == 0)
230 *rpki_status = RPKI_INVALID;
231 else
232 *rpki_status = RPKI_NOTFOUND;
233
234 return rpki_status;
235}
236
237static void route_match_free(void *rule)
238{
239 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
240}
241
242static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket)
243{
244 struct rtr_socket *rtr_socket =
245 XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct rtr_socket));
246 rtr_socket->tr_socket = tr_socket;
247 return rtr_socket;
248}
249
250static struct cache *find_cache(const uint8_t preference)
251{
252 struct listnode *cache_node;
253 struct cache *cache;
254
255 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
256 if (cache->preference == preference)
257 return cache;
258 }
259 return NULL;
260}
261
8156765a
DA
262static void rpki_delete_all_cache_nodes(void)
263{
264 struct listnode *cache_node, *cache_next;
265 struct cache *cache;
266
267 for (ALL_LIST_ELEMENTS(cache_list, cache_node, cache_next, cache)) {
268 rtr_mgr_remove_group(rtr_config, cache->preference);
269 listnode_delete(cache_list, cache);
270 }
271}
272
dff41cc8 273static void print_record(const struct pfx_record *record, struct vty *vty,
6ccfd103 274 json_object *json, enum asnotation_mode asnotation)
dabecd7c
MR
275{
276 char ip[INET6_ADDRSTRLEN];
dff41cc8 277 json_object *json_record = NULL;
5d799192
MR
278
279 lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
dff41cc8
DA
280
281 if (!json) {
6ccfd103
PG
282 vty_out(vty, "%-40s %3u - %3u ", ip, record->min_len,
283 record->max_len);
284 vty_out(vty, ASN_FORMAT(asnotation), &record->asn);
285 vty_out(vty, "\n");
dff41cc8
DA
286 } else {
287 json_record = json_object_new_object();
288 json_object_string_add(json_record, "prefix", ip);
289 json_object_int_add(json_record, "prefixLenMin",
290 record->min_len);
291 json_object_int_add(json_record, "prefixLenMax",
292 record->max_len);
6ccfd103 293 asn_asn2json(json_record, "asn", record->asn, asnotation);
dff41cc8
DA
294 json_object_array_add(json, json_record);
295 }
5d799192
MR
296}
297
02334bb2
DA
298static void print_record_by_asn(const struct pfx_record *record, void *data)
299{
300 struct rpki_for_each_record_arg *arg = data;
301 struct vty *vty = arg->vty;
302
303 if (record->asn == arg->as) {
304 (*arg->prefix_amount)++;
6ccfd103 305 print_record(record, vty, arg->json, arg->asnotation);
02334bb2
DA
306 }
307}
308
5d799192
MR
309static void print_record_cb(const struct pfx_record *record, void *data)
310{
dabecd7c
MR
311 struct rpki_for_each_record_arg *arg = data;
312 struct vty *vty = arg->vty;
313
a220aec6 314 (*arg->prefix_amount)++;
dabecd7c 315
6ccfd103 316 print_record(record, vty, arg->json, arg->asnotation);
dabecd7c
MR
317}
318
319static struct rtr_mgr_group *get_groups(void)
320{
321 struct listnode *cache_node;
322 struct rtr_mgr_group *rtr_mgr_groups;
323 struct cache *cache;
324
325 int group_count = listcount(cache_list);
326
327 if (group_count == 0)
328 return NULL;
329
330 rtr_mgr_groups = XMALLOC(MTYPE_BGP_RPKI_CACHE_GROUP,
331 group_count * sizeof(struct rtr_mgr_group));
332
333 size_t i = 0;
334
335 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
336 rtr_mgr_groups[i].sockets = &cache->rtr_socket;
337 rtr_mgr_groups[i].sockets_len = 1;
338 rtr_mgr_groups[i].preference = cache->preference;
339
92110aab 340 init_tr_socket(cache);
dabecd7c
MR
341
342 i++;
343 }
344
345 return rtr_mgr_groups;
346}
347
d67485c6 348inline bool is_synchronized(void)
dabecd7c 349{
d67485c6 350 return rtr_is_synced;
dabecd7c
MR
351}
352
0e3d96bf 353inline bool is_running(void)
dabecd7c
MR
354{
355 return rtr_is_running;
356}
357
0e3d96bf 358inline bool is_stopping(void)
9ca44fc8
DA
359{
360 return rtr_is_stopping;
361}
362
fc15f734
DS
363static void pfx_record_to_prefix(struct pfx_record *record,
364 struct prefix *prefix)
1dacdd8b 365{
1dacdd8b
MR
366 prefix->prefixlen = record->min_len;
367
368 if (record->prefix.ver == LRTR_IPV4) {
369 prefix->family = AF_INET;
370 prefix->u.prefix4.s_addr = htonl(record->prefix.u.addr4.addr);
371 } else {
372 prefix->family = AF_INET6;
373 ipv6_addr_to_network_byte_order(record->prefix.u.addr6.addr,
374 prefix->u.prefix6.s6_addr32);
375 }
1dacdd8b
MR
376}
377
7f1f9314
DS
378struct rpki_revalidate_prefix {
379 struct bgp *bgp;
380 struct prefix prefix;
381 afi_t afi;
382 safi_t safi;
383};
384
385static void rpki_revalidate_prefix(struct thread *thread)
386{
387 struct rpki_revalidate_prefix *rrp = THREAD_ARG(thread);
388 struct bgp_dest *match, *node;
389
390 match = bgp_table_subtree_lookup(rrp->bgp->rib[rrp->afi][rrp->safi],
391 &rrp->prefix);
31d0363f 392
7f1f9314
DS
393 node = match;
394
395 while (node) {
396 if (bgp_dest_has_bgp_path_info_data(node)) {
397 revalidate_bgp_node(node, rrp->afi, rrp->safi);
398 }
399
400 node = bgp_route_next_until(node, match);
401 }
402
7f1f9314
DS
403 XFREE(MTYPE_BGP_RPKI_REVALIDATE, rrp);
404}
405
cc9f21da 406static void bgpd_sync_callback(struct thread *thread)
1dacdd8b
MR
407{
408 struct bgp *bgp;
409 struct listnode *node;
fc15f734 410 struct prefix prefix;
1dacdd8b
MR
411 struct pfx_record rec;
412
d2e3f8a2
DA
413 thread_add_read(bm->master, bgpd_sync_callback, NULL,
414 rpki_sync_socket_bgpd, NULL);
4ce82676
MR
415
416 if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) {
d2e3f8a2
DA
417 while (read(rpki_sync_socket_bgpd, &rec,
418 sizeof(struct pfx_record)) != -1)
4ce82676
MR
419 ;
420
421 atomic_store_explicit(&rtr_update_overflow, 0,
422 memory_order_seq_cst);
423 revalidate_all_routes();
cc9f21da 424 return;
4ce82676
MR
425 }
426
d2e3f8a2
DA
427 int retval =
428 read(rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record));
3b128228 429 if (retval != sizeof(struct pfx_record)) {
d2e3f8a2 430 RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd");
cc9f21da 431 return;
38775a3c 432 }
fc15f734 433 pfx_record_to_prefix(&rec, &prefix);
1dacdd8b
MR
434
435 afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
436
437 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
35a1e798 438 safi_t safi;
1dacdd8b 439
35a1e798 440 for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
7e7f61ed 441 struct bgp_table *table = bgp->rib[afi][safi];
7f1f9314 442 struct rpki_revalidate_prefix *rrp;
7e7f61ed
DA
443
444 if (!table)
35a1e798 445 continue;
31a2af32 446
7f1f9314
DS
447 rrp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE, sizeof(*rrp));
448 rrp->bgp = bgp;
449 rrp->prefix = prefix;
450 rrp->afi = afi;
451 rrp->safi = safi;
452 thread_add_event(bm->master, rpki_revalidate_prefix,
453 rrp, 0, &bgp->t_revalidate[afi][safi]);
1dacdd8b
MR
454 }
455 }
1dacdd8b
MR
456}
457
9bcb3eef 458static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi,
1dacdd8b
MR
459 safi_t safi)
460{
461 struct bgp_adj_in *ain;
462
9bcb3eef 463 for (ain = bgp_dest->adj_in; ain; ain = ain->next) {
2b964e86 464 struct bgp_path_info *path =
9bcb3eef 465 bgp_dest_get_bgp_path_info(bgp_dest);
1dacdd8b
MR
466 mpls_label_t *label = NULL;
467 uint32_t num_labels = 0;
468
9b6d8fcf
DS
469 if (path && path->extra) {
470 label = path->extra->label;
471 num_labels = path->extra->num_labels;
1dacdd8b 472 }
73261b47 473 (void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest),
b54892e0
DS
474 ain->addpath_rx_id, ain->attr, afi, safi,
475 ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label,
476 num_labels, 1, NULL);
1dacdd8b
MR
477 }
478}
479
7651f277
DS
480/*
481 * The act of a soft reconfig in revalidation is really expensive
482 * coupled with the fact that the download of a full rpki state
483 * from a rpki server can be expensive, let's break up the revalidation
484 * to a point in time in the future to allow other bgp events
485 * to take place too.
486 */
487struct rpki_revalidate_peer {
488 afi_t afi;
489 safi_t safi;
490 struct peer *peer;
491};
492
493static void bgp_rpki_revalidate_peer(struct thread *thread)
494{
495 struct rpki_revalidate_peer *rvp = THREAD_ARG(thread);
496
497 /*
498 * Here's the expensive bit of gnomish deviousness
499 */
500 bgp_soft_reconfig_in(rvp->peer, rvp->afi, rvp->safi);
501
502 XFREE(MTYPE_BGP_RPKI_REVALIDATE, rvp);
503}
504
1dacdd8b
MR
505static void revalidate_all_routes(void)
506{
507 struct bgp *bgp;
508 struct listnode *node;
1dacdd8b
MR
509
510 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
31a2af32
MR
511 struct peer *peer;
512 struct listnode *peer_listnode;
1dacdd8b 513
31a2af32 514 for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) {
8fb15d02
DS
515 afi_t afi;
516 safi_t safi;
31a2af32 517
8fb15d02 518 FOREACH_AFI_SAFI (afi, safi) {
7651f277
DS
519 struct rpki_revalidate_peer *rvp;
520
802ca11f 521 if (!bgp->rib[afi][safi])
8fb15d02 522 continue;
d2e3f8a2 523
89c73443
DS
524 if (!peer_established(peer))
525 continue;
7651f277
DS
526
527 rvp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE,
528 sizeof(*rvp));
529 rvp->peer = peer;
530 rvp->afi = afi;
531 rvp->safi = safi;
532
533 thread_add_event(
534 bm->master, bgp_rpki_revalidate_peer,
535 rvp, 0,
536 &peer->t_revalidate_all[afi][safi]);
1dacdd8b
MR
537 }
538 }
539 }
540}
541
542static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)),
543 const struct pfx_record rec,
544 const bool added __attribute__((unused)))
545{
9ca44fc8
DA
546 if (is_stopping() ||
547 atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst))
1dacdd8b
MR
548 return;
549
550 int retval =
551 write(rpki_sync_socket_rtr, &rec, sizeof(struct pfx_record));
4ce82676
MR
552 if (retval == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
553 atomic_store_explicit(&rtr_update_overflow, 1,
554 memory_order_seq_cst);
555
556 else if (retval != sizeof(struct pfx_record))
1dacdd8b
MR
557 RPKI_DEBUG("Could not write to rpki_sync_socket_rtr");
558}
559
560static void rpki_init_sync_socket(void)
561{
562 int fds[2];
4ce82676 563 const char *msg;
1dacdd8b
MR
564
565 RPKI_DEBUG("initializing sync socket");
566 if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fds) != 0) {
4ce82676
MR
567 msg = "could not open rpki sync socketpair";
568 goto err;
1dacdd8b
MR
569 }
570 rpki_sync_socket_rtr = fds[0];
571 rpki_sync_socket_bgpd = fds[1];
4ce82676
MR
572
573 if (set_nonblocking(rpki_sync_socket_rtr) != 0) {
574 msg = "could not set rpki_sync_socket_rtr to non blocking";
575 goto err;
576 }
577
578 if (set_nonblocking(rpki_sync_socket_bgpd) != 0) {
579 msg = "could not set rpki_sync_socket_bgpd to non blocking";
580 goto err;
581 }
582
d2e3f8a2 583
1dacdd8b 584 thread_add_read(bm->master, bgpd_sync_callback, NULL,
d2e3f8a2 585 rpki_sync_socket_bgpd, NULL);
4ce82676
MR
586
587 return;
588
589err:
590 zlog_err("RPKI: %s", msg);
591 abort();
592
1dacdd8b
MR
593}
594
dabecd7c
MR
595static int bgp_rpki_init(struct thread_master *master)
596{
0e3d96bf
DA
597 rpki_debug = false;
598 rtr_is_running = false;
599 rtr_is_stopping = false;
d67485c6 600 rtr_is_synced = false;
dabecd7c
MR
601
602 cache_list = list_new();
996c9314 603 cache_list->del = (void (*)(void *)) & free_cache;
dabecd7c
MR
604
605 polling_period = POLLING_PERIOD_DEFAULT;
606 expire_interval = EXPIRE_INTERVAL_DEFAULT;
607 retry_interval = RETRY_INTERVAL_DEFAULT;
dabecd7c 608 install_cli_commands();
1dacdd8b 609 rpki_init_sync_socket();
dabecd7c
MR
610 return 0;
611}
612
613static int bgp_rpki_fini(void)
614{
615 stop();
6a154c88 616 list_delete(&cache_list);
dabecd7c 617
1dacdd8b
MR
618 close(rpki_sync_socket_rtr);
619 close(rpki_sync_socket_bgpd);
620
dabecd7c
MR
621 return 0;
622}
623
624static int bgp_rpki_module_init(void)
625{
996c9314 626 lrtr_set_alloc_functions(malloc_wrapper, realloc_wrapper, free_wrapper);
dabecd7c 627
b5b99af8 628 hook_register(bgp_rpki_prefix_status, rpki_validate_prefix);
dabecd7c 629 hook_register(frr_late_init, bgp_rpki_init);
f714e57a 630 hook_register(frr_early_fini, bgp_rpki_fini);
dabecd7c
MR
631
632 return 0;
633}
634
d67485c6 635static void sync_expired(struct thread *thread)
1b2095d1
DA
636{
637 if (!rtr_mgr_conf_in_sync(rtr_config)) {
d67485c6
DA
638 RPKI_DEBUG("rtr_mgr is not synced, retrying.");
639 thread_add_timer(bm->master, sync_expired, NULL,
1b2095d1 640 BGP_RPKI_CACHE_SERVER_SYNC_RETRY_TIMEOUT,
d67485c6 641 &t_rpki_sync);
1b2095d1
DA
642 return;
643 }
644
d67485c6
DA
645 RPKI_DEBUG("rtr_mgr sync is done.");
646
647 rtr_is_synced = true;
1b2095d1
DA
648}
649
dabecd7c
MR
650static int start(void)
651{
dabecd7c
MR
652 int ret;
653
0e3d96bf 654 rtr_is_stopping = false;
d67485c6 655 rtr_is_synced = false;
4ce82676 656 rtr_update_overflow = 0;
1dacdd8b 657
dabecd7c
MR
658 if (list_isempty(cache_list)) {
659 RPKI_DEBUG(
660 "No caches were found in config. Prefix validation is off.");
661 return ERROR;
662 }
663 RPKI_DEBUG("Init rtr_mgr.");
664 int groups_len = listcount(cache_list);
665 struct rtr_mgr_group *groups = get_groups();
666
1dacdd8b 667 RPKI_DEBUG("Polling period: %d", polling_period);
dabecd7c 668 ret = rtr_mgr_init(&rtr_config, groups, groups_len, polling_period,
1dacdd8b 669 expire_interval, retry_interval,
d2e3f8a2 670 rpki_update_cb_sync_rtr, NULL, NULL, NULL);
dabecd7c
MR
671 if (ret == RTR_ERROR) {
672 RPKI_DEBUG("Init rtr_mgr failed.");
673 return ERROR;
674 }
675
676 RPKI_DEBUG("Starting rtr_mgr.");
677 ret = rtr_mgr_start(rtr_config);
678 if (ret == RTR_ERROR) {
679 RPKI_DEBUG("Starting rtr_mgr failed.");
680 rtr_mgr_free(rtr_config);
681 return ERROR;
682 }
1b2095d1 683
d67485c6 684 thread_add_timer(bm->master, sync_expired, NULL, 0, &t_rpki_sync);
dabecd7c
MR
685
686 XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups);
687
0e3d96bf 688 rtr_is_running = true;
d67485c6 689
dabecd7c
MR
690 return SUCCESS;
691}
692
693static void stop(void)
694{
0e3d96bf 695 rtr_is_stopping = true;
01fcc189 696 if (is_running()) {
d67485c6 697 THREAD_OFF(t_rpki_sync);
dabecd7c
MR
698 rtr_mgr_stop(rtr_config);
699 rtr_mgr_free(rtr_config);
0e3d96bf 700 rtr_is_running = false;
dabecd7c
MR
701 }
702}
703
704static int reset(bool force)
705{
01fcc189 706 if (is_running() && !force)
dabecd7c
MR
707 return SUCCESS;
708
709 RPKI_DEBUG("Resetting RPKI Session");
710 stop();
711 return start();
712}
713
714static struct rtr_mgr_group *get_connected_group(void)
715{
18b91526 716 if (!cache_list || list_isempty(cache_list))
dabecd7c
MR
717 return NULL;
718
719 return rtr_mgr_get_first_group(rtr_config);
720}
721
dff41cc8
DA
722static void print_prefix_table_by_asn(struct vty *vty, as_t as,
723 json_object *json)
02334bb2
DA
724{
725 unsigned int number_of_ipv4_prefixes = 0;
726 unsigned int number_of_ipv6_prefixes = 0;
727 struct rtr_mgr_group *group = get_connected_group();
728 struct rpki_for_each_record_arg arg;
dff41cc8 729 json_object *json_records = NULL;
02334bb2
DA
730
731 arg.vty = vty;
732 arg.as = as;
dff41cc8 733 arg.json = NULL;
6ccfd103 734 arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT));
02334bb2
DA
735
736 if (!group) {
dff41cc8
DA
737 if (!json)
738 vty_out(vty, "Cannot find a connected group.\n");
02334bb2
DA
739 return;
740 }
741
742 struct pfx_table *pfx_table = group->sockets[0]->pfx_table;
743
dff41cc8
DA
744 if (!json) {
745 vty_out(vty, "RPKI/RTR prefix table\n");
746 vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
747 "Origin-AS");
748 } else {
749 json_records = json_object_new_array();
750 json_object_object_add(json, "prefixes", json_records);
751 arg.json = json_records;
752 }
02334bb2
DA
753
754 arg.prefix_amount = &number_of_ipv4_prefixes;
755 pfx_table_for_each_ipv4_record(pfx_table, print_record_by_asn, &arg);
756
757 arg.prefix_amount = &number_of_ipv6_prefixes;
758 pfx_table_for_each_ipv6_record(pfx_table, print_record_by_asn, &arg);
759
dff41cc8
DA
760 if (!json) {
761 vty_out(vty, "Number of IPv4 Prefixes: %u\n",
762 number_of_ipv4_prefixes);
763 vty_out(vty, "Number of IPv6 Prefixes: %u\n",
764 number_of_ipv6_prefixes);
765 } else {
766 json_object_int_add(json, "ipv4PrefixCount",
767 number_of_ipv4_prefixes);
768 json_object_int_add(json, "ipv6PrefixCount",
769 number_of_ipv6_prefixes);
770 }
771
772 if (json)
773 vty_json(vty, json);
02334bb2
DA
774}
775
dff41cc8 776static void print_prefix_table(struct vty *vty, json_object *json)
dabecd7c
MR
777{
778 struct rpki_for_each_record_arg arg;
779
780 unsigned int number_of_ipv4_prefixes = 0;
781 unsigned int number_of_ipv6_prefixes = 0;
782 struct rtr_mgr_group *group = get_connected_group();
dff41cc8 783 json_object *json_records = NULL;
dabecd7c
MR
784
785 arg.vty = vty;
dff41cc8 786 arg.json = NULL;
6ccfd103 787 arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT));
dabecd7c 788
dff41cc8
DA
789 if (!group) {
790 if (!json)
791 vty_out(vty, "Cannot find a connected group.\n");
dabecd7c 792 return;
dff41cc8 793 }
dabecd7c
MR
794
795 struct pfx_table *pfx_table = group->sockets[0]->pfx_table;
796
dff41cc8
DA
797 if (!json) {
798 vty_out(vty, "RPKI/RTR prefix table\n");
799 vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
800 "Origin-AS");
801 } else {
802 json_records = json_object_new_array();
803 json_object_object_add(json, "prefixes", json_records);
804 arg.json = json_records;
805 }
dabecd7c
MR
806
807 arg.prefix_amount = &number_of_ipv4_prefixes;
5d799192 808 pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg);
dabecd7c
MR
809
810 arg.prefix_amount = &number_of_ipv6_prefixes;
5d799192 811 pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg);
dabecd7c 812
dff41cc8
DA
813 if (!json) {
814 vty_out(vty, "Number of IPv4 Prefixes: %u\n",
815 number_of_ipv4_prefixes);
816 vty_out(vty, "Number of IPv6 Prefixes: %u\n",
817 number_of_ipv6_prefixes);
818 } else {
819 json_object_int_add(json, "ipv4PrefixCount",
820 number_of_ipv4_prefixes);
821 json_object_int_add(json, "ipv6PrefixCount",
822 number_of_ipv6_prefixes);
823 }
824
825 if (json)
826 vty_json(vty, json);
dabecd7c
MR
827}
828
829static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
898c4e66 830 const struct prefix *prefix)
dabecd7c
MR
831{
832 struct assegment *as_segment;
833 as_t as_number = 0;
834 struct lrtr_ip_addr ip_addr_prefix;
835 enum pfxv_state result;
dabecd7c
MR
836
837 if (!is_synchronized())
e1a05dd4 838 return RPKI_NOT_BEING_USED;
dabecd7c
MR
839
840 // No aspath means route comes from iBGP
841 if (!attr->aspath || !attr->aspath->segments) {
842 // Set own as number
843 as_number = peer->bgp->as;
844 } else {
845 as_segment = attr->aspath->segments;
846 // Find last AsSegment
847 while (as_segment->next)
848 as_segment = as_segment->next;
849
850 if (as_segment->type == AS_SEQUENCE) {
851 // Get rightmost asn
852 as_number = as_segment->as[as_segment->length - 1];
996c9314
LB
853 } else if (as_segment->type == AS_CONFED_SEQUENCE
854 || as_segment->type == AS_CONFED_SET) {
dabecd7c
MR
855 // Set own as number
856 as_number = peer->bgp->as;
857 } else {
858 // RFC says: "Take distinguished value NONE as asn"
859 // which means state is unknown
860 return RPKI_NOTFOUND;
861 }
862 }
863
864 // Get the prefix in requested format
865 switch (prefix->family) {
866 case AF_INET:
867 ip_addr_prefix.ver = LRTR_IPV4;
868 ip_addr_prefix.u.addr4.addr = ntohl(prefix->u.prefix4.s_addr);
869 break;
870
dabecd7c
MR
871 case AF_INET6:
872 ip_addr_prefix.ver = LRTR_IPV6;
873 ipv6_addr_to_host_byte_order(prefix->u.prefix6.s6_addr32,
874 ip_addr_prefix.u.addr6.addr);
875 break;
dabecd7c
MR
876
877 default:
e1a05dd4 878 return RPKI_NOT_BEING_USED;
dabecd7c
MR
879 }
880
881 // Do the actual validation
882 rtr_mgr_validate(rtr_config, as_number, &ip_addr_prefix,
883 prefix->prefixlen, &result);
884
885 // Print Debug output
dabecd7c
MR
886 switch (result) {
887 case BGP_PFXV_STATE_VALID:
888 RPKI_DEBUG(
2dbe669b
DA
889 "Validating Prefix %pFX from asn %u Result: VALID",
890 prefix, as_number);
dabecd7c
MR
891 return RPKI_VALID;
892 case BGP_PFXV_STATE_NOT_FOUND:
893 RPKI_DEBUG(
2dbe669b
DA
894 "Validating Prefix %pFX from asn %u Result: NOT FOUND",
895 prefix, as_number);
dabecd7c
MR
896 return RPKI_NOTFOUND;
897 case BGP_PFXV_STATE_INVALID:
898 RPKI_DEBUG(
2dbe669b
DA
899 "Validating Prefix %pFX from asn %u Result: INVALID",
900 prefix, as_number);
dabecd7c
MR
901 return RPKI_INVALID;
902 default:
903 RPKI_DEBUG(
2dbe669b
DA
904 "Validating Prefix %pFX from asn %u Result: CANNOT VALIDATE",
905 prefix, as_number);
dabecd7c
MR
906 break;
907 }
e1a05dd4 908 return RPKI_NOT_BEING_USED;
dabecd7c
MR
909}
910
911static int add_cache(struct cache *cache)
912{
913 uint8_t preference = cache->preference;
914 struct rtr_mgr_group group;
915
916 group.preference = preference;
917 group.sockets_len = 1;
918 group.sockets = &cache->rtr_socket;
919
01fcc189 920 if (is_running()) {
92110aab
MR
921 init_tr_socket(cache);
922
923 if (rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) {
924 free_tr_socket(cache);
925 return ERROR;
926 }
dabecd7c
MR
927 }
928
6893064b
MR
929 listnode_add(cache_list, cache);
930
dabecd7c
MR
931 return SUCCESS;
932}
933
996c9314 934static int add_tcp_cache(const char *host, const char *port,
7253a7bc 935 const uint8_t preference, const char *bindaddr)
dabecd7c
MR
936{
937 struct rtr_socket *rtr_socket;
938 struct tr_tcp_config *tcp_config =
a633498e 939 XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_tcp_config));
dabecd7c
MR
940 struct tr_socket *tr_socket =
941 XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_socket));
942 struct cache *cache =
943 XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct cache));
944
945 tcp_config->host = XSTRDUP(MTYPE_BGP_RPKI_CACHE, host);
946 tcp_config->port = XSTRDUP(MTYPE_BGP_RPKI_CACHE, port);
7253a7bc
PG
947 if (bindaddr)
948 tcp_config->bindaddr = XSTRDUP(MTYPE_BGP_RPKI_CACHE, bindaddr);
949 else
950 tcp_config->bindaddr = NULL;
dabecd7c
MR
951
952 rtr_socket = create_rtr_socket(tr_socket);
953
954 cache->type = TCP;
955 cache->tr_socket = tr_socket;
956 cache->tr_config.tcp_config = tcp_config;
957 cache->rtr_socket = rtr_socket;
958 cache->preference = preference;
959
6893064b
MR
960 int ret = add_cache(cache);
961 if (ret != SUCCESS) {
962 free_cache(cache);
963 }
964
965 return ret;
dabecd7c
MR
966}
967
968#if defined(FOUND_SSH)
996c9314
LB
969static int add_ssh_cache(const char *host, const unsigned int port,
970 const char *username, const char *client_privkey_path,
dabecd7c 971 const char *server_pubkey_path,
7253a7bc 972 const uint8_t preference, const char *bindaddr)
dabecd7c
MR
973{
974 struct tr_ssh_config *ssh_config =
a633498e 975 XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_ssh_config));
dabecd7c
MR
976 struct cache *cache =
977 XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct cache));
978 struct tr_socket *tr_socket =
979 XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_socket));
980 struct rtr_socket *rtr_socket;
981
982 ssh_config->port = port;
983 ssh_config->host = XSTRDUP(MTYPE_BGP_RPKI_CACHE, host);
7253a7bc
PG
984 if (bindaddr)
985 ssh_config->bindaddr = XSTRDUP(MTYPE_BGP_RPKI_CACHE, bindaddr);
986 else
987 ssh_config->bindaddr = NULL;
dabecd7c
MR
988
989 ssh_config->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username);
996c9314
LB
990 ssh_config->client_privkey_path =
991 XSTRDUP(MTYPE_BGP_RPKI_CACHE, client_privkey_path);
dabecd7c
MR
992 ssh_config->server_hostkey_path =
993 XSTRDUP(MTYPE_BGP_RPKI_CACHE, server_pubkey_path);
994
995 rtr_socket = create_rtr_socket(tr_socket);
996
997 cache->type = SSH;
998 cache->tr_socket = tr_socket;
999 cache->tr_config.ssh_config = ssh_config;
1000 cache->rtr_socket = rtr_socket;
1001 cache->preference = preference;
1002
6893064b
MR
1003 int ret = add_cache(cache);
1004 if (ret != SUCCESS) {
1005 free_cache(cache);
1006 }
1007
1008 return ret;
dabecd7c
MR
1009}
1010#endif
1011
1012static void free_cache(struct cache *cache)
1013{
1014 if (cache->type == TCP) {
996c9314
LB
1015 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.tcp_config->host);
1016 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.tcp_config->port);
c41a3cc5
DA
1017 XFREE(MTYPE_BGP_RPKI_CACHE,
1018 cache->tr_config.tcp_config->bindaddr);
dabecd7c
MR
1019 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.tcp_config);
1020 }
1021#if defined(FOUND_SSH)
1022 else {
996c9314 1023 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.ssh_config->host);
dabecd7c
MR
1024 XFREE(MTYPE_BGP_RPKI_CACHE,
1025 cache->tr_config.ssh_config->username);
1026 XFREE(MTYPE_BGP_RPKI_CACHE,
1027 cache->tr_config.ssh_config->client_privkey_path);
1028 XFREE(MTYPE_BGP_RPKI_CACHE,
1029 cache->tr_config.ssh_config->server_hostkey_path);
c41a3cc5
DA
1030 XFREE(MTYPE_BGP_RPKI_CACHE,
1031 cache->tr_config.ssh_config->bindaddr);
dabecd7c
MR
1032 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.ssh_config);
1033 }
1034#endif
1035 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_socket);
1036 XFREE(MTYPE_BGP_RPKI_CACHE, cache->rtr_socket);
1037 XFREE(MTYPE_BGP_RPKI_CACHE, cache);
1038}
1039
1040static int config_write(struct vty *vty)
1041{
1042 struct listnode *cache_node;
1043 struct cache *cache;
1044
708b8053
DS
1045 if (rpki_debug)
1046 vty_out(vty, "debug rpki\n");
1047
1048 vty_out(vty, "!\n");
1049 vty_out(vty, "rpki\n");
9a651153 1050
8f401cda
DA
1051 if (polling_period != POLLING_PERIOD_DEFAULT)
1052 vty_out(vty, " rpki polling_period %d\n", polling_period);
9a651153
DS
1053 if (retry_interval != RETRY_INTERVAL_DEFAULT)
1054 vty_out(vty, " rpki retry_interval %d\n", retry_interval);
1055 if (expire_interval != EXPIRE_INTERVAL_DEFAULT)
1056 vty_out(vty, " rpki expire_interval %d\n", expire_interval);
1057
708b8053
DS
1058 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
1059 switch (cache->type) {
1060 struct tr_tcp_config *tcp_config;
acd4a9f4 1061#if defined(FOUND_SSH)
708b8053 1062 struct tr_ssh_config *ssh_config;
acd4a9f4 1063#endif
708b8053
DS
1064 case TCP:
1065 tcp_config = cache->tr_config.tcp_config;
484fc374 1066 vty_out(vty, " rpki cache %s %s ", tcp_config->host,
708b8053 1067 tcp_config->port);
484fc374
IR
1068 if (tcp_config->bindaddr)
1069 vty_out(vty, "source %s ",
1070 tcp_config->bindaddr);
708b8053 1071 break;
dabecd7c 1072#if defined(FOUND_SSH)
708b8053
DS
1073 case SSH:
1074 ssh_config = cache->tr_config.ssh_config;
484fc374
IR
1075 vty_out(vty, " rpki cache %s %u %s %s %s ",
1076 ssh_config->host, ssh_config->port,
1077 ssh_config->username,
708b8053
DS
1078 ssh_config->client_privkey_path,
1079 ssh_config->server_hostkey_path != NULL
1080 ? ssh_config->server_hostkey_path
1081 : " ");
484fc374
IR
1082 if (ssh_config->bindaddr)
1083 vty_out(vty, "source %s ",
1084 ssh_config->bindaddr);
708b8053 1085 break;
dabecd7c 1086#endif
708b8053
DS
1087 default:
1088 break;
dabecd7c 1089 }
708b8053
DS
1090
1091 vty_out(vty, "preference %hhu\n", cache->preference);
dabecd7c 1092 }
07679ad9 1093 vty_out(vty, "exit\n");
708b8053
DS
1094
1095 return 1;
dabecd7c
MR
1096}
1097
1098DEFUN_NOSH (rpki,
1099 rpki_cmd,
1100 "rpki",
1101 "Enable rpki and enter rpki configuration mode\n")
1102{
1103 vty->node = RPKI_NODE;
1104 return CMD_SUCCESS;
1105}
1106
8156765a
DA
1107DEFPY (no_rpki,
1108 no_rpki_cmd,
1109 "no rpki",
1110 NO_STR
1111 "Enable rpki and enter rpki configuration mode\n")
1112{
1113 rpki_delete_all_cache_nodes();
1114 stop();
1115 return CMD_SUCCESS;
1116}
1117
dabecd7c
MR
1118DEFUN (bgp_rpki_start,
1119 bgp_rpki_start_cmd,
1120 "rpki start",
1121 RPKI_OUTPUT_STRING
1122 "start rpki support\n")
1123{
1124 if (listcount(cache_list) == 0)
996c9314
LB
1125 vty_out(vty,
1126 "Could not start rpki because no caches are configured\n");
dabecd7c
MR
1127
1128 if (!is_running()) {
1129 if (start() == ERROR) {
1130 RPKI_DEBUG("RPKI failed to start");
1131 return CMD_WARNING;
1132 }
1133 }
1134 return CMD_SUCCESS;
1135}
1136
1137DEFUN (bgp_rpki_stop,
1138 bgp_rpki_stop_cmd,
1139 "rpki stop",
1140 RPKI_OUTPUT_STRING
1141 "start rpki support\n")
1142{
1143 if (is_running())
1144 stop();
1145
1146 return CMD_SUCCESS;
1147}
1148
1149DEFPY (rpki_polling_period,
1150 rpki_polling_period_cmd,
1151 "rpki polling_period (1-86400)$pp",
1152 RPKI_OUTPUT_STRING
1153 "Set polling period\n"
1154 "Polling period value\n")
1155{
1156 polling_period = pp;
1157 return CMD_SUCCESS;
1158}
1159
1160DEFUN (no_rpki_polling_period,
1161 no_rpki_polling_period_cmd,
e9f709e5 1162 "no rpki polling_period [(1-86400)]",
dabecd7c
MR
1163 NO_STR
1164 RPKI_OUTPUT_STRING
e9f709e5
DS
1165 "Set polling period back to default\n"
1166 "Polling period value\n")
dabecd7c
MR
1167{
1168 polling_period = POLLING_PERIOD_DEFAULT;
1169 return CMD_SUCCESS;
1170}
1171
1172DEFPY (rpki_expire_interval,
1173 rpki_expire_interval_cmd,
1174 "rpki expire_interval (600-172800)$tmp",
1175 RPKI_OUTPUT_STRING
1176 "Set expire interval\n"
1177 "Expire interval value\n")
1178{
6f577f58 1179 if ((unsigned int)tmp >= polling_period) {
dabecd7c
MR
1180 expire_interval = tmp;
1181 return CMD_SUCCESS;
1182 }
1183
1184 vty_out(vty, "%% Expiry interval must be polling period or larger\n");
1185 return CMD_WARNING_CONFIG_FAILED;
1186}
1187
1188DEFUN (no_rpki_expire_interval,
1189 no_rpki_expire_interval_cmd,
e9f709e5 1190 "no rpki expire_interval [(600-172800)]",
dabecd7c
MR
1191 NO_STR
1192 RPKI_OUTPUT_STRING
e9f709e5
DS
1193 "Set expire interval back to default\n"
1194 "Expire interval value\n")
dabecd7c
MR
1195{
1196 expire_interval = polling_period * 2;
1197 return CMD_SUCCESS;
1198}
1199
1200DEFPY (rpki_retry_interval,
1201 rpki_retry_interval_cmd,
1202 "rpki retry_interval (1-7200)$tmp",
1203 RPKI_OUTPUT_STRING
1204 "Set retry interval\n"
1205 "retry interval value\n")
1206{
1207 retry_interval = tmp;
1208 return CMD_SUCCESS;
1209}
1210
1211DEFUN (no_rpki_retry_interval,
1212 no_rpki_retry_interval_cmd,
e9f709e5 1213 "no rpki retry_interval [(1-7200)]",
dabecd7c
MR
1214 NO_STR
1215 RPKI_OUTPUT_STRING
e9f709e5
DS
1216 "Set retry interval back to default\n"
1217 "retry interval value\n")
dabecd7c
MR
1218{
1219 retry_interval = RETRY_INTERVAL_DEFAULT;
1220 return CMD_SUCCESS;
1221}
1222
7253a7bc 1223DEFPY(rpki_cache, rpki_cache_cmd,
2a5f5ec0 1224 "rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [SERVER_PUBKEY]> [source <A.B.C.D>$bindaddr] preference (1-255)",
7253a7bc
PG
1225 RPKI_OUTPUT_STRING
1226 "Install a cache server to current group\n"
2a5f5ec0
DA
1227 "IP address of cache server\n"
1228 "Hostname of cache server\n"
7253a7bc
PG
1229 "TCP port number\n"
1230 "SSH port number\n"
1231 "SSH user name\n"
1232 "Path to own SSH private key\n"
7253a7bc 1233 "Path to Public key of cache server\n"
484fc374
IR
1234 "Configure source IP address of RPKI connection\n"
1235 "Define a Source IP Address\n"
7253a7bc
PG
1236 "Preference of the cache server\n"
1237 "Preference value\n")
dabecd7c 1238{
3f54c705 1239 int return_value;
a2ed7b2b
MR
1240 struct listnode *cache_node;
1241 struct cache *current_cache;
1242
1243 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, current_cache)) {
1244 if (current_cache->preference == preference) {
1245 vty_out(vty,
1246 "Cache with preference %ld is already configured\n",
1247 preference);
1248 return CMD_WARNING;
1249 }
1250 }
1251
dabecd7c
MR
1252
1253 // use ssh connection
1254 if (ssh_uname) {
1255#if defined(FOUND_SSH)
2a5f5ec0
DA
1256 return_value =
1257 add_ssh_cache(cache, sshport, ssh_uname, ssh_privkey,
1258 server_pubkey, preference, bindaddr_str);
dabecd7c 1259#else
3f54c705 1260 return_value = SUCCESS;
dabecd7c 1261 vty_out(vty,
3efd0893 1262 "ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n");
dabecd7c
MR
1263#endif
1264 } else { // use tcp connection
7253a7bc
PG
1265 return_value =
1266 add_tcp_cache(cache, tcpport, preference, bindaddr_str);
dabecd7c
MR
1267 }
1268
1269 if (return_value == ERROR) {
1270 vty_out(vty, "Could not create new rpki cache\n");
1271 return CMD_WARNING;
1272 }
1273
1274 return CMD_SUCCESS;
1275}
1276
1277DEFPY (no_rpki_cache,
1278 no_rpki_cache_cmd,
2a5f5ec0 1279 "no rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [SERVER_PUBKEY]> [source <A.B.C.D>$bindaddr] preference (1-255)",
dabecd7c
MR
1280 NO_STR
1281 RPKI_OUTPUT_STRING
cc22635a 1282 "Install a cache server to current group\n"
2a5f5ec0
DA
1283 "IP address of cache server\n"
1284 "Hostname of cache server\n"
dabecd7c
MR
1285 "TCP port number\n"
1286 "SSH port number\n"
cc22635a
DA
1287 "SSH user name\n"
1288 "Path to own SSH private key\n"
cc22635a
DA
1289 "Path to Public key of cache server\n"
1290 "Configure source IP address of RPKI connection\n"
1291 "Define a Source IP Address\n"
dabecd7c
MR
1292 "Preference of the cache server\n"
1293 "Preference value\n")
1294{
1295 struct cache *cache_p = find_cache(preference);
1296
222487fe 1297 if (!cache_p) {
11423e50
DA
1298 vty_out(vty, "Could not find cache with preference %ld\n",
1299 preference);
dabecd7c
MR
1300 return CMD_WARNING;
1301 }
1302
01fcc189 1303 if (is_running() && listcount(cache_list) == 1) {
8add1719 1304 stop();
01fcc189 1305 } else if (is_running()) {
dabecd7c 1306 if (rtr_mgr_remove_group(rtr_config, preference) == RTR_ERROR) {
11423e50
DA
1307 vty_out(vty,
1308 "Could not remove cache with preference %ld\n",
1309 preference);
dabecd7c
MR
1310 return CMD_WARNING;
1311 }
1312 }
1313
1314 listnode_delete(cache_list, cache_p);
1315 free_cache(cache_p);
1316
1317 return CMD_SUCCESS;
1318}
1319
dff41cc8 1320DEFPY (show_rpki_prefix_table,
dabecd7c 1321 show_rpki_prefix_table_cmd,
dff41cc8 1322 "show rpki prefix-table [json$uj]",
dabecd7c
MR
1323 SHOW_STR
1324 RPKI_OUTPUT_STRING
dff41cc8
DA
1325 "Show validated prefixes which were received from RPKI Cache\n"
1326 JSON_STR)
dabecd7c 1327{
dff41cc8
DA
1328 struct json_object *json = NULL;
1329
1330 if (!is_synchronized()) {
1331 if (!uj)
1332 vty_out(vty, "No connection to RPKI cache server.\n");
1333 return CMD_WARNING;
1334 }
1335
1336 if (uj)
1337 json = json_object_new_object();
dabecd7c 1338
dff41cc8 1339 print_prefix_table(vty, json);
dabecd7c
MR
1340 return CMD_SUCCESS;
1341}
1342
dff41cc8
DA
1343DEFPY (show_rpki_as_number,
1344 show_rpki_as_number_cmd,
6ccfd103 1345 "show rpki as-number ASNUM$by_asn [json$uj]",
dff41cc8
DA
1346 SHOW_STR
1347 RPKI_OUTPUT_STRING
1348 "Lookup by ASN in prefix table\n"
1349 "AS Number\n"
1350 JSON_STR)
02334bb2 1351{
dff41cc8 1352 struct json_object *json = NULL;
6ccfd103 1353 as_t as;
dff41cc8 1354
02334bb2 1355 if (!is_synchronized()) {
dff41cc8
DA
1356 if (!uj)
1357 vty_out(vty, "No Connection to RPKI cache server.\n");
02334bb2
DA
1358 return CMD_WARNING;
1359 }
6ccfd103
PG
1360 if (!asn_str2asn(by_asn, &as)) {
1361 if (!uj)
1362 vty_out(vty, "Invalid AS value: %s.\n", by_asn);
1363 return CMD_WARNING;
1364 }
dff41cc8
DA
1365 if (uj)
1366 json = json_object_new_object();
1367
6ccfd103 1368 print_prefix_table_by_asn(vty, as, json);
02334bb2
DA
1369 return CMD_SUCCESS;
1370}
1371
5d799192
MR
1372DEFPY (show_rpki_prefix,
1373 show_rpki_prefix_cmd,
6ccfd103 1374 "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [ASNUM$asn] [json$uj]",
5d799192
MR
1375 SHOW_STR
1376 RPKI_OUTPUT_STRING
1377 "Lookup IP prefix and optionally ASN in prefix table\n"
1378 "IPv4 prefix\n"
1379 "IPv6 prefix\n"
dff41cc8
DA
1380 "AS Number\n"
1381 JSON_STR)
5d799192 1382{
dff41cc8
DA
1383 json_object *json = NULL;
1384 json_object *json_records = NULL;
6ccfd103
PG
1385 as_t as;
1386 enum asnotation_mode asnotation;
5d799192
MR
1387
1388 if (!is_synchronized()) {
dff41cc8
DA
1389 if (!uj)
1390 vty_out(vty, "No Connection to RPKI cache server.\n");
5d799192
MR
1391 return CMD_WARNING;
1392 }
1393
1394 struct lrtr_ip_addr addr;
1395 char addr_str[INET6_ADDRSTRLEN];
1396 size_t addr_len = strchr(prefix_str, '/') - prefix_str;
1397
1398 memset(addr_str, 0, sizeof(addr_str));
1399 memcpy(addr_str, prefix_str, addr_len);
1400
1401 if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) {
dff41cc8
DA
1402 if (!json)
1403 vty_out(vty, "Invalid IP prefix\n");
5d799192
MR
1404 return CMD_WARNING;
1405 }
1406
6ccfd103
PG
1407 if (asn && !asn_str2asn(asn, &as)) {
1408 if (!uj)
1409 vty_out(vty, "Invalid AS value: %s.\n", asn);
1410 return CMD_WARNING;
1411 }
1412
5d799192
MR
1413 struct pfx_record *matches = NULL;
1414 unsigned int match_count = 0;
1415 enum pfxv_state result;
1416
1417 if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
6ccfd103
PG
1418 as, &addr, prefix->prefixlen,
1419 &result) != PFX_SUCCESS) {
dff41cc8
DA
1420 if (!json)
1421 vty_out(vty, "Prefix lookup failed\n");
5d799192
MR
1422 return CMD_WARNING;
1423 }
1424
dff41cc8
DA
1425 if (uj)
1426 json = json_object_new_object();
1427
1428 if (!json) {
1429 vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
1430 "Origin-AS");
1431 } else {
1432 json_records = json_object_new_array();
1433 json_object_object_add(json, "prefixes", json_records);
1434 }
1435
6ccfd103 1436 asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT));
5d799192
MR
1437 for (size_t i = 0; i < match_count; ++i) {
1438 const struct pfx_record *record = &matches[i];
1439
6ccfd103
PG
1440 if (record->max_len >= prefix->prefixlen &&
1441 ((as != 0 && (uint32_t)as == record->asn) || as == 0)) {
1442 print_record(&matches[i], vty, json_records,
1443 asnotation);
5d799192
MR
1444 }
1445 }
1446
dff41cc8
DA
1447 if (json)
1448 vty_json(vty, json);
1449
5d799192
MR
1450 return CMD_SUCCESS;
1451}
1452
cc4d121f 1453DEFPY (show_rpki_cache_server,
dabecd7c 1454 show_rpki_cache_server_cmd,
cc4d121f 1455 "show rpki cache-server [json$uj]",
dabecd7c
MR
1456 SHOW_STR
1457 RPKI_OUTPUT_STRING
cc4d121f
DA
1458 "Show configured cache server\n"
1459 JSON_STR)
dabecd7c 1460{
cc4d121f
DA
1461 struct json_object *json = NULL;
1462 struct json_object *json_server = NULL;
1463 struct json_object *json_servers = NULL;
dabecd7c
MR
1464 struct listnode *cache_node;
1465 struct cache *cache;
1466
cc4d121f
DA
1467 if (uj) {
1468 json = json_object_new_object();
1469 json_servers = json_object_new_array();
1470 json_object_object_add(json, "servers", json_servers);
1471 }
1472
dabecd7c 1473 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
745ae9c0 1474 if (cache->type == TCP) {
cc4d121f 1475 if (!json) {
77be6d6a
DA
1476 vty_out(vty,
1477 "host: %s port: %s, preference: %hhu\n",
cc4d121f 1478 cache->tr_config.tcp_config->host,
77be6d6a
DA
1479 cache->tr_config.tcp_config->port,
1480 cache->preference);
cc4d121f
DA
1481 } else {
1482 json_server = json_object_new_object();
1483 json_object_string_add(json_server, "mode",
1484 "tcp");
1485 json_object_string_add(
1486 json_server, "host",
1487 cache->tr_config.tcp_config->host);
1488 json_object_string_add(
1489 json_server, "port",
1490 cache->tr_config.tcp_config->port);
77be6d6a
DA
1491 json_object_int_add(json_server, "preference",
1492 cache->preference);
cc4d121f
DA
1493 json_object_array_add(json_servers,
1494 json_server);
1495 }
745ae9c0 1496
fef6fafa 1497#if defined(FOUND_SSH)
745ae9c0 1498 } else if (cache->type == SSH) {
cc4d121f
DA
1499 if (!json) {
1500 vty_out(vty,
77be6d6a 1501 "host: %s port: %d username: %s server_hostkey_path: %s client_privkey_path: %s, preference: %hhu\n",
cc4d121f
DA
1502 cache->tr_config.ssh_config->host,
1503 cache->tr_config.ssh_config->port,
1504 cache->tr_config.ssh_config->username,
1505 cache->tr_config.ssh_config
1506 ->server_hostkey_path,
1507 cache->tr_config.ssh_config
77be6d6a
DA
1508 ->client_privkey_path,
1509 cache->preference);
cc4d121f
DA
1510 } else {
1511 json_server = json_object_new_object();
1512 json_object_string_add(json_server, "mode",
1513 "ssh");
1514 json_object_string_add(
1515 json_server, "host",
1516 cache->tr_config.ssh_config->host);
1517 json_object_int_add(
1518 json_server, "port",
1519 cache->tr_config.ssh_config->port);
1520 json_object_string_add(
1521 json_server, "username",
1522 cache->tr_config.ssh_config->username);
1523 json_object_string_add(
1524 json_server, "serverHostkeyPath",
1525 cache->tr_config.ssh_config
1526 ->server_hostkey_path);
1527 json_object_string_add(
1528 json_server, "clientPrivkeyPath",
1529 cache->tr_config.ssh_config
1530 ->client_privkey_path);
77be6d6a
DA
1531 json_object_int_add(json_server, "preference",
1532 cache->preference);
cc4d121f
DA
1533 json_object_array_add(json_servers,
1534 json_server);
1535 }
fef6fafa 1536#endif
745ae9c0 1537 }
dabecd7c
MR
1538 }
1539
cc4d121f
DA
1540 if (json)
1541 vty_json(vty, json);
1542
dabecd7c
MR
1543 return CMD_SUCCESS;
1544}
1545
ae872c2f 1546DEFPY (show_rpki_cache_connection,
dabecd7c 1547 show_rpki_cache_connection_cmd,
ae872c2f 1548 "show rpki cache-connection [json$uj]",
dabecd7c
MR
1549 SHOW_STR
1550 RPKI_OUTPUT_STRING
ae872c2f
DA
1551 "Show to which RPKI Cache Servers we have a connection\n"
1552 JSON_STR)
dabecd7c 1553{
ae872c2f
DA
1554 struct json_object *json = NULL;
1555 struct json_object *json_conn = NULL;
1556 struct json_object *json_conns = NULL;
1557 struct listnode *cache_node;
1558 struct cache *cache;
1559 struct rtr_mgr_group *group;
1560
1561 if (uj)
1562 json = json_object_new_object();
1563
708b8053 1564 if (!is_synchronized()) {
ae872c2f
DA
1565 if (!json)
1566 vty_out(vty, "No connection to RPKI cache server.\n");
1567 else
1568 vty_json(vty, json);
708b8053
DS
1569
1570 return CMD_SUCCESS;
1571 }
1572
ae872c2f 1573 group = get_connected_group();
708b8053 1574 if (!group) {
ae872c2f
DA
1575 if (!json)
1576 vty_out(vty, "Cannot find a connected group.\n");
1577 else
1578 vty_json(vty, json);
1579
708b8053
DS
1580 return CMD_SUCCESS;
1581 }
ae872c2f
DA
1582
1583 if (!json) {
1584 vty_out(vty, "Connected to group %d\n", group->preference);
1585 } else {
1586 json_conns = json_object_new_array();
1587 json_object_int_add(json, "connectedGroup", group->preference);
1588 json_object_object_add(json, "connections", json_conns);
1589 }
1590
708b8053 1591 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
c1a68b62 1592 struct tr_tcp_config *tcp_config;
acd4a9f4 1593#if defined(FOUND_SSH)
c1a68b62 1594 struct tr_ssh_config *ssh_config;
acd4a9f4 1595#endif
c1a68b62
DA
1596 switch (cache->type) {
1597 case TCP:
1598 tcp_config = cache->tr_config.tcp_config;
ae872c2f
DA
1599
1600 if (!json) {
1601 vty_out(vty,
1602 "rpki tcp cache %s %s pref %hhu%s\n",
1603 tcp_config->host, tcp_config->port,
1604 cache->preference,
1605 cache->rtr_socket->state ==
1606 RTR_ESTABLISHED
1607 ? " (connected)"
1608 : "");
1609 } else {
1610 json_conn = json_object_new_object();
1611 json_object_string_add(json_conn, "mode",
1612 "tcp");
1613 json_object_string_add(json_conn, "host",
1614 tcp_config->host);
1615 json_object_string_add(json_conn, "port",
1616 tcp_config->port);
1617 json_object_int_add(json_conn, "preference",
1618 cache->preference);
1619 json_object_string_add(
1620 json_conn, "state",
1621 cache->rtr_socket->state ==
1622 RTR_ESTABLISHED
1623 ? "connected"
1624 : "disconnected");
1625 json_object_array_add(json_conns, json_conn);
1626 }
c1a68b62 1627 break;
dabecd7c 1628#if defined(FOUND_SSH)
c1a68b62
DA
1629 case SSH:
1630 ssh_config = cache->tr_config.ssh_config;
ae872c2f
DA
1631
1632 if (!json) {
1633 vty_out(vty,
1634 "rpki ssh cache %s %u pref %hhu%s\n",
1635 ssh_config->host, ssh_config->port,
1636 cache->preference,
1637 cache->rtr_socket->state ==
1638 RTR_ESTABLISHED
1639 ? " (connected)"
1640 : "");
1641 } else {
1642 json_conn = json_object_new_object();
1643 json_object_string_add(json_conn, "mode",
1644 "ssh");
1645 json_object_string_add(json_conn, "host",
1646 ssh_config->host);
4d4b9dc1
DA
1647 json_object_int_add(json_conn, "port",
1648 ssh_config->port);
ae872c2f
DA
1649 json_object_int_add(json_conn, "preference",
1650 cache->preference);
1651 json_object_string_add(
1652 json_conn, "state",
1653 cache->rtr_socket->state ==
1654 RTR_ESTABLISHED
1655 ? "connected"
1656 : "disconnected");
1657 json_object_array_add(json_conns, json_conn);
1658 }
c1a68b62 1659 break;
dabecd7c 1660#endif
c1a68b62
DA
1661 default:
1662 break;
dabecd7c 1663 }
dabecd7c
MR
1664 }
1665
ae872c2f
DA
1666 if (json)
1667 vty_json(vty, json);
1668
dabecd7c
MR
1669 return CMD_SUCCESS;
1670}
1671
791ded4a 1672static int config_on_exit(struct vty *vty)
dabecd7c 1673{
61a484a9 1674 reset(false);
791ded4a 1675 return 1;
dabecd7c
MR
1676}
1677
1678DEFUN (rpki_reset,
1679 rpki_reset_cmd,
1680 "rpki reset",
1681 RPKI_OUTPUT_STRING
1682 "reset rpki\n")
1683{
1684 return reset(true) == SUCCESS ? CMD_SUCCESS : CMD_WARNING;
1685}
1686
1687DEFUN (debug_rpki,
1688 debug_rpki_cmd,
1689 "debug rpki",
1690 DEBUG_STR
08f9cfb8 1691 "Enable debugging for rpki\n")
dabecd7c 1692{
0e3d96bf 1693 rpki_debug = true;
dabecd7c
MR
1694 return CMD_SUCCESS;
1695}
1696
1697DEFUN (no_debug_rpki,
1698 no_debug_rpki_cmd,
1699 "no debug rpki",
1700 NO_STR
1701 DEBUG_STR
08f9cfb8 1702 "Disable debugging for rpki\n")
dabecd7c 1703{
0e3d96bf 1704 rpki_debug = false;
dabecd7c
MR
1705 return CMD_SUCCESS;
1706}
1707
48cb7ea9 1708DEFUN_YANG (match_rpki,
dabecd7c
MR
1709 match_rpki_cmd,
1710 "match rpki <valid|invalid|notfound>",
1711 MATCH_STR
1712 RPKI_OUTPUT_STRING
1713 "Valid prefix\n"
1714 "Invalid prefix\n"
1715 "Prefix not found\n")
1716{
48cb7ea9
SP
1717 const char *xpath =
1718 "./match-condition[condition='frr-bgp-route-map:rpki']";
1719 char xpath_value[XPATH_MAXLEN];
69337c34 1720
48cb7ea9
SP
1721 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
1722 snprintf(xpath_value, sizeof(xpath_value),
1723 "%s/rmap-match-condition/frr-bgp-route-map:rpki", xpath);
1724 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[2]->arg);
1725
1726 return nb_cli_apply_changes(vty, NULL);
dabecd7c
MR
1727}
1728
48cb7ea9 1729DEFUN_YANG (no_match_rpki,
dabecd7c
MR
1730 no_match_rpki_cmd,
1731 "no match rpki <valid|invalid|notfound>",
1732 NO_STR
1733 MATCH_STR
1734 RPKI_OUTPUT_STRING
1735 "Valid prefix\n"
1736 "Invalid prefix\n"
1737 "Prefix not found\n")
1738{
48cb7ea9
SP
1739 const char *xpath =
1740 "./match-condition[condition='frr-bgp-route-map:rpki']";
dabecd7c 1741
87c3ed1b 1742 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
48cb7ea9 1743 return nb_cli_apply_changes(vty, NULL);
dabecd7c
MR
1744}
1745
dabecd7c
MR
1746static void install_cli_commands(void)
1747{
996c9314 1748 // TODO: make config write work
612c2c15 1749 install_node(&rpki_node);
dabecd7c 1750 install_default(RPKI_NODE);
dabecd7c 1751 install_element(CONFIG_NODE, &rpki_cmd);
9593708d 1752 install_element(ENABLE_NODE, &rpki_cmd);
8156765a
DA
1753 install_element(CONFIG_NODE, &no_rpki_cmd);
1754
dabecd7c
MR
1755
1756 install_element(ENABLE_NODE, &bgp_rpki_start_cmd);
1757 install_element(ENABLE_NODE, &bgp_rpki_stop_cmd);
1758
1759 /* Install rpki reset command */
8f14ae47 1760 install_element(ENABLE_NODE, &rpki_reset_cmd);
dabecd7c
MR
1761 install_element(RPKI_NODE, &rpki_reset_cmd);
1762
1763 /* Install rpki polling period commands */
1764 install_element(RPKI_NODE, &rpki_polling_period_cmd);
1765 install_element(RPKI_NODE, &no_rpki_polling_period_cmd);
1766
1767 /* Install rpki expire interval commands */
1768 install_element(RPKI_NODE, &rpki_expire_interval_cmd);
1769 install_element(RPKI_NODE, &no_rpki_expire_interval_cmd);
1770
1771 /* Install rpki retry interval commands */
1772 install_element(RPKI_NODE, &rpki_retry_interval_cmd);
1773 install_element(RPKI_NODE, &no_rpki_retry_interval_cmd);
1774
dabecd7c
MR
1775 /* Install rpki cache commands */
1776 install_element(RPKI_NODE, &rpki_cache_cmd);
1777 install_element(RPKI_NODE, &no_rpki_cache_cmd);
1778
1779 /* Install show commands */
9593708d 1780 install_element(VIEW_NODE, &show_rpki_prefix_table_cmd);
1781 install_element(VIEW_NODE, &show_rpki_cache_connection_cmd);
1782 install_element(VIEW_NODE, &show_rpki_cache_server_cmd);
1783 install_element(VIEW_NODE, &show_rpki_prefix_cmd);
02334bb2 1784 install_element(VIEW_NODE, &show_rpki_as_number_cmd);
dabecd7c
MR
1785
1786 /* Install debug commands */
1787 install_element(CONFIG_NODE, &debug_rpki_cmd);
1788 install_element(ENABLE_NODE, &debug_rpki_cmd);
1789 install_element(CONFIG_NODE, &no_debug_rpki_cmd);
1790 install_element(ENABLE_NODE, &no_debug_rpki_cmd);
1791
1792 /* Install route match */
1793 route_map_install_match(&route_match_rpki_cmd);
1794 install_element(RMAP_NODE, &match_rpki_cmd);
1795 install_element(RMAP_NODE, &no_match_rpki_cmd);
1796}
1797
1798FRR_MODULE_SETUP(.name = "bgpd_rpki", .version = "0.3.6",
1799 .description = "Enable RPKI support for FRR.",
80413c20
DL
1800 .init = bgp_rpki_module_init,
1801);