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