]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_rpki.c
Merge pull request #11290 from donaldsharp/bgp_auth_breakup
[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 1196{
dabecd7c
MR
1197 if (is_synchronized())
1198 print_prefix_table(vty);
1199 else
1200 vty_out(vty, "No connection to RPKI cache server.\n");
1201
1202 return CMD_SUCCESS;
1203}
1204
48cb7ea9 1205DEFPY (show_rpki_as_number, show_rpki_as_number_cmd,
02334bb2
DA
1206 "show rpki as-number (1-4294967295)$by_asn",
1207 SHOW_STR RPKI_OUTPUT_STRING
1208 "Lookup by ASN in prefix table\n"
1209 "AS Number\n")
1210{
1211 if (!is_synchronized()) {
1212 vty_out(vty, "No Connection to RPKI cache server.\n");
1213 return CMD_WARNING;
1214 }
1215
1216 print_prefix_table_by_asn(vty, by_asn);
1217 return CMD_SUCCESS;
1218}
1219
5d799192
MR
1220DEFPY (show_rpki_prefix,
1221 show_rpki_prefix_cmd,
1222 "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn]",
1223 SHOW_STR
1224 RPKI_OUTPUT_STRING
1225 "Lookup IP prefix and optionally ASN in prefix table\n"
1226 "IPv4 prefix\n"
1227 "IPv6 prefix\n"
1228 "AS Number\n")
1229{
1230
1231 if (!is_synchronized()) {
f79f7a7b 1232 vty_out(vty, "No Connection to RPKI cache server.\n");
5d799192
MR
1233 return CMD_WARNING;
1234 }
1235
1236 struct lrtr_ip_addr addr;
1237 char addr_str[INET6_ADDRSTRLEN];
1238 size_t addr_len = strchr(prefix_str, '/') - prefix_str;
1239
1240 memset(addr_str, 0, sizeof(addr_str));
1241 memcpy(addr_str, prefix_str, addr_len);
1242
1243 if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) {
1244 vty_out(vty, "Invalid IP prefix\n");
1245 return CMD_WARNING;
1246 }
1247
1248 struct pfx_record *matches = NULL;
1249 unsigned int match_count = 0;
1250 enum pfxv_state result;
1251
1252 if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
1253 asn, &addr, prefix->prefixlen, &result)
1254 != PFX_SUCCESS) {
4d4c404b 1255 vty_out(vty, "Prefix lookup failed\n");
5d799192
MR
1256 return CMD_WARNING;
1257 }
1258
1259 vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
1260 for (size_t i = 0; i < match_count; ++i) {
1261 const struct pfx_record *record = &matches[i];
1262
1263 if (record->max_len >= prefix->prefixlen
c17140fd
DS
1264 && ((asn != 0 && (uint32_t)asn == record->asn)
1265 || asn == 0)) {
5d799192
MR
1266 print_record(&matches[i], vty);
1267 }
1268 }
1269
1270 return CMD_SUCCESS;
1271}
1272
cc4d121f 1273DEFPY (show_rpki_cache_server,
dabecd7c 1274 show_rpki_cache_server_cmd,
cc4d121f 1275 "show rpki cache-server [json$uj]",
dabecd7c
MR
1276 SHOW_STR
1277 RPKI_OUTPUT_STRING
cc4d121f
DA
1278 "Show configured cache server\n"
1279 JSON_STR)
dabecd7c 1280{
cc4d121f
DA
1281 struct json_object *json = NULL;
1282 struct json_object *json_server = NULL;
1283 struct json_object *json_servers = NULL;
dabecd7c
MR
1284 struct listnode *cache_node;
1285 struct cache *cache;
1286
cc4d121f
DA
1287 if (uj) {
1288 json = json_object_new_object();
1289 json_servers = json_object_new_array();
1290 json_object_object_add(json, "servers", json_servers);
1291 }
1292
dabecd7c 1293 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
745ae9c0 1294 if (cache->type == TCP) {
cc4d121f
DA
1295 if (!json) {
1296 vty_out(vty, "host: %s port: %s\n",
1297 cache->tr_config.tcp_config->host,
1298 cache->tr_config.tcp_config->port);
1299 } else {
1300 json_server = json_object_new_object();
1301 json_object_string_add(json_server, "mode",
1302 "tcp");
1303 json_object_string_add(
1304 json_server, "host",
1305 cache->tr_config.tcp_config->host);
1306 json_object_string_add(
1307 json_server, "port",
1308 cache->tr_config.tcp_config->port);
1309 json_object_array_add(json_servers,
1310 json_server);
1311 }
745ae9c0 1312
fef6fafa 1313#if defined(FOUND_SSH)
745ae9c0 1314 } else if (cache->type == SSH) {
cc4d121f
DA
1315 if (!json) {
1316 vty_out(vty,
1317 "host: %s port: %d username: %s server_hostkey_path: %s client_privkey_path: %s\n",
1318 cache->tr_config.ssh_config->host,
1319 cache->tr_config.ssh_config->port,
1320 cache->tr_config.ssh_config->username,
1321 cache->tr_config.ssh_config
1322 ->server_hostkey_path,
1323 cache->tr_config.ssh_config
1324 ->client_privkey_path);
1325 } else {
1326 json_server = json_object_new_object();
1327 json_object_string_add(json_server, "mode",
1328 "ssh");
1329 json_object_string_add(
1330 json_server, "host",
1331 cache->tr_config.ssh_config->host);
1332 json_object_int_add(
1333 json_server, "port",
1334 cache->tr_config.ssh_config->port);
1335 json_object_string_add(
1336 json_server, "username",
1337 cache->tr_config.ssh_config->username);
1338 json_object_string_add(
1339 json_server, "serverHostkeyPath",
1340 cache->tr_config.ssh_config
1341 ->server_hostkey_path);
1342 json_object_string_add(
1343 json_server, "clientPrivkeyPath",
1344 cache->tr_config.ssh_config
1345 ->client_privkey_path);
1346 json_object_array_add(json_servers,
1347 json_server);
1348 }
fef6fafa 1349#endif
745ae9c0 1350 }
dabecd7c
MR
1351 }
1352
cc4d121f
DA
1353 if (json)
1354 vty_json(vty, json);
1355
dabecd7c
MR
1356 return CMD_SUCCESS;
1357}
1358
ae872c2f 1359DEFPY (show_rpki_cache_connection,
dabecd7c 1360 show_rpki_cache_connection_cmd,
ae872c2f 1361 "show rpki cache-connection [json$uj]",
dabecd7c
MR
1362 SHOW_STR
1363 RPKI_OUTPUT_STRING
ae872c2f
DA
1364 "Show to which RPKI Cache Servers we have a connection\n"
1365 JSON_STR)
dabecd7c 1366{
ae872c2f
DA
1367 struct json_object *json = NULL;
1368 struct json_object *json_conn = NULL;
1369 struct json_object *json_conns = NULL;
1370 struct listnode *cache_node;
1371 struct cache *cache;
1372 struct rtr_mgr_group *group;
1373
1374 if (uj)
1375 json = json_object_new_object();
1376
708b8053 1377 if (!is_synchronized()) {
ae872c2f
DA
1378 if (!json)
1379 vty_out(vty, "No connection to RPKI cache server.\n");
1380 else
1381 vty_json(vty, json);
708b8053
DS
1382
1383 return CMD_SUCCESS;
1384 }
1385
ae872c2f 1386 group = get_connected_group();
708b8053 1387 if (!group) {
ae872c2f
DA
1388 if (!json)
1389 vty_out(vty, "Cannot find a connected group.\n");
1390 else
1391 vty_json(vty, json);
1392
708b8053
DS
1393 return CMD_SUCCESS;
1394 }
ae872c2f
DA
1395
1396 if (!json) {
1397 vty_out(vty, "Connected to group %d\n", group->preference);
1398 } else {
1399 json_conns = json_object_new_array();
1400 json_object_int_add(json, "connectedGroup", group->preference);
1401 json_object_object_add(json, "connections", json_conns);
1402 }
1403
708b8053 1404 for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
c1a68b62 1405 struct tr_tcp_config *tcp_config;
acd4a9f4 1406#if defined(FOUND_SSH)
c1a68b62 1407 struct tr_ssh_config *ssh_config;
acd4a9f4 1408#endif
c1a68b62
DA
1409 switch (cache->type) {
1410 case TCP:
1411 tcp_config = cache->tr_config.tcp_config;
ae872c2f
DA
1412
1413 if (!json) {
1414 vty_out(vty,
1415 "rpki tcp cache %s %s pref %hhu%s\n",
1416 tcp_config->host, tcp_config->port,
1417 cache->preference,
1418 cache->rtr_socket->state ==
1419 RTR_ESTABLISHED
1420 ? " (connected)"
1421 : "");
1422 } else {
1423 json_conn = json_object_new_object();
1424 json_object_string_add(json_conn, "mode",
1425 "tcp");
1426 json_object_string_add(json_conn, "host",
1427 tcp_config->host);
1428 json_object_string_add(json_conn, "port",
1429 tcp_config->port);
1430 json_object_int_add(json_conn, "preference",
1431 cache->preference);
1432 json_object_string_add(
1433 json_conn, "state",
1434 cache->rtr_socket->state ==
1435 RTR_ESTABLISHED
1436 ? "connected"
1437 : "disconnected");
1438 json_object_array_add(json_conns, json_conn);
1439 }
c1a68b62 1440 break;
dabecd7c 1441#if defined(FOUND_SSH)
c1a68b62
DA
1442 case SSH:
1443 ssh_config = cache->tr_config.ssh_config;
ae872c2f
DA
1444
1445 if (!json) {
1446 vty_out(vty,
1447 "rpki ssh cache %s %u pref %hhu%s\n",
1448 ssh_config->host, ssh_config->port,
1449 cache->preference,
1450 cache->rtr_socket->state ==
1451 RTR_ESTABLISHED
1452 ? " (connected)"
1453 : "");
1454 } else {
1455 json_conn = json_object_new_object();
1456 json_object_string_add(json_conn, "mode",
1457 "ssh");
1458 json_object_string_add(json_conn, "host",
1459 ssh_config->host);
4d4b9dc1
DA
1460 json_object_int_add(json_conn, "port",
1461 ssh_config->port);
ae872c2f
DA
1462 json_object_int_add(json_conn, "preference",
1463 cache->preference);
1464 json_object_string_add(
1465 json_conn, "state",
1466 cache->rtr_socket->state ==
1467 RTR_ESTABLISHED
1468 ? "connected"
1469 : "disconnected");
1470 json_object_array_add(json_conns, json_conn);
1471 }
c1a68b62 1472 break;
dabecd7c 1473#endif
c1a68b62
DA
1474 default:
1475 break;
dabecd7c 1476 }
dabecd7c
MR
1477 }
1478
ae872c2f
DA
1479 if (json)
1480 vty_json(vty, json);
1481
dabecd7c
MR
1482 return CMD_SUCCESS;
1483}
1484
791ded4a 1485static int config_on_exit(struct vty *vty)
dabecd7c 1486{
61a484a9 1487 reset(false);
791ded4a 1488 return 1;
dabecd7c
MR
1489}
1490
1491DEFUN (rpki_reset,
1492 rpki_reset_cmd,
1493 "rpki reset",
1494 RPKI_OUTPUT_STRING
1495 "reset rpki\n")
1496{
1497 return reset(true) == SUCCESS ? CMD_SUCCESS : CMD_WARNING;
1498}
1499
1500DEFUN (debug_rpki,
1501 debug_rpki_cmd,
1502 "debug rpki",
1503 DEBUG_STR
08f9cfb8 1504 "Enable debugging for rpki\n")
dabecd7c 1505{
0e3d96bf 1506 rpki_debug = true;
dabecd7c
MR
1507 return CMD_SUCCESS;
1508}
1509
1510DEFUN (no_debug_rpki,
1511 no_debug_rpki_cmd,
1512 "no debug rpki",
1513 NO_STR
1514 DEBUG_STR
08f9cfb8 1515 "Disable debugging for rpki\n")
dabecd7c 1516{
0e3d96bf 1517 rpki_debug = false;
dabecd7c
MR
1518 return CMD_SUCCESS;
1519}
1520
48cb7ea9 1521DEFUN_YANG (match_rpki,
dabecd7c
MR
1522 match_rpki_cmd,
1523 "match rpki <valid|invalid|notfound>",
1524 MATCH_STR
1525 RPKI_OUTPUT_STRING
1526 "Valid prefix\n"
1527 "Invalid prefix\n"
1528 "Prefix not found\n")
1529{
48cb7ea9
SP
1530 const char *xpath =
1531 "./match-condition[condition='frr-bgp-route-map:rpki']";
1532 char xpath_value[XPATH_MAXLEN];
69337c34 1533
48cb7ea9
SP
1534 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
1535 snprintf(xpath_value, sizeof(xpath_value),
1536 "%s/rmap-match-condition/frr-bgp-route-map:rpki", xpath);
1537 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[2]->arg);
1538
1539 return nb_cli_apply_changes(vty, NULL);
dabecd7c
MR
1540}
1541
48cb7ea9 1542DEFUN_YANG (no_match_rpki,
dabecd7c
MR
1543 no_match_rpki_cmd,
1544 "no match rpki <valid|invalid|notfound>",
1545 NO_STR
1546 MATCH_STR
1547 RPKI_OUTPUT_STRING
1548 "Valid prefix\n"
1549 "Invalid prefix\n"
1550 "Prefix not found\n")
1551{
48cb7ea9
SP
1552 const char *xpath =
1553 "./match-condition[condition='frr-bgp-route-map:rpki']";
dabecd7c 1554
48cb7ea9
SP
1555 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
1556 return nb_cli_apply_changes(vty, NULL);
dabecd7c
MR
1557}
1558
dabecd7c
MR
1559static void install_cli_commands(void)
1560{
996c9314 1561 // TODO: make config write work
612c2c15 1562 install_node(&rpki_node);
dabecd7c 1563 install_default(RPKI_NODE);
dabecd7c 1564 install_element(CONFIG_NODE, &rpki_cmd);
9593708d 1565 install_element(ENABLE_NODE, &rpki_cmd);
dabecd7c
MR
1566
1567 install_element(ENABLE_NODE, &bgp_rpki_start_cmd);
1568 install_element(ENABLE_NODE, &bgp_rpki_stop_cmd);
1569
1570 /* Install rpki reset command */
8f14ae47 1571 install_element(ENABLE_NODE, &rpki_reset_cmd);
dabecd7c
MR
1572 install_element(RPKI_NODE, &rpki_reset_cmd);
1573
1574 /* Install rpki polling period commands */
1575 install_element(RPKI_NODE, &rpki_polling_period_cmd);
1576 install_element(RPKI_NODE, &no_rpki_polling_period_cmd);
1577
1578 /* Install rpki expire interval commands */
1579 install_element(RPKI_NODE, &rpki_expire_interval_cmd);
1580 install_element(RPKI_NODE, &no_rpki_expire_interval_cmd);
1581
1582 /* Install rpki retry interval commands */
1583 install_element(RPKI_NODE, &rpki_retry_interval_cmd);
1584 install_element(RPKI_NODE, &no_rpki_retry_interval_cmd);
1585
dabecd7c
MR
1586 /* Install rpki cache commands */
1587 install_element(RPKI_NODE, &rpki_cache_cmd);
1588 install_element(RPKI_NODE, &no_rpki_cache_cmd);
1589
1590 /* Install show commands */
9593708d 1591 install_element(VIEW_NODE, &show_rpki_prefix_table_cmd);
1592 install_element(VIEW_NODE, &show_rpki_cache_connection_cmd);
1593 install_element(VIEW_NODE, &show_rpki_cache_server_cmd);
1594 install_element(VIEW_NODE, &show_rpki_prefix_cmd);
02334bb2 1595 install_element(VIEW_NODE, &show_rpki_as_number_cmd);
dabecd7c
MR
1596
1597 /* Install debug commands */
1598 install_element(CONFIG_NODE, &debug_rpki_cmd);
1599 install_element(ENABLE_NODE, &debug_rpki_cmd);
1600 install_element(CONFIG_NODE, &no_debug_rpki_cmd);
1601 install_element(ENABLE_NODE, &no_debug_rpki_cmd);
1602
1603 /* Install route match */
1604 route_map_install_match(&route_match_rpki_cmd);
1605 install_element(RMAP_NODE, &match_rpki_cmd);
1606 install_element(RMAP_NODE, &no_match_rpki_cmd);
1607}
1608
1609FRR_MODULE_SETUP(.name = "bgpd_rpki", .version = "0.3.6",
1610 .description = "Enable RPKI support for FRR.",
80413c20
DL
1611 .init = bgp_rpki_module_init,
1612);