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