]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
RPKI: load RTRLib dynamically with dlopen()
authorPavel Tvrdík <pawel.tvrdik@gmail.cz>
Mon, 5 Oct 2015 14:25:48 +0000 (16:25 +0200)
committerPavel Tvrdík <pawel.tvrdik@gmail.cz>
Mon, 5 Oct 2015 14:52:15 +0000 (16:52 +0200)
In configuration bird.conf you can specify a path to the RTRlib:

  protocol rpki {
    rtrlib "/usr/lib/librtr.so";
    ...
  }

proto/rpki/config.Y
proto/rpki/rpki.c
proto/rpki/rpki.h
proto/rpki/rtrlib-mockup.h [new file with mode: 0644]
tools/Makefile-top.in
tools/Makefile.in
tools/Rules.in

index 384cc1995bbb263c582ef352ae6c7fa22d4df52a..757a94f6c15f4a5cd48561eb0adb80fc946e8697 100644 (file)
@@ -18,7 +18,7 @@ static struct rpki_cache *this_rpki_cache;
 
 CF_DECLS
 
-CF_KEYWORDS(RPKI, CACHE, LIST, PREFERENCE)
+CF_KEYWORDS(RPKI, CACHE, LIST, PREFERENCE, RTRLIB)
 
 CF_GRAMMAR
 
@@ -37,6 +37,7 @@ rpki_proto_start:
    proto_start RPKI {
      this_proto = proto_config_new(&proto_rpki, $1);
      init_list(&RPKI_CFG->cache_list);
+     RPKI_CFG->rtrlib_path = RPKI_RTRLIB_PATH;
    }
  ;
 
@@ -49,6 +50,7 @@ rpki_proto_item:
    proto_item
  | CACHE LIST '{' rpki_cache_list '}'
  | ROA TABLE roa_table_cf { RPKI_CFG->roa_table_cf = $3; }
+ | RTRLIB text { RPKI_CFG->rtrlib_path = $2; }
  ;
 
 rpki_cache_list:
index 57445ef00e6fb06d887977379c8575a895ed48f9..cef80d7bce008b1c34c43766188a2d291286d24d 100644 (file)
@@ -15,6 +15,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <pthread.h>
+#include <dlfcn.h>
 
 #include "proto/rpki/rpki.h"
 #include "lib/socket.h"
@@ -25,8 +26,8 @@ struct rpki_entry {
   node n;
   u32 asn;
   ip_addr ip;
-  u8 min_len;
-  u8 max_len;
+  u8 pxlen;
+  u8 maxlen;
   u8 added;
   struct rpki_proto *rpki;
 };
@@ -36,10 +37,93 @@ void pipe_kick(int fd);     /* implementation in io.c */
 
 static list rpki_proto_list;
 
+static void *rtrlib;
+static struct rtr_mgr_config * (*rtr_mgr_init_fp)(
+    struct rtr_mgr_group groups[], const unsigned int groups_len,
+    const unsigned int refresh_interval, const unsigned int expire_interval,
+    const void *update_fp,
+    const void *spki_update_fp,
+    const void *status_fp,
+    void *status_fp_data);
+static int (*rtr_mgr_start_fp)(struct rtr_mgr_config *config);
+static const char * (*rtr_state_to_str_fp)(enum rtr_socket_state state);
+static const char * (*rtr_mgr_status_to_str_fp)(enum rtr_mgr_status status);
+static int (*tr_tcp_init_fp)(const struct tr_tcp_config *config, struct tr_socket *socket);
+static void (*rtr_mgr_stop_fp)(struct rtr_mgr_config *config);
+static void (*rtr_mgr_free_fp)(struct rtr_mgr_config *config);
+
+static int
+was_dlsym_ok(struct rpki_proto *p)
+{
+  char *err_buffer = dlerror();
+
+  if (err_buffer != NULL)
+  {
+    RPKI_ERROR(p, "%s. Try the latest version of RTRLib.", err_buffer);
+    return 0; /* FAIL */
+  }
+  return 1; /* OK */
+}
+
+static int
+load_rtrlib(struct rpki_proto *p)
+{
+  rtrlib = dlopen(p->cf->rtrlib_path, RTLD_LAZY);
+  if (!rtrlib)
+  {
+    RPKI_ERROR(p, "dlopen(): %s. Try specify path to the shared RTRLib (http://rpki.realmv6.org/) with 'rtrlib' option"
+                 "inside of the rpki protocol configuration", dlerror());
+    return 0; /* FAIL */
+  }
+  else
+  {
+    RPKI_TRACE(p, "Loaded RTRLib from %s", p->cf->rtrlib_path);
+  }
+
+  dlerror();    /* Clear any existing error */
+
+  rtr_mgr_init_fp = (struct rtr_mgr_config * (*)(
+      struct rtr_mgr_group groups[], const unsigned int groups_len,
+      const unsigned int refresh_interval, const unsigned int expire_interval,
+      const void *update_fp,
+      const void *spki_update_fp,
+      const void *status_fp,
+      void *status_fp_data)) dlsym(rtrlib, "rtr_mgr_init");
+  if (!was_dlsym_ok(p))
+    return 0; /* FAIL */
+
+  rtr_mgr_start_fp = (int (*)(struct rtr_mgr_config *)) dlsym(rtrlib, "rtr_mgr_start");
+  if (!was_dlsym_ok(p))
+    return 0; /* FAIL */
+
+  rtr_state_to_str_fp = (const char * (*)(enum rtr_socket_state state)) dlsym(rtrlib, "rtr_state_to_str");
+  if (!was_dlsym_ok(p))
+    return 0; /* FAIL */
+
+  rtr_mgr_status_to_str_fp = (const char * (*)(enum rtr_mgr_status status)) dlsym(rtrlib, "rtr_mgr_status_to_str");
+  if (!was_dlsym_ok(p))
+    return 0; /* FAIL */
+
+  tr_tcp_init_fp = (int (*)(const struct tr_tcp_config *config, struct tr_socket *socket)) dlsym(rtrlib, "tr_tcp_init");
+  if (!was_dlsym_ok(p))
+    return 0; /* FAIL */
+
+  rtr_mgr_stop_fp = (void (*)(struct rtr_mgr_config *config)) dlsym(rtrlib, "rtr_mgr_stop");
+  if (!was_dlsym_ok(p))
+    return 0; /* FAIL */
+
+  rtr_mgr_free_fp = (void (*)(struct rtr_mgr_config *config)) dlsym(rtrlib, "rtr_mgr_free");
+  if (!was_dlsym_ok(p))
+    return 0; /* FAIL */
+
+  return 1; /* OK */
+}
+
 void
 rpki_init_all(void)
 {
   init_list(&rpki_proto_list);
+  rtrlib = NULL;
 }
 
 static void
@@ -53,7 +137,7 @@ status_cb(const struct rtr_mgr_group *group, enum rtr_mgr_status status, const s
   }
   else
   {
-    RPKI_TRACE(p, "status: %s\t%s", rtr_mgr_status_to_str(status), rtr_state_to_str(socket->state));
+    RPKI_TRACE(p, "status: %s\t%s", (*rtr_mgr_status_to_str_fp)(status), (*rtr_state_to_str_fp)(socket->state));
   }
 }
 
@@ -85,15 +169,19 @@ log_skip_entry(struct rpki_proto *p, const struct pfx_record *rec, const bool ad
     ip6_ntop(ip6, ip_buf);
   }
 
-#define LOG_SKIP_ENTRY_FMT(operation_name) "skip unsupported IP version: " operation_name " %25s/%u-%-3u \tASN: %10u"
+#define RPKI_LOG_ADD "add"
+#define RPKI_LOG_DEL "del"
+#define RPKI_LOG_ENTRY_FMT(ip_fmt) " roa %-25" ip_fmt "/%u-%-3u ASN: %u"
+#define RPKI_LOG_FMT(operation_name)              operation_name RPKI_LOG_ENTRY_FMT("I")
+#define RPKI_LOG_SKIP_FMT(operation_name) "skip " operation_name RPKI_LOG_ENTRY_FMT("s") " (unsupported IP version)"
 
   if (added)
   {
-    RPKI_TRACE(p, LOG_SKIP_ENTRY_FMT("add"), ip_buf, rec->min_len, rec->max_len, rec->asn);
+    RPKI_TRACE(p, RPKI_LOG_SKIP_FMT(RPKI_LOG_ADD), ip_buf, rec->min_len, rec->max_len, rec->asn);
   }
   else
   {
-    RPKI_TRACE(p, LOG_SKIP_ENTRY_FMT("del"), ip_buf, rec->min_len, rec->max_len, rec->asn);
+    RPKI_TRACE(p, RPKI_LOG_SKIP_FMT(RPKI_LOG_DEL), ip_buf, rec->min_len, rec->max_len, rec->asn);
   }
 }
 
@@ -150,10 +238,19 @@ rtr_thread_update_hook(struct pfx_table *pfx_table, const struct pfx_record rec,
   e->added = added;
   e->asn = rec.asn;
   e->ip = ip;
-  e->max_len = rec.max_len;
-  e->min_len = rec.min_len;
+  e->pxlen = rec.min_len;
+  e->maxlen = rec.max_len;
   e->rpki = p;
 
+  if (e->added)
+  {
+    RPKI_TRACE(p, RPKI_LOG_FMT(RPKI_LOG_ADD), e->ip, e->pxlen, e->maxlen, e->asn);
+  }
+  else
+  {
+    RPKI_TRACE(p, RPKI_LOG_FMT(RPKI_LOG_DEL), e->ip, e->pxlen, e->maxlen, e->asn);
+  }
+
   send_data_to_main_thread(p, e);
 }
 
@@ -206,9 +303,9 @@ rpki_notify_hook(struct birdsock *sk, int size)
   {
     rem2_node(&entry->n);
     if (entry->added)
-      roa_add_item(p->cf->roa_table_cf->table, entry->ip, entry->min_len, entry->max_len, entry->asn, ROA_SRC_RPKI);
+      roa_add_item(p->cf->roa_table_cf->table, entry->ip, entry->pxlen, entry->maxlen, entry->asn, ROA_SRC_RPKI);
     else
-      roa_delete_item(p->cf->roa_table_cf->table, entry->ip, entry->min_len, entry->max_len, entry->asn, ROA_SRC_RPKI);
+      roa_delete_item(p->cf->roa_table_cf->table, entry->ip, entry->pxlen, entry->maxlen, entry->asn, ROA_SRC_RPKI);
   }
   rpki_unlock_sessions(p);
 }
@@ -268,6 +365,9 @@ rpki_start(struct proto *P)
 
   RPKI_TRACE(p, "------------- rpki_start -------------");
 
+  if (!rtrlib && !load_rtrlib(p))
+    return PS_DOWN;
+
   create_rw_sockets(p);
   init_list(&p->notify_list);
   pthread_spin_init(&p->notify_lock, PTHREAD_PROCESS_PRIVATE);
@@ -296,7 +396,7 @@ rpki_start(struct proto *P)
 
     tcp_config->host = cache->full_domain_name;
     tcp_config->port = cache->port;
-    tr_tcp_init(tcp_config, tr_tcp);
+    (*tr_tcp_init_fp)(tcp_config, tr_tcp);
 
     // create an rtr_socket and associate it with the transport socket
     rtr_tcp->tr_socket = tr_tcp;
@@ -306,8 +406,8 @@ rpki_start(struct proto *P)
     idx++;
   }
 
-  p->rtr_conf = rtr_mgr_init(groups, 1, 30, 520, &rtr_thread_update_hook, NULL, &status_cb, p);
-  rtr_mgr_start(p->rtr_conf);
+  p->rtr_conf = (*rtr_mgr_init_fp)(groups, 1, 30, 520, &rtr_thread_update_hook, NULL, &status_cb, p);
+  (*rtr_mgr_start_fp)(p->rtr_conf);
 
   return PS_UP;
 }
@@ -317,8 +417,8 @@ rpki_shutdown(struct proto *P)
 {
   struct rpki_proto *p = (struct rpki_proto *) P;
 
-  rtr_mgr_stop(p->rtr_conf);
-  rtr_mgr_free(p->rtr_conf);
+  (*rtr_mgr_stop_fp)(p->rtr_conf);
+  (*rtr_mgr_free_fp)(p->rtr_conf);
   mb_free(p->rtr_groups);
   mb_free(p->rtr_sockets);
 
index a0957180558943ddf45374b413a403152c798b96..e5da7acd2753e76cbf3a6c3d07521e45e57ebe5b 100644 (file)
 
 #include <pthread.h>
 
-#include "rtrlib/rtrlib.h"
-
 #include "nest/bird.h"
 #include "nest/protocol.h"
 #include "lib/socket.h"
+#include "proto/rpki/rtrlib-mockup.h"
+
 
 #define RPKI_PORT "8282"
 #define RPKI_PORT_MAX_LENGTH_STR 6
 #define RPKI_RX_BUFFER_EXT_SIZE 0xffff
 #define RPKI_TX_BUFFER_EXT_SIZE 0xffff
+#define RPKI_RTRLIB_PATH "/usr/local/lib64/librtr.so"
 
 #define RPKI_LOG(log_level, p, msg, args...)                           \
   do {                                                                         \
@@ -60,6 +61,7 @@ struct rpki_config {
   struct proto_config c;
   list cache_list;     /* (struct rpki_cache *) */
   struct roa_table_config *roa_table_cf;
+  const char *rtrlib_path;
 };
 
 struct rpki_proto {
diff --git a/proto/rpki/rtrlib-mockup.h b/proto/rpki/rtrlib-mockup.h
new file mode 100644 (file)
index 0000000..160d3e5
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ *     BIRD -- RTRLib Headers mockup
+ *
+ *     (c) 2015 CZ.NIC
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ *
+ *
+ * RTRlib is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * RTRlib is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with RTRlib; see the file COPYING.LESSER.
+ *
+ * INET group, Hamburg University of Applied Sciences,
+ * CST group, Freie Universitaet Berlin
+ * Website: http://rpki.realmv6.org/
+ *
+ */
+
+#ifndef _BIRD_RTRLIB_MOCKUP_H_
+#define _BIRD_RTRLIB_MOCKUP_H_
+
+#include <stdbool.h>
+
+/**
+ * @brief A transport socket datastructure.
+ *
+ * @param socket A pointer to a technology specific socket.
+ * @param open_fp Pointer to a function that establishes the socket connection.
+ * @param close_fp Pointer to a function that closes the socket.
+ * @param free_fp Pointer to a function that frees all memory allocated with this socket.
+ * @param send_fp Pointer to a function that sends data through this socket.
+ * @param recv_fp Pointer to a function that receives data from this socket.
+ */
+struct tr_socket {
+    void *socket;
+    void *open_fp;     /* voided for mockuping */
+    void *close_fp;    /* voided for mockuping */
+    void *free_fp;     /* voided for mockuping */
+    void *send_fp;     /* voided for mockuping */
+    void *recv_fp;     /* voided for mockuping */
+    void *ident_fp;    /* voided for mockuping */
+};
+
+/**
+ * @brief States of the RTR socket.
+ */
+enum rtr_socket_state {
+    /** Socket is establishing the transport connection. */
+    RTR_CONNECTING,
+
+    /** Connection is established, socket is waiting for a Serial Notify or expiration of the refresh_interval timer */
+    RTR_ESTABLISHED,
+
+    /** Resetting RTR connection. */
+    RTR_RESET,
+
+    /** Receiving validation records from the RTR server.  */
+    RTR_SYNC,
+
+    /** Reconnect without any waiting period */
+    RTR_FAST_RECONNECT,
+
+    /** No validation records are available on the RTR server. */
+    RTR_ERROR_NO_DATA_AVAIL,
+
+    /** Server was unable to answer the last serial or reset query. */
+    RTR_ERROR_NO_INCR_UPDATE_AVAIL,
+
+    /** Fatal protocol error occurred. */
+    RTR_ERROR_FATAL,
+
+    /** Error on the transport socket occurred. */
+    RTR_ERROR_TRANSPORT,
+
+    /** RTR Socket is stopped. */
+    RTR_SHUTDOWN,
+};
+
+/**
+ * @brief A RTR socket.
+ * @param tr_socket Pointer to an initialized tr_socket that will be used to communicate with the RTR server.
+ * @param refresh_interval Time period in seconds. Tells the router how long to wait before next attempting to poll the cache, using a Serial Query or
+ * Reset Query PDU.
+ * @param last_update Timestamp of the last validation record update. Is 0 if the pfx_table doesn't stores any
+ * validation reords from this rtr_socket.
+ * @param expire_interval Time period in seconds. Received records are deleted if the client was unable to refresh data for this time period.
+ * If 0 is specified, the expire_interval is twice the refresh_interval.
+ * @param retry_interval Time period in seconds between a faild quary and the next attempt.
+ * @param state Current state of the socket.
+ * @param session_id session_id of the RTR session.
+ * @param request_session_id True, if the rtr_client have to request a new none from the server.
+ * @param serial_number Last serial number of the obtained validation records.
+ * @param pfx_table pfx_table that stores the validation records obtained from the connected rtr server.
+ * @param connection_state_fp A callback function that is executed when the state of the socket changes.
+ * @param connection_state_fp_param Parameter that is passed to the connection_state_fp callback.
+ */
+struct rtr_socket {
+  struct tr_socket *tr_socket;
+  unsigned int refresh_interval;
+  time_t last_update;
+  unsigned int expire_interval;
+  unsigned int retry_interval;
+  enum rtr_socket_state state;
+  uint32_t session_id;
+  bool request_session_id;
+  uint32_t serial_number;
+  void *pfx_table;                             /* voided for mockuping */
+  pthread_t thread_id;
+  void *connection_state_fp;                   /* voided for mockuping */
+  void *connection_state_fp_param;
+  unsigned int version;
+  void *spki_table;                            /* voided for mockuping */
+};
+
+/**
+ * @brief  A tr_tcp_config struct holds configuration for a TCP connection.
+ * @param host Hostname or IP address to connect to.
+ * @param port Port to connect to.
+ * @param bindaddr Hostname or IP address to connect from. NULL for
+ *                determination by OS.
+ * to use the source address of the system's default route to the server
+ */
+struct tr_tcp_config {
+    char *host;
+    char *port;
+    char *bindaddr;
+};
+
+/**
+ * @brief Status of a rtr_mgr_group.
+ */
+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,
+};
+
+/**
+ * @brief A set of RTR sockets.
+ * @param sockets Array of rtr_socket pointer. The tr_socket element of the rtr_socket must be associated with an initialized transport socket.
+ * @param sockets_len Number of elements in the sockets array.
+ * @param preference The preference value of this group. Groups with lower preference values are preferred.
+ * @param status Status of the group.
+ */
+struct rtr_mgr_group {
+    struct rtr_socket **sockets;
+    unsigned int sockets_len;
+    uint8_t preference;
+    enum rtr_mgr_status status;
+};
+
+struct rtr_mgr_config {
+    struct rtr_mgr_group *groups;
+    unsigned int len;
+    /* some items deleted */
+};
+
+
+/**
+ * @brief Version of the IP protocol.
+ */
+enum rtr_ip_version {
+    RTRLIB_IPV4,
+    RTRLIB_IPV6
+};
+
+/**
+ * @brief Struct storing an IPv4 address in host byte order.
+ * @param addr The IPv4 address.
+ */
+struct ipv4_addr {
+    uint32_t addr;
+};
+
+/**
+ * @brief Struct holding an IPv6 address in host byte order.
+ * @param addr The IPv6 address.
+ */
+struct ipv6_addr {
+    uint32_t addr[4];
+};
+
+/**
+ * @brief The rtr_ip_addr struct stores a IPv4 or IPv6 address in host byte order.
+ * @param ver Specifies the type of the stored address.
+ * @param u Union holding a ipv4_addr or ipv6_addr.
+ */
+struct rtr_ip_addr {
+    enum rtr_ip_version ver;
+    union {
+        struct ipv4_addr addr4;
+        struct ipv6_addr addr6;
+    } u;
+};
+
+/**
+ * @brief pfx_record.
+ * @param asn Origin AS number.
+ * @param prefix IP prefix.
+ * @param min_len Minimum prefix length.
+ * @param max_len Maximum prefix length.
+ * @param socket_id unique id of the rtr_socket that received this record.
+ */
+struct pfx_record {
+    uint32_t asn;
+    struct rtr_ip_addr prefix;
+    uint8_t min_len;
+    uint8_t max_len;
+    const struct rtr_socket *socket;
+};
+
+#endif /* _BIRD_RTRLIB_MOCKUP_H_ */
index 0244a5630835535f80caa94fe71a662bf95bcc7b..cf59f7a1742717f5d3a70e4291f7a23be6513528 100644 (file)
@@ -4,7 +4,6 @@
 objdir=@objdir@
 
 all depend tags install install-docs:
-       $(MAKE) -C rtrlib
        $(MAKE) -C $(objdir) $@
 
 docs userdocs progdocs:
index f19aceb24f382516b10c3a416ca538812409df78..01bb7a7c1459bbbf12ba670baaf1af8e3c5cf956 100644 (file)
@@ -13,7 +13,7 @@ birdc: $(exedir)/birdc
 
 birdcl: $(exedir)/birdcl
 
-bird-dep := $(addsuffix /all.o, $(static-dirs)) conf/all.o lib/birdlib.a ../rtrlib/librtr.a
+bird-dep := $(addsuffix /all.o, $(static-dirs)) conf/all.o lib/birdlib.a
 
 $(bird-dep): sysdep/paths.h .dep-stamp subdir
 
index ea05b287a558417230c09415c649530fd39eaf0b..f00c85d1e95bcf2acb8289e3b693a1193f25b421 100644 (file)
@@ -19,7 +19,7 @@ doc-dir-paths := $(doc-dirs)
 all-dirs:=$(static-dirs) $(dynamic-dirs) $(client-dirs) $(doc-dirs)
 clean-dirs:=$(all-dirs) proto sysdep
 
-CPPFLAGS=-I$(root-rel) -I$(srcdir) -I$(srcdir)/rtrlib @CPPFLAGS@
+CPPFLAGS=-I$(root-rel) -I$(srcdir) @CPPFLAGS@
 CFLAGS=$(CPPFLAGS) @CFLAGS@
 LDFLAGS=@LDFLAGS@
 LIBS=@LIBS@