From 27d7aae89f31feef50135c571150186d2f7607e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Wed, 6 Jan 2016 15:55:29 +0100 Subject: [PATCH] RPKI: Add the basis for manager --- proto/rpki/rpki.c | 98 ++++++++++++++++++++++++++++---------- proto/rpki/rpki.h | 40 +++++++++++----- proto/rpki/rtr.c | 32 ++++++++++++- proto/rpki/rtr.h | 7 --- proto/rpki/ssh_transport.c | 2 +- proto/rpki/tcp_transport.c | 5 +- 6 files changed, 136 insertions(+), 48 deletions(-) diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index 2f82c8fb..e358a219 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -24,8 +24,22 @@ #include #include +#include #include "rpki.h" +static const char *mgr_str_status[] = { + [RTR_MGR_CLOSED] = "RTR_MGR_CLOSED", + [RTR_MGR_CONNECTING] = "RTR_MGR_CONNECTING", + [RTR_MGR_ESTABLISHED] = "RTR_MGR_ESTABLISHED", + [RTR_MGR_ERROR] = "RTR_MGR_ERROR", +}; + +const char * +get_group_status(struct rpki_cache_group *group) +{ + return mgr_str_status[group->status]; +} + static struct proto * rpki_init(struct proto_config *C) { @@ -44,6 +58,22 @@ get_cache_ident(struct rpki_cache *cache) return tr_ident(cache->rtr_socket->tr_socket); } +void +debug_print_groups(struct rpki_proto *p) +{ + struct rpki_cache_group *g; + WALK_LIST(g, p->group_list) + { + DBG("Group(%u) %s \n", g->preference, get_group_status(g)); + + struct rpki_cache *c; + WALK_LIST(c, g->cache_list) + { + DBG(" Cache(%s) %s \n", get_cache_ident(c), rtr_state_to_str(c->rtr_socket->state)); + } + } +} + static struct rpki_cache_group * rpki_cache_group_alloc(struct rpki_proto *p, u8 preference) { @@ -76,6 +106,7 @@ rpki_insert_cache_into_group(struct rpki_cache *cache) if (group_iter->preference == cache->cfg->preference) { add_tail(&group_iter->cache_list, &cache->n); + cache->group = group_iter; return; } @@ -83,6 +114,7 @@ rpki_insert_cache_into_group(struct rpki_cache *cache) { struct rpki_cache_group *new_group = rpki_new_cache_group_before(p, group_iter, &p->group_list, cache->cfg->preference); add_tail(&new_group->cache_list, &cache->n); + cache->group = new_group; return; } } @@ -90,6 +122,7 @@ rpki_insert_cache_into_group(struct rpki_cache *cache) struct rpki_cache_group *new_group = rpki_cache_group_alloc(p, cache->cfg->preference); add_tail(&p->group_list, &new_group->n); add_tail(&new_group->cache_list, &cache->n); + cache->group = new_group; } struct rpki_cache_cfg * @@ -227,8 +260,11 @@ rpki_open_connection(struct rpki_cache *cache) return TR_SUCCESS; } +/* + * Open connections to all caches in group + */ static void -rpki_open_group(struct rpki_proto *p, struct rpki_cache_group *group) +rpki_open_group(struct rpki_cache_group *group) { struct rpki_cache *cache; WALK_LIST(cache, group->cache_list) @@ -239,7 +275,7 @@ rpki_open_group(struct rpki_proto *p, struct rpki_cache_group *group) } static void -rpki_close_group(struct rpki_proto *p, struct rpki_cache_group *group) +rpki_close_group(struct rpki_cache_group *group) { struct rpki_cache *cache; WALK_LIST(cache, group->cache_list) @@ -347,11 +383,8 @@ find_cache_in_proto_by_host_and_port(struct rpki_proto *p, struct rpki_cache_cfg return NULL; } -/* - * Remove empty cache groups in list - */ static void -rpki_relax_group_list(struct rpki_proto *p) +remove_empty_cache_groups(struct rpki_proto *p) { struct rpki_cache_group *group, *group_nxt; WALK_LIST_DELSAFE(group, group_nxt, p->group_list) @@ -369,32 +402,55 @@ move_cache_into_group(struct rpki_cache *cache) { rpki_remove_cache_from_group(cache); rpki_insert_cache_into_group(cache); - rpki_relax_group_list(cache->p); + remove_empty_cache_groups(cache->p); } /* - * Start connections to caches in the first (the highest priority) group - * and shut down all connections to caches in others groups + * Go through the group list ordered by priority. + * Open the first CLOSED group or stop opening groups if the processed group state is CONNECTING or ESTABLISHED + * Then close all groups with the more unimportant priority */ -static int +void rpki_relax_groups(struct rpki_proto *p) { + RPKI_TRACE(D_EVENTS, p, "rpki_relax_groups START"); + debug_print_groups(p); + if (EMPTY_LIST(p->group_list)) { RPKI_WARN(p, "No cache in configuration found"); - return 0; + return; } + bool close_all_next_groups = false; + struct rpki_cache_group *group; WALK_LIST(group, p->group_list) { - if (group == (struct rpki_cache_group *) p->group_list.head) - rpki_open_group(p, group); + if (!close_all_next_groups) + { + switch (group->status) + { + case RTR_MGR_CLOSED: + RPKI_TRACE(D_EVENTS, p, "rpki_relax_groups open group(%u)", group->preference); + rpki_open_group(group); + /* Fall through */ + case RTR_MGR_CONNECTING: + case RTR_MGR_ESTABLISHED: + close_all_next_groups = 1; + break; + + case RTR_MGR_ERROR: + break; + } + } else - rpki_close_group(p, group); + rpki_close_group(group); } - return 1; + debug_print_groups(p); + RPKI_TRACE(D_EVENTS, p, "rpki_relax_groups END"); + return; } static int @@ -466,17 +522,7 @@ rpki_reconfigure_proto(struct rpki_proto *p, struct rpki_config *new_cf, struct } } - struct rpki_cache_group *g; - WALK_LIST(g, p->group_list) - { - DBG("Group(%u)", g->preference); - - struct rpki_cache *c; - WALK_LIST(c, g->cache_list) - { - DBG(" Cache(%s)", get_cache_ident(c)); - } - } + debug_print_groups(p); return 1; } diff --git a/proto/rpki/rpki.h b/proto/rpki/rpki.h index 70669bd6..e783c55a 100644 --- a/proto/rpki/rpki.h +++ b/proto/rpki/rpki.h @@ -28,6 +28,29 @@ #define RPKI_DEFAULT_EXPIRE_INTERVAL 1200 #define RPKI_DEFAULT_CACHE_PREFERENCE 1 /* The most important priority */ +/* + * +-------------------------------------------+ + * v | + * RTR_MGR_CLOSED <--> RTR_MGR_CONNECTING --> RTR_MGR_ESTABLISHED <--> RTR_MGR_ERROR + * ^ | ^ | + * | +-----------------------------------------+ | + * | | + * +-----------------------------------------------------------------+ + */ +enum rtr_mgr_status { + /* RTR sockets are disconnected */ + RTR_MGR_CLOSED, + + /* RTR sockets trying to establish a connection. */ + RTR_MGR_CONNECTING, + + /* All RTR sockets of the group are synchronized with the rtr servers. */ + RTR_MGR_ESTABLISHED, + + /* Error occured on at least one RTR socket. */ + RTR_MGR_ERROR, +}; + struct rpki_cache_ssh_cfg { char *bird_private_key; /* Filepath to the BIRD server private key */ char *cache_public_key; /* Filepath to the public key of cache server, can be file known_hosts */ @@ -51,6 +74,7 @@ struct rpki_cache { node n; struct rpki_proto *p; struct rpki_cache_cfg *cfg; + struct rpki_cache_group *group; struct rtr_socket *rtr_socket; /* RTRlib's socket data structure */ sock *sk; /* BIRD's socket data structure */ timer *retry_timer; /* Timer for Cache server */ @@ -63,7 +87,7 @@ struct rpki_cache_group { node n; u8 preference; /* Preference: the most prioritized are the lowest numbers and starts with 1 */ list cache_list; /* List of cache servers (struct rpki_cache) * */ - u8 state; /* RPKI_CACHE_GROUP_STATE_* */ + enum rtr_mgr_status status; }; struct rpki_config { @@ -84,6 +108,8 @@ void rpki_init_all(void); void rpki_close_connection(struct rpki_cache *cache); int rpki_open_connection(struct rpki_cache *cache); const char *get_cache_ident(struct rpki_cache *cache); +void rpki_relax_groups(struct rpki_proto *p); +void debug_print_groups(struct rpki_proto *p); #define RPKI_LOG(log_level, rpki, msg, args...) \ do { \ @@ -102,23 +128,15 @@ const char *get_cache_ident(struct rpki_cache *cache); #define RPKI_TRACE(level,rpki,msg,args...) \ do { \ if ((rpki)->p.debug & level) \ - RPKI_LOG(L_TRACE, rpki, msg, ## args); \ + RPKI_LOG(L_TRACE, rpki, msg, ## args); \ } while(0) #define CACHE_TRACE(level,cache,msg,args...) \ do { \ if ((cache)->p->p.debug & level) \ - RPKI_LOG(L_TRACE, (cache)->p, "%s: " msg, get_cache_ident(cache), ## args); \ + RPKI_LOG(L_TRACE, (cache)->p, "%s: " msg, get_cache_ident(cache), ## args); \ } while(0) #define RPKI_WARN(p, msg, args...) RPKI_LOG(L_WARN, p, msg, ## args); -#define RPKI_ERROR(p, msg, args...) RPKI_LOG(L_ERR, p, msg, ## args); - -#define RPKI_DIE(p, msg, args...) \ - do { \ - RPKI_LOG(L_FATAL, p, msg, ## args); \ - exit(1); \ - } while(0) - #endif /* _BIRD_RPKI_H_ */ diff --git a/proto/rpki/rtr.c b/proto/rpki/rtr.c index da84a9ce..e3e5c228 100644 --- a/proto/rpki/rtr.c +++ b/proto/rpki/rtr.c @@ -91,6 +91,24 @@ rtr_state_to_str(enum rtr_socket_state state) return rtr_socket_str_states[state]; } +/* + * Set group status to @mgr_status if all sockets of caches in the @group are @socket_state + */ +static void +set_group_status_to_if_all_sockets_are(struct rpki_cache_group *group, const enum rtr_mgr_status mgr_status, const enum rtr_socket_state socket_state) +{ + bool do_all_sockets_pass = true; + + struct rpki_cache *cache; + WALK_LIST(cache, group->cache_list) + { + if (cache->rtr_socket->state != socket_state) + do_all_sockets_pass = false; + } + if (do_all_sockets_pass) + group->status = mgr_status; +} + void rtr_change_socket_state(struct rtr_socket *rtr_socket, const enum rtr_socket_state new_state) { @@ -107,6 +125,9 @@ rtr_change_socket_state(struct rtr_socket *rtr_socket, const enum rtr_socket_sta switch (new_state) { case RTR_CONNECTING: + if (old_state == RTR_SHUTDOWN) + cache->group->status = RTR_MGR_CONNECTING; + if (cache->sk == NULL || cache->sk->fd < 0) { if (rpki_open_connection(cache) == TR_SUCCESS) @@ -117,7 +138,9 @@ rtr_change_socket_state(struct rtr_socket *rtr_socket, const enum rtr_socket_sta break; case RTR_ESTABLISHED: - /* Connection is established, socket is waiting for a Serial Notify or expiration of the refresh_interval timer */ + /* set status of group to RTR_MGR_ESTABLISHED if all caches in the common group are RTR_ESTABLISHED */ + set_group_status_to_if_all_sockets_are(cache->group, RTR_MGR_ESTABLISHED, RTR_ESTABLISHED); + rpki_relax_groups(cache->p); break; case RTR_RESET: @@ -165,6 +188,8 @@ rtr_change_socket_state(struct rtr_socket *rtr_socket, const enum rtr_socket_sta /* Error on the transport socket occurred. */ rpki_close_connection(cache); rtr_schedule_next_retry(cache); + cache->group->status = RTR_MGR_ERROR; + rpki_relax_groups(cache->p); break; case RTR_FAST_RECONNECT: @@ -180,6 +205,10 @@ rtr_change_socket_state(struct rtr_socket *rtr_socket, const enum rtr_socket_sta rtr_socket->serial_number = 0; rtr_socket->last_update = 0; pfx_table_src_remove(cache); + + /* set status of group to RTR_MGR_CLOSED if all caches in the common group are RTR_SHUTDOWN */ + set_group_status_to_if_all_sockets_are(cache->group, RTR_MGR_CLOSED, RTR_SHUTDOWN); + rpki_relax_groups(cache->p); break; }; } @@ -284,6 +313,7 @@ rpki_retry_hook(struct timer *tm) default: CACHE_DBG(cache, "Retry Connecting (%s)", rtr_socket_str_states[rtr_socket->state]); rtr_change_socket_state(rtr_socket, RTR_CONNECTING); + debug_print_groups(p); break; } } diff --git a/proto/rpki/rtr.h b/proto/rpki/rtr.h index ab308686..6550068e 100644 --- a/proto/rpki/rtr.h +++ b/proto/rpki/rtr.h @@ -8,13 +8,6 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ -/** - * @defgroup mod_rtr_h RTR socket - * @brief An RTR socket implements the RPKI-RTR protocol scheme. - * @details One rtr_socket communicates with a single RPKI-RTR server. - * @{ - */ - #ifndef RTR_H #define RTR_H #include diff --git a/proto/rpki/ssh_transport.c b/proto/rpki/ssh_transport.c index 06355c8d..f8b3a130 100644 --- a/proto/rpki/ssh_transport.c +++ b/proto/rpki/ssh_transport.c @@ -34,7 +34,7 @@ int tr_ssh_open(void *socket) const char *err_msg; if((err_msg = load_libssh()) != NULL) { - RPKI_ERROR(p, "%s", err_msg); + CACHE_TRACE(D_EVENTS, cache, "%s", err_msg); return TR_ERROR; } diff --git a/proto/rpki/tcp_transport.c b/proto/rpki/tcp_transport.c index 96308118..a73c93cf 100644 --- a/proto/rpki/tcp_transport.c +++ b/proto/rpki/tcp_transport.c @@ -106,7 +106,8 @@ const char *tr_tcp_ident(void *socket) static int fulfill_ip_addr(struct tr_tcp_socket *tcp_socket) { - struct rpki_proto *p = tcp_socket->cache->p; + struct rpki_cache *cache = tcp_socket->cache; + struct rpki_proto *p = cache->p; struct addrinfo hints; struct addrinfo *res; @@ -122,7 +123,7 @@ fulfill_ip_addr(struct tr_tcp_socket *tcp_socket) if (getaddrinfo(tcp_socket->config.host, port_buf, &hints, &res) != 0) { - RPKI_ERROR(p, "getaddrinfo error, %s", tcp_socket, gai_strerror(errno)); + CACHE_TRACE(D_EVENTS, cache, "getaddrinfo error, %s", gai_strerror(errno)); return TR_ERROR; }