]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_rpki.c
bgpd: rpki should use a stack pointer instead of a pointer
[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
fc15f734
DS
375static void pfx_record_to_prefix(struct pfx_record *record,
376 struct prefix *prefix)
1dacdd8b 377{
1dacdd8b
MR
378 prefix->prefixlen = record->min_len;
379
380 if (record->prefix.ver == LRTR_IPV4) {
381 prefix->family = AF_INET;
382 prefix->u.prefix4.s_addr = htonl(record->prefix.u.addr4.addr);
383 } else {
384 prefix->family = AF_INET6;
385 ipv6_addr_to_network_byte_order(record->prefix.u.addr6.addr,
386 prefix->u.prefix6.s6_addr32);
387 }
1dacdd8b
MR
388}
389
cc9f21da 390static void bgpd_sync_callback(struct thread *thread)
1dacdd8b
MR
391{
392 struct bgp *bgp;
393 struct listnode *node;
fc15f734 394 struct prefix prefix;
1dacdd8b
MR
395 struct pfx_record rec;
396
d2e3f8a2
DA
397 thread_add_read(bm->master, bgpd_sync_callback, NULL,
398 rpki_sync_socket_bgpd, NULL);
4ce82676
MR
399
400 if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) {
d2e3f8a2
DA
401 while (read(rpki_sync_socket_bgpd, &rec,
402 sizeof(struct pfx_record)) != -1)
4ce82676
MR
403 ;
404
405 atomic_store_explicit(&rtr_update_overflow, 0,
406 memory_order_seq_cst);
407 revalidate_all_routes();
cc9f21da 408 return;
4ce82676
MR
409 }
410
d2e3f8a2
DA
411 int retval =
412 read(rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record));
3b128228 413 if (retval != sizeof(struct pfx_record)) {
d2e3f8a2 414 RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd");
cc9f21da 415 return;
38775a3c 416 }
fc15f734 417 pfx_record_to_prefix(&rec, &prefix);
1dacdd8b
MR
418
419 afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
420
421 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
35a1e798 422 safi_t safi;
1dacdd8b 423
35a1e798 424 for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
7e7f61ed
DA
425 struct bgp_table *table = bgp->rib[afi][safi];
426
427 if (!table)
35a1e798 428 continue;
31a2af32 429
35a1e798
DS
430 struct bgp_dest *match;
431 struct bgp_dest *node;
1dacdd8b 432
fc15f734 433 match = bgp_table_subtree_lookup(table, &prefix);
35a1e798 434 node = match;
bac31cb8 435
35a1e798
DS
436 while (node) {
437 if (bgp_dest_has_bgp_path_info_data(node)) {
438 revalidate_bgp_node(node, afi, safi);
bac31cb8 439 }
35a1e798
DS
440
441 node = bgp_route_next_until(node, match);
31a2af32 442 }
7e7f61ed
DA
443
444 if (match)
445 bgp_dest_unlock_node(match);
1dacdd8b
MR
446 }
447 }
1dacdd8b
MR
448}
449
9bcb3eef 450static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi,
1dacdd8b
MR
451 safi_t safi)
452{
453 struct bgp_adj_in *ain;
454
9bcb3eef 455 for (ain = bgp_dest->adj_in; ain; ain = ain->next) {
2b964e86 456 struct bgp_path_info *path =
9bcb3eef 457 bgp_dest_get_bgp_path_info(bgp_dest);
1dacdd8b
MR
458 mpls_label_t *label = NULL;
459 uint32_t num_labels = 0;
460
9b6d8fcf
DS
461 if (path && path->extra) {
462 label = path->extra->label;
463 num_labels = path->extra->num_labels;
1dacdd8b 464 }
73261b47 465 (void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest),
b54892e0
DS
466 ain->addpath_rx_id, ain->attr, afi, safi,
467 ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label,
468 num_labels, 1, NULL);
1dacdd8b
MR
469 }
470}
471
7651f277
DS
472/*
473 * The act of a soft reconfig in revalidation is really expensive
474 * coupled with the fact that the download of a full rpki state
475 * from a rpki server can be expensive, let's break up the revalidation
476 * to a point in time in the future to allow other bgp events
477 * to take place too.
478 */
479struct rpki_revalidate_peer {
480 afi_t afi;
481 safi_t safi;
482 struct peer *peer;
483};
484
485static void bgp_rpki_revalidate_peer(struct thread *thread)
486{
487 struct rpki_revalidate_peer *rvp = THREAD_ARG(thread);
488
489 /*
490 * Here's the expensive bit of gnomish deviousness
491 */
492 bgp_soft_reconfig_in(rvp->peer, rvp->afi, rvp->safi);
493
494 XFREE(MTYPE_BGP_RPKI_REVALIDATE, rvp);
495}
496
1dacdd8b
MR
497static void revalidate_all_routes(void)
498{
499 struct bgp *bgp;
500 struct listnode *node;
1dacdd8b
MR
501
502 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
31a2af32
MR
503 struct peer *peer;
504 struct listnode *peer_listnode;
1dacdd8b 505
31a2af32 506 for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) {
8fb15d02
DS
507 afi_t afi;
508 safi_t safi;
31a2af32 509
8fb15d02 510 FOREACH_AFI_SAFI (afi, safi) {
7651f277
DS
511 struct rpki_revalidate_peer *rvp;
512
802ca11f 513 if (!bgp->rib[afi][safi])
8fb15d02 514 continue;
d2e3f8a2 515
89c73443
DS
516 if (!peer_established(peer))
517 continue;
7651f277
DS
518
519 rvp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE,
520 sizeof(*rvp));
521 rvp->peer = peer;
522 rvp->afi = afi;
523 rvp->safi = safi;
524
525 thread_add_event(
526 bm->master, bgp_rpki_revalidate_peer,
527 rvp, 0,
528 &peer->t_revalidate_all[afi][safi]);
1dacdd8b
MR
529 }
530 }
531 }
532}
533
534static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)),
535 const struct pfx_record rec,
536 const bool added __attribute__((unused)))
537{
9ca44fc8
DA
538 if (is_stopping() ||
539 atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst))
1dacdd8b
MR
540 return;
541
542 int retval =
543 write(rpki_sync_socket_rtr, &rec, sizeof(struct pfx_record));
4ce82676
MR
544 if (retval == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
545 atomic_store_explicit(&rtr_update_overflow, 1,
546 memory_order_seq_cst);
547
548 else if (retval != sizeof(struct pfx_record))
1dacdd8b
MR
549 RPKI_DEBUG("Could not write to rpki_sync_socket_rtr");
550}
551
552static void rpki_init_sync_socket(void)
553{
554 int fds[2];
4ce82676 555 const char *msg;
1dacdd8b
MR
556
557 RPKI_DEBUG("initializing sync socket");
558 if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fds) != 0) {
4ce82676
MR
559 msg = "could not open rpki sync socketpair";
560 goto err;
1dacdd8b
MR
561 }
562 rpki_sync_socket_rtr = fds[0];
563 rpki_sync_socket_bgpd = fds[1];
4ce82676
MR
564
565 if (set_nonblocking(rpki_sync_socket_rtr) != 0) {
566 msg = "could not set rpki_sync_socket_rtr to non blocking";
567 goto err;
568 }
569
570 if (set_nonblocking(rpki_sync_socket_bgpd) != 0) {
571 msg = "could not set rpki_sync_socket_bgpd to non blocking";
572 goto err;
573 }
574
d2e3f8a2 575
1dacdd8b 576 thread_add_read(bm->master, bgpd_sync_callback, NULL,
d2e3f8a2 577 rpki_sync_socket_bgpd, NULL);
4ce82676
MR
578
579 return;
580
581err:
582 zlog_err("RPKI: %s", msg);
583 abort();
584
1dacdd8b
MR
585}
586
dabecd7c
MR
587static int bgp_rpki_init(struct thread_master *master)
588{
0e3d96bf
DA
589 rpki_debug = false;
590 rtr_is_running = false;
591 rtr_is_stopping = false;
d67485c6 592 rtr_is_synced = false;
dabecd7c
MR
593
594 cache_list = list_new();
996c9314 595 cache_list->del = (void (*)(void *)) & free_cache;
dabecd7c
MR
596
597 polling_period = POLLING_PERIOD_DEFAULT;
598 expire_interval = EXPIRE_INTERVAL_DEFAULT;
599 retry_interval = RETRY_INTERVAL_DEFAULT;
dabecd7c 600 install_cli_commands();
1dacdd8b 601 rpki_init_sync_socket();
dabecd7c
MR
602 return 0;
603}
604
605static int bgp_rpki_fini(void)
606{
607 stop();
6a154c88 608 list_delete(&cache_list);
dabecd7c 609
1dacdd8b
MR
610 close(rpki_sync_socket_rtr);
611 close(rpki_sync_socket_bgpd);
612
dabecd7c
MR
613 return 0;
614}
615
616static int bgp_rpki_module_init(void)
617{
996c9314 618 lrtr_set_alloc_functions(malloc_wrapper, realloc_wrapper, free_wrapper);
dabecd7c 619
b5b99af8 620 hook_register(bgp_rpki_prefix_status, rpki_validate_prefix);
dabecd7c 621 hook_register(frr_late_init, bgp_rpki_init);
f714e57a 622 hook_register(frr_early_fini, bgp_rpki_fini);
dabecd7c
MR
623
624 return 0;
625}
626
d67485c6 627static void sync_expired(struct thread *thread)
1b2095d1
DA
628{
629 if (!rtr_mgr_conf_in_sync(rtr_config)) {
d67485c6
DA
630 RPKI_DEBUG("rtr_mgr is not synced, retrying.");
631 thread_add_timer(bm->master, sync_expired, NULL,
1b2095d1 632 BGP_RPKI_CACHE_SERVER_SYNC_RETRY_TIMEOUT,
d67485c6 633 &t_rpki_sync);
1b2095d1
DA
634 return;
635 }
636
d67485c6
DA
637 RPKI_DEBUG("rtr_mgr sync is done.");
638
639 rtr_is_synced = true;
1b2095d1
DA
640}
641
dabecd7c
MR
642static int start(void)
643{
dabecd7c
MR
644 int ret;
645
0e3d96bf 646 rtr_is_stopping = false;
d67485c6 647 rtr_is_synced = false;
4ce82676 648 rtr_update_overflow = 0;
1dacdd8b 649
dabecd7c
MR
650 if (list_isempty(cache_list)) {
651 RPKI_DEBUG(
652 "No caches were found in config. Prefix validation is off.");
653 return ERROR;
654 }
655 RPKI_DEBUG("Init rtr_mgr.");
656 int groups_len = listcount(cache_list);
657 struct rtr_mgr_group *groups = get_groups();
658
1dacdd8b 659 RPKI_DEBUG("Polling period: %d", polling_period);
dabecd7c 660 ret = rtr_mgr_init(&rtr_config, groups, groups_len, polling_period,
1dacdd8b 661 expire_interval, retry_interval,
d2e3f8a2 662 rpki_update_cb_sync_rtr, NULL, NULL, NULL);
dabecd7c
MR
663 if (ret == RTR_ERROR) {
664 RPKI_DEBUG("Init rtr_mgr failed.");
665 return ERROR;
666 }
667
668 RPKI_DEBUG("Starting rtr_mgr.");
669 ret = rtr_mgr_start(rtr_config);
670 if (ret == RTR_ERROR) {
671 RPKI_DEBUG("Starting rtr_mgr failed.");
672 rtr_mgr_free(rtr_config);
673 return ERROR;
674 }
1b2095d1 675
d67485c6 676 thread_add_timer(bm->master, sync_expired, NULL, 0, &t_rpki_sync);
dabecd7c
MR
677
678 XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups);
679
0e3d96bf 680 rtr_is_running = true;
d67485c6 681
dabecd7c
MR
682 return SUCCESS;
683}
684
685static void stop(void)
686{
0e3d96bf 687 rtr_is_stopping = true;
01fcc189 688 if (is_running()) {
d67485c6 689 THREAD_OFF(t_rpki_sync);
dabecd7c
MR
690 rtr_mgr_stop(rtr_config);
691 rtr_mgr_free(rtr_config);
0e3d96bf 692 rtr_is_running = false;
dabecd7c
MR
693 }
694}
695
696static int reset(bool force)
697{
01fcc189 698 if (is_running() && !force)
dabecd7c
MR
699 return SUCCESS;
700
701 RPKI_DEBUG("Resetting RPKI Session");
702 stop();
703 return start();
704}
705
706static struct rtr_mgr_group *get_connected_group(void)
707{
18b91526 708 if (!cache_list || list_isempty(cache_list))
dabecd7c
MR
709 return NULL;
710
711 return rtr_mgr_get_first_group(rtr_config);
712}
713
dff41cc8
DA
714static void print_prefix_table_by_asn(struct vty *vty, as_t as,
715 json_object *json)
02334bb2
DA
716{
717 unsigned int number_of_ipv4_prefixes = 0;
718 unsigned int number_of_ipv6_prefixes = 0;
719 struct rtr_mgr_group *group = get_connected_group();
720 struct rpki_for_each_record_arg arg;
dff41cc8 721 json_object *json_records = NULL;
02334bb2
DA
722
723 arg.vty = vty;
724 arg.as = as;
dff41cc8 725 arg.json = NULL;
02334bb2
DA
726
727 if (!group) {
dff41cc8
DA
728 if (!json)
729 vty_out(vty, "Cannot find a connected group.\n");
02334bb2
DA
730 return;
731 }
732
733 struct pfx_table *pfx_table = group->sockets[0]->pfx_table;
734
dff41cc8
DA
735 if (!json) {
736 vty_out(vty, "RPKI/RTR prefix table\n");
737 vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
738 "Origin-AS");
739 } else {
740 json_records = json_object_new_array();
741 json_object_object_add(json, "prefixes", json_records);
742 arg.json = json_records;
743 }
02334bb2
DA
744
745 arg.prefix_amount = &number_of_ipv4_prefixes;
746 pfx_table_for_each_ipv4_record(pfx_table, print_record_by_asn, &arg);
747
748 arg.prefix_amount = &number_of_ipv6_prefixes;
749 pfx_table_for_each_ipv6_record(pfx_table, print_record_by_asn, &arg);
750
dff41cc8
DA
751 if (!json) {
752 vty_out(vty, "Number of IPv4 Prefixes: %u\n",
753 number_of_ipv4_prefixes);
754 vty_out(vty, "Number of IPv6 Prefixes: %u\n",
755 number_of_ipv6_prefixes);
756 } else {
757 json_object_int_add(json, "ipv4PrefixCount",
758 number_of_ipv4_prefixes);
759 json_object_int_add(json, "ipv6PrefixCount",
760 number_of_ipv6_prefixes);
761 }
762
763 if (json)
764 vty_json(vty, json);
02334bb2
DA
765}
766
dff41cc8 767static void print_prefix_table(struct vty *vty, json_object *json)
dabecd7c
MR
768{
769 struct rpki_for_each_record_arg arg;
770
771 unsigned int number_of_ipv4_prefixes = 0;
772 unsigned int number_of_ipv6_prefixes = 0;
773 struct rtr_mgr_group *group = get_connected_group();
dff41cc8 774 json_object *json_records = NULL;
dabecd7c
MR
775
776 arg.vty = vty;
dff41cc8 777 arg.json = NULL;
dabecd7c 778
dff41cc8
DA
779 if (!group) {
780 if (!json)
781 vty_out(vty, "Cannot find a connected group.\n");
dabecd7c 782 return;
dff41cc8 783 }
dabecd7c
MR
784
785 struct pfx_table *pfx_table = group->sockets[0]->pfx_table;
786
dff41cc8
DA
787 if (!json) {
788 vty_out(vty, "RPKI/RTR prefix table\n");
789 vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
790 "Origin-AS");
791 } else {
792 json_records = json_object_new_array();
793 json_object_object_add(json, "prefixes", json_records);
794 arg.json = json_records;
795 }
dabecd7c
MR
796
797 arg.prefix_amount = &number_of_ipv4_prefixes;
5d799192 798 pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg);
dabecd7c
MR
799
800 arg.prefix_amount = &number_of_ipv6_prefixes;
5d799192 801 pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg);
dabecd7c 802
dff41cc8
DA
803 if (!json) {
804 vty_out(vty, "Number of IPv4 Prefixes: %u\n",
805 number_of_ipv4_prefixes);
806 vty_out(vty, "Number of IPv6 Prefixes: %u\n",
807 number_of_ipv6_prefixes);
808 } else {
809 json_object_int_add(json, "ipv4PrefixCount",
810 number_of_ipv4_prefixes);
811 json_object_int_add(json, "ipv6PrefixCount",
812 number_of_ipv6_prefixes);
813 }
814
815 if (json)
816 vty_json(vty, json);
dabecd7c
MR
817}
818
819static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
898c4e66 820 const struct prefix *prefix)
dabecd7c
MR
821{
822 struct assegment *as_segment;
823 as_t as_number = 0;
824 struct lrtr_ip_addr ip_addr_prefix;
825 enum pfxv_state result;
dabecd7c
MR
826
827 if (!is_synchronized())
e1a05dd4 828 return RPKI_NOT_BEING_USED;
dabecd7c
MR
829
830 // No aspath means route comes from iBGP
831 if (!attr->aspath || !attr->aspath->segments) {
832 // Set own as number
833 as_number = peer->bgp->as;
834 } else {
835 as_segment = attr->aspath->segments;
836 // Find last AsSegment
837 while (as_segment->next)
838 as_segment = as_segment->next;
839
840 if (as_segment->type == AS_SEQUENCE) {
841 // Get rightmost asn
842 as_number = as_segment->as[as_segment->length - 1];
996c9314
LB
843 } else if (as_segment->type == AS_CONFED_SEQUENCE
844 || as_segment->type == AS_CONFED_SET) {
dabecd7c
MR
845 // Set own as number
846 as_number = peer->bgp->as;
847 } else {
848 // RFC says: "Take distinguished value NONE as asn"
849 // which means state is unknown
850 return RPKI_NOTFOUND;
851 }
852 }
853
854 // Get the prefix in requested format
855 switch (prefix->family) {
856 case AF_INET:
857 ip_addr_prefix.ver = LRTR_IPV4;
858 ip_addr_prefix.u.addr4.addr = ntohl(prefix->u.prefix4.s_addr);
859 break;
860
dabecd7c
MR
861 case AF_INET6:
862 ip_addr_prefix.ver = LRTR_IPV6;
863 ipv6_addr_to_host_byte_order(prefix->u.prefix6.s6_addr32,
864 ip_addr_prefix.u.addr6.addr);
865 break;
dabecd7c
MR
866
867 default:
e1a05dd4 868 return RPKI_NOT_BEING_USED;
dabecd7c
MR
869 }
870
871 // Do the actual validation
872 rtr_mgr_validate(rtr_config, as_number, &ip_addr_prefix,
873 prefix->prefixlen, &result);
874
875 // Print Debug output
dabecd7c
MR
876 switch (result) {
877 case BGP_PFXV_STATE_VALID:
878 RPKI_DEBUG(
2dbe669b
DA
879 "Validating Prefix %pFX from asn %u Result: VALID",
880 prefix, as_number);
dabecd7c
MR
881 return RPKI_VALID;
882 case BGP_PFXV_STATE_NOT_FOUND:
883 RPKI_DEBUG(
2dbe669b
DA
884 "Validating Prefix %pFX from asn %u Result: NOT FOUND",
885 prefix, as_number);
dabecd7c
MR
886 return RPKI_NOTFOUND;
887 case BGP_PFXV_STATE_INVALID:
888 RPKI_DEBUG(
2dbe669b
DA
889 "Validating Prefix %pFX from asn %u Result: INVALID",
890 prefix, as_number);
dabecd7c
MR
891 return RPKI_INVALID;
892 default:
893 RPKI_DEBUG(
2dbe669b
DA
894 "Validating Prefix %pFX from asn %u Result: CANNOT VALIDATE",
895 prefix, as_number);
dabecd7c
MR
896 break;
897 }
e1a05dd4 898 return RPKI_NOT_BEING_USED;
dabecd7c
MR
899}
900
901static int add_cache(struct cache *cache)
902{
903 uint8_t preference = cache->preference;
904 struct rtr_mgr_group group;
905
906 group.preference = preference;
907 group.sockets_len = 1;
908 group.sockets = &cache->rtr_socket;
909
01fcc189 910 if (is_running()) {
92110aab
MR
911 init_tr_socket(cache);
912
913 if (rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) {
914 free_tr_socket(cache);
915 return ERROR;
916 }
dabecd7c
MR
917 }
918
6893064b
MR
919 listnode_add(cache_list, cache);
920
dabecd7c
MR
921 return SUCCESS;
922}
923
996c9314 924static int add_tcp_cache(const char *host, const char *port,
7253a7bc 925 const uint8_t preference, const char *bindaddr)
dabecd7c
MR
926{
927 struct rtr_socket *rtr_socket;
928 struct tr_tcp_config *tcp_config =
a633498e 929 XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_tcp_config));
dabecd7c
MR
930 struct tr_socket *tr_socket =
931 XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_socket));
932 struct cache *cache =
933 XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct cache));
934
935 tcp_config->host = XSTRDUP(MTYPE_BGP_RPKI_CACHE, host);
936 tcp_config->port = XSTRDUP(MTYPE_BGP_RPKI_CACHE, port);
7253a7bc
PG
937 if (bindaddr)
938 tcp_config->bindaddr = XSTRDUP(MTYPE_BGP_RPKI_CACHE, bindaddr);
939 else
940 tcp_config->bindaddr = NULL;
dabecd7c
MR
941
942 rtr_socket = create_rtr_socket(tr_socket);
943
944 cache->type = TCP;
945 cache->tr_socket = tr_socket;
946 cache->tr_config.tcp_config = tcp_config;
947 cache->rtr_socket = rtr_socket;
948 cache->preference = preference;
949
6893064b
MR
950 int ret = add_cache(cache);
951 if (ret != SUCCESS) {
952 free_cache(cache);
953 }
954
955 return ret;
dabecd7c
MR
956}
957
958#if defined(FOUND_SSH)
996c9314
LB
959static int add_ssh_cache(const char *host, const unsigned int port,
960 const char *username, const char *client_privkey_path,
dabecd7c 961 const char *server_pubkey_path,
7253a7bc 962 const uint8_t preference, const char *bindaddr)
dabecd7c
MR
963{
964 struct tr_ssh_config *ssh_config =
a633498e 965 XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_ssh_config));
dabecd7c
MR
966 struct cache *cache =
967 XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct cache));
968 struct tr_socket *tr_socket =
969 XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_socket));
970 struct rtr_socket *rtr_socket;
971
972 ssh_config->port = port;
973 ssh_config->host = XSTRDUP(MTYPE_BGP_RPKI_CACHE, host);
7253a7bc
PG
974 if (bindaddr)
975 ssh_config->bindaddr = XSTRDUP(MTYPE_BGP_RPKI_CACHE, bindaddr);
976 else
977 ssh_config->bindaddr = NULL;
dabecd7c
MR
978
979 ssh_config->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username);
996c9314
LB
980 ssh_config->client_privkey_path =
981 XSTRDUP(MTYPE_BGP_RPKI_CACHE, client_privkey_path);
dabecd7c
MR
982 ssh_config->server_hostkey_path =
983 XSTRDUP(MTYPE_BGP_RPKI_CACHE, server_pubkey_path);
984
985 rtr_socket = create_rtr_socket(tr_socket);
986
987 cache->type = SSH;
988 cache->tr_socket = tr_socket;
989 cache->tr_config.ssh_config = ssh_config;
990 cache->rtr_socket = rtr_socket;
991 cache->preference = preference;
992
6893064b
MR
993 int ret = add_cache(cache);
994 if (ret != SUCCESS) {
995 free_cache(cache);
996 }
997
998 return ret;
dabecd7c
MR
999}
1000#endif
1001
1002static void free_cache(struct cache *cache)
1003{
1004 if (cache->type == TCP) {
996c9314
LB
1005 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.tcp_config->host);
1006 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.tcp_config->port);
c41a3cc5
DA
1007 XFREE(MTYPE_BGP_RPKI_CACHE,
1008 cache->tr_config.tcp_config->bindaddr);
dabecd7c
MR
1009 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.tcp_config);
1010 }
1011#if defined(FOUND_SSH)
1012 else {
996c9314 1013 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.ssh_config->host);
dabecd7c
MR
1014 XFREE(MTYPE_BGP_RPKI_CACHE,
1015 cache->tr_config.ssh_config->username);
1016 XFREE(MTYPE_BGP_RPKI_CACHE,
1017 cache->tr_config.ssh_config->client_privkey_path);
1018 XFREE(MTYPE_BGP_RPKI_CACHE,
1019 cache->tr_config.ssh_config->server_hostkey_path);
c41a3cc5
DA
1020 XFREE(MTYPE_BGP_RPKI_CACHE,
1021 cache->tr_config.ssh_config->bindaddr);
dabecd7c
MR
1022 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.ssh_config);
1023 }
1024#endif
1025 XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_socket);
1026 XFREE(MTYPE_BGP_RPKI_CACHE, cache->rtr_socket);
1027 XFREE(MTYPE_BGP_RPKI_CACHE, cache);
1028}
1029
1030static int config_write(struct vty *vty)
1031{
1032 struct listnode *cache_node;
1033 struct cache *cache;
1034
708b8053
DS
1035 if (rpki_debug)
1036 vty_out(vty, "debug rpki\n");
1037
1038 vty_out(vty, "!\n");
1039 vty_out(vty, "rpki\n");
9a651153 1040
8f401cda
DA
1041 if (polling_period != POLLING_PERIOD_DEFAULT)
1042 vty_out(vty, " rpki polling_period %d\n", polling_period);
9a651153
DS
1043 if (retry_interval != RETRY_INTERVAL_DEFAULT)
1044 vty_out(vty, " rpki retry_interval %d\n", retry_interval);
1045 if (expire_interval != EXPIRE_INTERVAL_DEFAULT)
1046 vty_out(vty, " rpki expire_interval %d\n", expire_interval);
1047
708b8053
DS
1048 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
1049 switch (cache->type) {
1050 struct tr_tcp_config *tcp_config;
acd4a9f4 1051#if defined(FOUND_SSH)
708b8053 1052 struct tr_ssh_config *ssh_config;
acd4a9f4 1053#endif
708b8053
DS
1054 case TCP:
1055 tcp_config = cache->tr_config.tcp_config;
484fc374 1056 vty_out(vty, " rpki cache %s %s ", tcp_config->host,
708b8053 1057 tcp_config->port);
484fc374
IR
1058 if (tcp_config->bindaddr)
1059 vty_out(vty, "source %s ",
1060 tcp_config->bindaddr);
708b8053 1061 break;
dabecd7c 1062#if defined(FOUND_SSH)
708b8053
DS
1063 case SSH:
1064 ssh_config = cache->tr_config.ssh_config;
484fc374
IR
1065 vty_out(vty, " rpki cache %s %u %s %s %s ",
1066 ssh_config->host, ssh_config->port,
1067 ssh_config->username,
708b8053
DS
1068 ssh_config->client_privkey_path,
1069 ssh_config->server_hostkey_path != NULL
1070 ? ssh_config->server_hostkey_path
1071 : " ");
484fc374
IR
1072 if (ssh_config->bindaddr)
1073 vty_out(vty, "source %s ",
1074 ssh_config->bindaddr);
708b8053 1075 break;
dabecd7c 1076#endif
708b8053
DS
1077 default:
1078 break;
dabecd7c 1079 }
708b8053
DS
1080
1081 vty_out(vty, "preference %hhu\n", cache->preference);
dabecd7c 1082 }
07679ad9 1083 vty_out(vty, "exit\n");
708b8053
DS
1084
1085 return 1;
dabecd7c
MR
1086}
1087
1088DEFUN_NOSH (rpki,
1089 rpki_cmd,
1090 "rpki",
1091 "Enable rpki and enter rpki configuration mode\n")
1092{
1093 vty->node = RPKI_NODE;
1094 return CMD_SUCCESS;
1095}
1096
8156765a
DA
1097DEFPY (no_rpki,
1098 no_rpki_cmd,
1099 "no rpki",
1100 NO_STR
1101 "Enable rpki and enter rpki configuration mode\n")
1102{
1103 rpki_delete_all_cache_nodes();
1104 stop();
1105 return CMD_SUCCESS;
1106}
1107
dabecd7c
MR
1108DEFUN (bgp_rpki_start,
1109 bgp_rpki_start_cmd,
1110 "rpki start",
1111 RPKI_OUTPUT_STRING
1112 "start rpki support\n")
1113{
1114 if (listcount(cache_list) == 0)
996c9314
LB
1115 vty_out(vty,
1116 "Could not start rpki because no caches are configured\n");
dabecd7c
MR
1117
1118 if (!is_running()) {
1119 if (start() == ERROR) {
1120 RPKI_DEBUG("RPKI failed to start");
1121 return CMD_WARNING;
1122 }
1123 }
1124 return CMD_SUCCESS;
1125}
1126
1127DEFUN (bgp_rpki_stop,
1128 bgp_rpki_stop_cmd,
1129 "rpki stop",
1130 RPKI_OUTPUT_STRING
1131 "start rpki support\n")
1132{
1133 if (is_running())
1134 stop();
1135
1136 return CMD_SUCCESS;
1137}
1138
1139DEFPY (rpki_polling_period,
1140 rpki_polling_period_cmd,
1141 "rpki polling_period (1-86400)$pp",
1142 RPKI_OUTPUT_STRING
1143 "Set polling period\n"
1144 "Polling period value\n")
1145{
1146 polling_period = pp;
1147 return CMD_SUCCESS;
1148}
1149
1150DEFUN (no_rpki_polling_period,
1151 no_rpki_polling_period_cmd,
e9f709e5 1152 "no rpki polling_period [(1-86400)]",
dabecd7c
MR
1153 NO_STR
1154 RPKI_OUTPUT_STRING
e9f709e5
DS
1155 "Set polling period back to default\n"
1156 "Polling period value\n")
dabecd7c
MR
1157{
1158 polling_period = POLLING_PERIOD_DEFAULT;
1159 return CMD_SUCCESS;
1160}
1161
1162DEFPY (rpki_expire_interval,
1163 rpki_expire_interval_cmd,
1164 "rpki expire_interval (600-172800)$tmp",
1165 RPKI_OUTPUT_STRING
1166 "Set expire interval\n"
1167 "Expire interval value\n")
1168{
6f577f58 1169 if ((unsigned int)tmp >= polling_period) {
dabecd7c
MR
1170 expire_interval = tmp;
1171 return CMD_SUCCESS;
1172 }
1173
1174 vty_out(vty, "%% Expiry interval must be polling period or larger\n");
1175 return CMD_WARNING_CONFIG_FAILED;
1176}
1177
1178DEFUN (no_rpki_expire_interval,
1179 no_rpki_expire_interval_cmd,
e9f709e5 1180 "no rpki expire_interval [(600-172800)]",
dabecd7c
MR
1181 NO_STR
1182 RPKI_OUTPUT_STRING
e9f709e5
DS
1183 "Set expire interval back to default\n"
1184 "Expire interval value\n")
dabecd7c
MR
1185{
1186 expire_interval = polling_period * 2;
1187 return CMD_SUCCESS;
1188}
1189
1190DEFPY (rpki_retry_interval,
1191 rpki_retry_interval_cmd,
1192 "rpki retry_interval (1-7200)$tmp",
1193 RPKI_OUTPUT_STRING
1194 "Set retry interval\n"
1195 "retry interval value\n")
1196{
1197 retry_interval = tmp;
1198 return CMD_SUCCESS;
1199}
1200
1201DEFUN (no_rpki_retry_interval,
1202 no_rpki_retry_interval_cmd,
e9f709e5 1203 "no rpki retry_interval [(1-7200)]",
dabecd7c
MR
1204 NO_STR
1205 RPKI_OUTPUT_STRING
e9f709e5
DS
1206 "Set retry interval back to default\n"
1207 "retry interval value\n")
dabecd7c
MR
1208{
1209 retry_interval = RETRY_INTERVAL_DEFAULT;
1210 return CMD_SUCCESS;
1211}
1212
7253a7bc 1213DEFPY(rpki_cache, rpki_cache_cmd,
2a5f5ec0 1214 "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
1215 RPKI_OUTPUT_STRING
1216 "Install a cache server to current group\n"
2a5f5ec0
DA
1217 "IP address of cache server\n"
1218 "Hostname of cache server\n"
7253a7bc
PG
1219 "TCP port number\n"
1220 "SSH port number\n"
1221 "SSH user name\n"
1222 "Path to own SSH private key\n"
7253a7bc 1223 "Path to Public key of cache server\n"
484fc374
IR
1224 "Configure source IP address of RPKI connection\n"
1225 "Define a Source IP Address\n"
7253a7bc
PG
1226 "Preference of the cache server\n"
1227 "Preference value\n")
dabecd7c 1228{
3f54c705 1229 int return_value;
a2ed7b2b
MR
1230 struct listnode *cache_node;
1231 struct cache *current_cache;
1232
1233 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, current_cache)) {
1234 if (current_cache->preference == preference) {
1235 vty_out(vty,
1236 "Cache with preference %ld is already configured\n",
1237 preference);
1238 return CMD_WARNING;
1239 }
1240 }
1241
dabecd7c
MR
1242
1243 // use ssh connection
1244 if (ssh_uname) {
1245#if defined(FOUND_SSH)
2a5f5ec0
DA
1246 return_value =
1247 add_ssh_cache(cache, sshport, ssh_uname, ssh_privkey,
1248 server_pubkey, preference, bindaddr_str);
dabecd7c 1249#else
3f54c705 1250 return_value = SUCCESS;
dabecd7c 1251 vty_out(vty,
3efd0893 1252 "ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n");
dabecd7c
MR
1253#endif
1254 } else { // use tcp connection
7253a7bc
PG
1255 return_value =
1256 add_tcp_cache(cache, tcpport, preference, bindaddr_str);
dabecd7c
MR
1257 }
1258
1259 if (return_value == ERROR) {
1260 vty_out(vty, "Could not create new rpki cache\n");
1261 return CMD_WARNING;
1262 }
1263
1264 return CMD_SUCCESS;
1265}
1266
1267DEFPY (no_rpki_cache,
1268 no_rpki_cache_cmd,
2a5f5ec0 1269 "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
1270 NO_STR
1271 RPKI_OUTPUT_STRING
cc22635a 1272 "Install a cache server to current group\n"
2a5f5ec0
DA
1273 "IP address of cache server\n"
1274 "Hostname of cache server\n"
dabecd7c
MR
1275 "TCP port number\n"
1276 "SSH port number\n"
cc22635a
DA
1277 "SSH user name\n"
1278 "Path to own SSH private key\n"
cc22635a
DA
1279 "Path to Public key of cache server\n"
1280 "Configure source IP address of RPKI connection\n"
1281 "Define a Source IP Address\n"
dabecd7c
MR
1282 "Preference of the cache server\n"
1283 "Preference value\n")
1284{
1285 struct cache *cache_p = find_cache(preference);
1286
222487fe 1287 if (!cache_p) {
11423e50
DA
1288 vty_out(vty, "Could not find cache with preference %ld\n",
1289 preference);
dabecd7c
MR
1290 return CMD_WARNING;
1291 }
1292
01fcc189 1293 if (is_running() && listcount(cache_list) == 1) {
8add1719 1294 stop();
01fcc189 1295 } else if (is_running()) {
dabecd7c 1296 if (rtr_mgr_remove_group(rtr_config, preference) == RTR_ERROR) {
11423e50
DA
1297 vty_out(vty,
1298 "Could not remove cache with preference %ld\n",
1299 preference);
dabecd7c
MR
1300 return CMD_WARNING;
1301 }
1302 }
1303
1304 listnode_delete(cache_list, cache_p);
1305 free_cache(cache_p);
1306
1307 return CMD_SUCCESS;
1308}
1309
dff41cc8 1310DEFPY (show_rpki_prefix_table,
dabecd7c 1311 show_rpki_prefix_table_cmd,
dff41cc8 1312 "show rpki prefix-table [json$uj]",
dabecd7c
MR
1313 SHOW_STR
1314 RPKI_OUTPUT_STRING
dff41cc8
DA
1315 "Show validated prefixes which were received from RPKI Cache\n"
1316 JSON_STR)
dabecd7c 1317{
dff41cc8
DA
1318 struct json_object *json = NULL;
1319
1320 if (!is_synchronized()) {
1321 if (!uj)
1322 vty_out(vty, "No connection to RPKI cache server.\n");
1323 return CMD_WARNING;
1324 }
1325
1326 if (uj)
1327 json = json_object_new_object();
dabecd7c 1328
dff41cc8 1329 print_prefix_table(vty, json);
dabecd7c
MR
1330 return CMD_SUCCESS;
1331}
1332
dff41cc8
DA
1333DEFPY (show_rpki_as_number,
1334 show_rpki_as_number_cmd,
1335 "show rpki as-number (1-4294967295)$by_asn [json$uj]",
1336 SHOW_STR
1337 RPKI_OUTPUT_STRING
1338 "Lookup by ASN in prefix table\n"
1339 "AS Number\n"
1340 JSON_STR)
02334bb2 1341{
dff41cc8
DA
1342 struct json_object *json = NULL;
1343
02334bb2 1344 if (!is_synchronized()) {
dff41cc8
DA
1345 if (!uj)
1346 vty_out(vty, "No Connection to RPKI cache server.\n");
02334bb2
DA
1347 return CMD_WARNING;
1348 }
1349
dff41cc8
DA
1350 if (uj)
1351 json = json_object_new_object();
1352
1353 print_prefix_table_by_asn(vty, by_asn, json);
02334bb2
DA
1354 return CMD_SUCCESS;
1355}
1356
5d799192
MR
1357DEFPY (show_rpki_prefix,
1358 show_rpki_prefix_cmd,
dff41cc8 1359 "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn] [json$uj]",
5d799192
MR
1360 SHOW_STR
1361 RPKI_OUTPUT_STRING
1362 "Lookup IP prefix and optionally ASN in prefix table\n"
1363 "IPv4 prefix\n"
1364 "IPv6 prefix\n"
dff41cc8
DA
1365 "AS Number\n"
1366 JSON_STR)
5d799192 1367{
dff41cc8
DA
1368 json_object *json = NULL;
1369 json_object *json_records = NULL;
5d799192
MR
1370
1371 if (!is_synchronized()) {
dff41cc8
DA
1372 if (!uj)
1373 vty_out(vty, "No Connection to RPKI cache server.\n");
5d799192
MR
1374 return CMD_WARNING;
1375 }
1376
1377 struct lrtr_ip_addr addr;
1378 char addr_str[INET6_ADDRSTRLEN];
1379 size_t addr_len = strchr(prefix_str, '/') - prefix_str;
1380
1381 memset(addr_str, 0, sizeof(addr_str));
1382 memcpy(addr_str, prefix_str, addr_len);
1383
1384 if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) {
dff41cc8
DA
1385 if (!json)
1386 vty_out(vty, "Invalid IP prefix\n");
5d799192
MR
1387 return CMD_WARNING;
1388 }
1389
1390 struct pfx_record *matches = NULL;
1391 unsigned int match_count = 0;
1392 enum pfxv_state result;
1393
1394 if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
1395 asn, &addr, prefix->prefixlen, &result)
1396 != PFX_SUCCESS) {
dff41cc8
DA
1397 if (!json)
1398 vty_out(vty, "Prefix lookup failed\n");
5d799192
MR
1399 return CMD_WARNING;
1400 }
1401
dff41cc8
DA
1402 if (uj)
1403 json = json_object_new_object();
1404
1405 if (!json) {
1406 vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length",
1407 "Origin-AS");
1408 } else {
1409 json_records = json_object_new_array();
1410 json_object_object_add(json, "prefixes", json_records);
1411 }
1412
5d799192
MR
1413 for (size_t i = 0; i < match_count; ++i) {
1414 const struct pfx_record *record = &matches[i];
1415
1416 if (record->max_len >= prefix->prefixlen
c17140fd
DS
1417 && ((asn != 0 && (uint32_t)asn == record->asn)
1418 || asn == 0)) {
dff41cc8 1419 print_record(&matches[i], vty, json_records);
5d799192
MR
1420 }
1421 }
1422
dff41cc8
DA
1423 if (json)
1424 vty_json(vty, json);
1425
5d799192
MR
1426 return CMD_SUCCESS;
1427}
1428
cc4d121f 1429DEFPY (show_rpki_cache_server,
dabecd7c 1430 show_rpki_cache_server_cmd,
cc4d121f 1431 "show rpki cache-server [json$uj]",
dabecd7c
MR
1432 SHOW_STR
1433 RPKI_OUTPUT_STRING
cc4d121f
DA
1434 "Show configured cache server\n"
1435 JSON_STR)
dabecd7c 1436{
cc4d121f
DA
1437 struct json_object *json = NULL;
1438 struct json_object *json_server = NULL;
1439 struct json_object *json_servers = NULL;
dabecd7c
MR
1440 struct listnode *cache_node;
1441 struct cache *cache;
1442
cc4d121f
DA
1443 if (uj) {
1444 json = json_object_new_object();
1445 json_servers = json_object_new_array();
1446 json_object_object_add(json, "servers", json_servers);
1447 }
1448
dabecd7c 1449 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
745ae9c0 1450 if (cache->type == TCP) {
cc4d121f 1451 if (!json) {
77be6d6a
DA
1452 vty_out(vty,
1453 "host: %s port: %s, preference: %hhu\n",
cc4d121f 1454 cache->tr_config.tcp_config->host,
77be6d6a
DA
1455 cache->tr_config.tcp_config->port,
1456 cache->preference);
cc4d121f
DA
1457 } else {
1458 json_server = json_object_new_object();
1459 json_object_string_add(json_server, "mode",
1460 "tcp");
1461 json_object_string_add(
1462 json_server, "host",
1463 cache->tr_config.tcp_config->host);
1464 json_object_string_add(
1465 json_server, "port",
1466 cache->tr_config.tcp_config->port);
77be6d6a
DA
1467 json_object_int_add(json_server, "preference",
1468 cache->preference);
cc4d121f
DA
1469 json_object_array_add(json_servers,
1470 json_server);
1471 }
745ae9c0 1472
fef6fafa 1473#if defined(FOUND_SSH)
745ae9c0 1474 } else if (cache->type == SSH) {
cc4d121f
DA
1475 if (!json) {
1476 vty_out(vty,
77be6d6a 1477 "host: %s port: %d username: %s server_hostkey_path: %s client_privkey_path: %s, preference: %hhu\n",
cc4d121f
DA
1478 cache->tr_config.ssh_config->host,
1479 cache->tr_config.ssh_config->port,
1480 cache->tr_config.ssh_config->username,
1481 cache->tr_config.ssh_config
1482 ->server_hostkey_path,
1483 cache->tr_config.ssh_config
77be6d6a
DA
1484 ->client_privkey_path,
1485 cache->preference);
cc4d121f
DA
1486 } else {
1487 json_server = json_object_new_object();
1488 json_object_string_add(json_server, "mode",
1489 "ssh");
1490 json_object_string_add(
1491 json_server, "host",
1492 cache->tr_config.ssh_config->host);
1493 json_object_int_add(
1494 json_server, "port",
1495 cache->tr_config.ssh_config->port);
1496 json_object_string_add(
1497 json_server, "username",
1498 cache->tr_config.ssh_config->username);
1499 json_object_string_add(
1500 json_server, "serverHostkeyPath",
1501 cache->tr_config.ssh_config
1502 ->server_hostkey_path);
1503 json_object_string_add(
1504 json_server, "clientPrivkeyPath",
1505 cache->tr_config.ssh_config
1506 ->client_privkey_path);
77be6d6a
DA
1507 json_object_int_add(json_server, "preference",
1508 cache->preference);
cc4d121f
DA
1509 json_object_array_add(json_servers,
1510 json_server);
1511 }
fef6fafa 1512#endif
745ae9c0 1513 }
dabecd7c
MR
1514 }
1515
cc4d121f
DA
1516 if (json)
1517 vty_json(vty, json);
1518
dabecd7c
MR
1519 return CMD_SUCCESS;
1520}
1521
ae872c2f 1522DEFPY (show_rpki_cache_connection,
dabecd7c 1523 show_rpki_cache_connection_cmd,
ae872c2f 1524 "show rpki cache-connection [json$uj]",
dabecd7c
MR
1525 SHOW_STR
1526 RPKI_OUTPUT_STRING
ae872c2f
DA
1527 "Show to which RPKI Cache Servers we have a connection\n"
1528 JSON_STR)
dabecd7c 1529{
ae872c2f
DA
1530 struct json_object *json = NULL;
1531 struct json_object *json_conn = NULL;
1532 struct json_object *json_conns = NULL;
1533 struct listnode *cache_node;
1534 struct cache *cache;
1535 struct rtr_mgr_group *group;
1536
1537 if (uj)
1538 json = json_object_new_object();
1539
708b8053 1540 if (!is_synchronized()) {
ae872c2f
DA
1541 if (!json)
1542 vty_out(vty, "No connection to RPKI cache server.\n");
1543 else
1544 vty_json(vty, json);
708b8053
DS
1545
1546 return CMD_SUCCESS;
1547 }
1548
ae872c2f 1549 group = get_connected_group();
708b8053 1550 if (!group) {
ae872c2f
DA
1551 if (!json)
1552 vty_out(vty, "Cannot find a connected group.\n");
1553 else
1554 vty_json(vty, json);
1555
708b8053
DS
1556 return CMD_SUCCESS;
1557 }
ae872c2f
DA
1558
1559 if (!json) {
1560 vty_out(vty, "Connected to group %d\n", group->preference);
1561 } else {
1562 json_conns = json_object_new_array();
1563 json_object_int_add(json, "connectedGroup", group->preference);
1564 json_object_object_add(json, "connections", json_conns);
1565 }
1566
708b8053 1567 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
c1a68b62 1568 struct tr_tcp_config *tcp_config;
acd4a9f4 1569#if defined(FOUND_SSH)
c1a68b62 1570 struct tr_ssh_config *ssh_config;
acd4a9f4 1571#endif
c1a68b62
DA
1572 switch (cache->type) {
1573 case TCP:
1574 tcp_config = cache->tr_config.tcp_config;
ae872c2f
DA
1575
1576 if (!json) {
1577 vty_out(vty,
1578 "rpki tcp cache %s %s pref %hhu%s\n",
1579 tcp_config->host, tcp_config->port,
1580 cache->preference,
1581 cache->rtr_socket->state ==
1582 RTR_ESTABLISHED
1583 ? " (connected)"
1584 : "");
1585 } else {
1586 json_conn = json_object_new_object();
1587 json_object_string_add(json_conn, "mode",
1588 "tcp");
1589 json_object_string_add(json_conn, "host",
1590 tcp_config->host);
1591 json_object_string_add(json_conn, "port",
1592 tcp_config->port);
1593 json_object_int_add(json_conn, "preference",
1594 cache->preference);
1595 json_object_string_add(
1596 json_conn, "state",
1597 cache->rtr_socket->state ==
1598 RTR_ESTABLISHED
1599 ? "connected"
1600 : "disconnected");
1601 json_object_array_add(json_conns, json_conn);
1602 }
c1a68b62 1603 break;
dabecd7c 1604#if defined(FOUND_SSH)
c1a68b62
DA
1605 case SSH:
1606 ssh_config = cache->tr_config.ssh_config;
ae872c2f
DA
1607
1608 if (!json) {
1609 vty_out(vty,
1610 "rpki ssh cache %s %u pref %hhu%s\n",
1611 ssh_config->host, ssh_config->port,
1612 cache->preference,
1613 cache->rtr_socket->state ==
1614 RTR_ESTABLISHED
1615 ? " (connected)"
1616 : "");
1617 } else {
1618 json_conn = json_object_new_object();
1619 json_object_string_add(json_conn, "mode",
1620 "ssh");
1621 json_object_string_add(json_conn, "host",
1622 ssh_config->host);
4d4b9dc1
DA
1623 json_object_int_add(json_conn, "port",
1624 ssh_config->port);
ae872c2f
DA
1625 json_object_int_add(json_conn, "preference",
1626 cache->preference);
1627 json_object_string_add(
1628 json_conn, "state",
1629 cache->rtr_socket->state ==
1630 RTR_ESTABLISHED
1631 ? "connected"
1632 : "disconnected");
1633 json_object_array_add(json_conns, json_conn);
1634 }
c1a68b62 1635 break;
dabecd7c 1636#endif
c1a68b62
DA
1637 default:
1638 break;
dabecd7c 1639 }
dabecd7c
MR
1640 }
1641
ae872c2f
DA
1642 if (json)
1643 vty_json(vty, json);
1644
dabecd7c
MR
1645 return CMD_SUCCESS;
1646}
1647
791ded4a 1648static int config_on_exit(struct vty *vty)
dabecd7c 1649{
61a484a9 1650 reset(false);
791ded4a 1651 return 1;
dabecd7c
MR
1652}
1653
1654DEFUN (rpki_reset,
1655 rpki_reset_cmd,
1656 "rpki reset",
1657 RPKI_OUTPUT_STRING
1658 "reset rpki\n")
1659{
1660 return reset(true) == SUCCESS ? CMD_SUCCESS : CMD_WARNING;
1661}
1662
1663DEFUN (debug_rpki,
1664 debug_rpki_cmd,
1665 "debug rpki",
1666 DEBUG_STR
08f9cfb8 1667 "Enable debugging for rpki\n")
dabecd7c 1668{
0e3d96bf 1669 rpki_debug = true;
dabecd7c
MR
1670 return CMD_SUCCESS;
1671}
1672
1673DEFUN (no_debug_rpki,
1674 no_debug_rpki_cmd,
1675 "no debug rpki",
1676 NO_STR
1677 DEBUG_STR
08f9cfb8 1678 "Disable debugging for rpki\n")
dabecd7c 1679{
0e3d96bf 1680 rpki_debug = false;
dabecd7c
MR
1681 return CMD_SUCCESS;
1682}
1683
48cb7ea9 1684DEFUN_YANG (match_rpki,
dabecd7c
MR
1685 match_rpki_cmd,
1686 "match rpki <valid|invalid|notfound>",
1687 MATCH_STR
1688 RPKI_OUTPUT_STRING
1689 "Valid prefix\n"
1690 "Invalid prefix\n"
1691 "Prefix not found\n")
1692{
48cb7ea9
SP
1693 const char *xpath =
1694 "./match-condition[condition='frr-bgp-route-map:rpki']";
1695 char xpath_value[XPATH_MAXLEN];
69337c34 1696
48cb7ea9
SP
1697 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
1698 snprintf(xpath_value, sizeof(xpath_value),
1699 "%s/rmap-match-condition/frr-bgp-route-map:rpki", xpath);
1700 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[2]->arg);
1701
1702 return nb_cli_apply_changes(vty, NULL);
dabecd7c
MR
1703}
1704
48cb7ea9 1705DEFUN_YANG (no_match_rpki,
dabecd7c
MR
1706 no_match_rpki_cmd,
1707 "no match rpki <valid|invalid|notfound>",
1708 NO_STR
1709 MATCH_STR
1710 RPKI_OUTPUT_STRING
1711 "Valid prefix\n"
1712 "Invalid prefix\n"
1713 "Prefix not found\n")
1714{
48cb7ea9
SP
1715 const char *xpath =
1716 "./match-condition[condition='frr-bgp-route-map:rpki']";
dabecd7c 1717
87c3ed1b 1718 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
48cb7ea9 1719 return nb_cli_apply_changes(vty, NULL);
dabecd7c
MR
1720}
1721
dabecd7c
MR
1722static void install_cli_commands(void)
1723{
996c9314 1724 // TODO: make config write work
612c2c15 1725 install_node(&rpki_node);
dabecd7c 1726 install_default(RPKI_NODE);
dabecd7c 1727 install_element(CONFIG_NODE, &rpki_cmd);
9593708d 1728 install_element(ENABLE_NODE, &rpki_cmd);
8156765a
DA
1729 install_element(CONFIG_NODE, &no_rpki_cmd);
1730
dabecd7c
MR
1731
1732 install_element(ENABLE_NODE, &bgp_rpki_start_cmd);
1733 install_element(ENABLE_NODE, &bgp_rpki_stop_cmd);
1734
1735 /* Install rpki reset command */
8f14ae47 1736 install_element(ENABLE_NODE, &rpki_reset_cmd);
dabecd7c
MR
1737 install_element(RPKI_NODE, &rpki_reset_cmd);
1738
1739 /* Install rpki polling period commands */
1740 install_element(RPKI_NODE, &rpki_polling_period_cmd);
1741 install_element(RPKI_NODE, &no_rpki_polling_period_cmd);
1742
1743 /* Install rpki expire interval commands */
1744 install_element(RPKI_NODE, &rpki_expire_interval_cmd);
1745 install_element(RPKI_NODE, &no_rpki_expire_interval_cmd);
1746
1747 /* Install rpki retry interval commands */
1748 install_element(RPKI_NODE, &rpki_retry_interval_cmd);
1749 install_element(RPKI_NODE, &no_rpki_retry_interval_cmd);
1750
dabecd7c
MR
1751 /* Install rpki cache commands */
1752 install_element(RPKI_NODE, &rpki_cache_cmd);
1753 install_element(RPKI_NODE, &no_rpki_cache_cmd);
1754
1755 /* Install show commands */
9593708d 1756 install_element(VIEW_NODE, &show_rpki_prefix_table_cmd);
1757 install_element(VIEW_NODE, &show_rpki_cache_connection_cmd);
1758 install_element(VIEW_NODE, &show_rpki_cache_server_cmd);
1759 install_element(VIEW_NODE, &show_rpki_prefix_cmd);
02334bb2 1760 install_element(VIEW_NODE, &show_rpki_as_number_cmd);
dabecd7c
MR
1761
1762 /* Install debug commands */
1763 install_element(CONFIG_NODE, &debug_rpki_cmd);
1764 install_element(ENABLE_NODE, &debug_rpki_cmd);
1765 install_element(CONFIG_NODE, &no_debug_rpki_cmd);
1766 install_element(ENABLE_NODE, &no_debug_rpki_cmd);
1767
1768 /* Install route match */
1769 route_map_install_match(&route_match_rpki_cmd);
1770 install_element(RMAP_NODE, &match_rpki_cmd);
1771 install_element(RMAP_NODE, &no_match_rpki_cmd);
1772}
1773
1774FRR_MODULE_SETUP(.name = "bgpd_rpki", .version = "0.3.6",
1775 .description = "Enable RPKI support for FRR.",
80413c20
DL
1776 .init = bgp_rpki_module_init,
1777);