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