]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
RPKI: Add the basis for manager
authorPavel Tvrdík <pawel.tvrdik@gmail.com>
Wed, 6 Jan 2016 14:55:29 +0000 (15:55 +0100)
committerPavel Tvrdík <pawel.tvrdik@gmail.com>
Wed, 6 Jan 2016 15:04:48 +0000 (16:04 +0100)
proto/rpki/rpki.c
proto/rpki/rpki.h
proto/rpki/rtr.c
proto/rpki/rtr.h
proto/rpki/ssh_transport.c
proto/rpki/tcp_transport.c

index 2f82c8fbc635a70ea48e111782d417c5dcb80b0e..e358a2197b0f10c3daba9d7680c3ce92a0b5a16b 100644 (file)
 
 #include <stdlib.h>
 #include <assert.h>
+#include <stdbool.h>
 #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;
 }
index 70669bd6fefdfdbd9951b2d52f4c180b2f584d4d..e783c55a4b8e3147eb35db7d61d74717aa832b43 100644 (file)
 #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_ */
index da84a9ce3ba0f741dd83f6273cb1314e450b70e9..e3e5c22820ec0f510f4b04ee753549de70c281b1 100644 (file)
@@ -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;
   }
 }
index ab308686ebc6591fb71b7a9b2c692c2600cb5400..6550068ef7c4098f3e39e45f3b872a538be6141b 100644 (file)
@@ -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 <time.h>
index 06355c8d5dcc92468e05af4a6c90c518dd4b72ec..f8b3a1308011de5fbcb3dd055c74e14f05571322 100644 (file)
@@ -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;
   }
 
index 96308118f701a7acaf72e0d0755f547df205be05..a73c93cf80aef6d5c60ab17c1dc1fc841170f13b 100644 (file)
@@ -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;
   }