]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Add core support for MRT Table Dump (RFC 6396)
authorPavel Tvrdík <pawel.tvrdik@gmail.cz>
Tue, 19 May 2015 08:47:14 +0000 (10:47 +0200)
committerPavel Tvrdík <pawel.tvrdik@gmail.cz>
Tue, 28 Jul 2015 13:04:03 +0000 (15:04 +0200)
lib/ip.c
lib/ip.h
lib/ip_test.c
nest/mrtdump.c [new file with mode: 0644]
nest/mrtdump.h
nest/mrtdump_test.c [new file with mode: 0644]
nest/route.h
nest/rt-fib.c
sysdep/unix/log.c
test/birdtest_support.h

index 70f337832060b229135c9b0c5c3e38892db8ceac..87af52292e13d1945026feda1cb51c775a5b8c30 100644 (file)
--- a/lib/ip.c
+++ b/lib/ip.c
@@ -233,7 +233,7 @@ ip6_ntop(ip6_addr a, char *b)
 }
 
 int
-ip4_pton(char *a, ip4_addr *o)
+ip4_pton(const char *a, ip4_addr *o)
 {
   int i;
   unsigned long int l;
@@ -258,11 +258,11 @@ ip4_pton(char *a, ip4_addr *o)
 }
 
 int
-ip6_pton(char *a, ip6_addr *o)
+ip6_pton(const char *a, ip6_addr *o)
 {
   u16 words[8];
   int i, j, k, l, hfil;
-  char *start;
+  const char *start;
 
   if (a[0] == ':')                     /* Leading :: */
   {
index 90bb7f8acf4148fed7069e533fea588d5fe4b282..e33adc6e62032018dc800af579e2e5a2c593c539 100644 (file)
--- a/lib/ip.h
+++ b/lib/ip.h
@@ -446,8 +446,8 @@ static inline char * ip4_ntox(ip4_addr a, char *b)
 static inline char * ip6_ntox(ip6_addr a, char *b)
 { return b + bsprintf(b, "%08x.%08x.%08x.%08x", _I0(a), _I1(a), _I2(a), _I3(a)); }
 
-int ip4_pton(char *a, ip4_addr *o);
-int ip6_pton(char *a, ip6_addr *o);
+int ip4_pton(const char *a, ip4_addr *o);
+int ip6_pton(const char *a, ip6_addr *o);
 
 // XXXX these functions must be redesigned or removed
 #ifdef IPV6
index 149fc048fd84ccc884e2f4e67f7fc53760e3a385..e64a876434b75c143a2e985f98baca9a3fd61b32 100644 (file)
@@ -20,10 +20,10 @@ build_ip4(u8 a, u8 b, u8 c, u8 d)
 }
 
 static u32
-ip4_pton_(char *s)
+ip4_pton_(const char *s)
 {
   ip4_addr ip;
-  ip4_pton(s,&ip);
+  ip4_pton(s, &ip);
   return ip.addr;
 }
 
@@ -54,7 +54,7 @@ t_ip4_pton(void)
 }
 
 static void
-ip6_pton_(char *s, u32 (*addr)[4])
+ip6_pton_(const char *s, u32 (*addr)[4])
 {
   static ip6_addr ip;
   ip6_pton(s, &ip);
diff --git a/nest/mrtdump.c b/nest/mrtdump.c
new file mode 100644 (file)
index 0000000..0c79ba7
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *     BIRD -- Multi-Threaded Routing Toolkit (MRT) Routing Information Export Format
+ *
+ *     (c) 2015 CZ.NIC z.s.p.o.
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "nest/mrtdump.h"
+
+void
+mrt_msg_init(struct mrt_msg *msg, pool *mem_pool)
+{
+  msg->mem_pool = mem_pool;
+  msg->msg_capacity = MRT_MSG_DEFAULT_CAPACITY;
+  msg->msg_length = 0;
+  msg->msg = mb_alloc(msg->mem_pool, msg->msg_capacity);
+}
+
+void
+mrt_msg_free(struct mrt_msg *msg)
+{
+  mb_free(msg->msg);
+}
+
+static byte *
+mrt_peer_index_table_get_peer_count(struct mrt_peer_index_table *pit_msg)
+{
+  struct mrt_msg * msg = pit_msg->msg;
+  uint collector_bgp_id_size = 4;
+  uint name_length_size = 2;
+  uint name_size = pit_msg->name_length;
+  uint peer_count_offset = collector_bgp_id_size + name_length_size + name_size;
+  return &(msg->msg[peer_count_offset]);
+}
+
+static void
+mrt_grow_msg_buffer(struct mrt_msg * msg, size_t min_required_capacity)
+{
+  msg->msg_capacity *= 2;
+  if (min_required_capacity > msg->msg_capacity)
+    msg->msg_capacity = min_required_capacity;
+  msg->msg = mb_realloc(msg->msg, msg->msg_capacity);
+}
+
+static void
+mrt_write_to_msg(struct mrt_msg * msg, const void *data, size_t data_size)
+{
+  if (data_size == 0)
+    return;
+
+  u32 i;
+  for (i = 0; i < data_size; i++)
+    debug("%02X ", ((byte*)data)[i]);
+  debug("| ");
+
+  size_t required_size = data_size + msg->msg_length;
+  if (msg->msg_capacity < required_size)
+    mrt_grow_msg_buffer(msg, required_size);
+
+  memcpy(&msg->msg[msg->msg_length], data, data_size);
+  msg->msg_length += data_size;
+}
+#define mrt_write_to_msg_(msg, data) mrt_write_to_msg(msg, &data, sizeof(data))
+
+void
+mrt_peer_index_table_init(struct mrt_peer_index_table *pit_msg, u32 collector_bgp_id, const char *name)
+{
+  struct mrt_msg * msg = pit_msg->msg;
+  pit_msg->peer_count = 0;
+  pit_msg->name_length = strlen(name);
+
+  mrt_write_to_msg_(msg, collector_bgp_id);
+  mrt_write_to_msg_(msg, pit_msg->name_length);
+  mrt_write_to_msg(msg, name, pit_msg->name_length);
+  mrt_write_to_msg_(msg, pit_msg->peer_count);
+  debug("\n");
+}
+
+static void
+mrt_peer_index_table_inc_peer_count(struct mrt_peer_index_table *pit_msg)
+{
+  pit_msg->peer_count++;
+  byte *peer_count = mrt_peer_index_table_get_peer_count(pit_msg);
+  put_u16(peer_count, pit_msg->peer_count);
+}
+
+void
+mrt_peer_index_table_add_peer(struct mrt_peer_index_table *pit_msg, u32 peer_bgp_id, ip_addr *peer_ip_addr, u32 peer_as)
+{
+  struct mrt_msg * msg = pit_msg->msg;
+
+  u8 peer_type = PEER_TYPE_AS_32BIT;
+  if (sizeof(*peer_ip_addr) > sizeof(ip4_addr))
+    peer_type |= PEER_TYPE_IPV6;
+
+  mrt_write_to_msg_(msg, peer_type);
+  mrt_write_to_msg_(msg, peer_bgp_id);
+  mrt_write_to_msg_(msg, *peer_ip_addr);
+  mrt_write_to_msg_(msg, peer_as);
+
+  mrt_peer_index_table_inc_peer_count(pit_msg);
+  debug("\n");
+}
+
+void
+mrt_rib_table_init(struct mrt_rib_table *rt_msg, u32 sequence_number, u8 prefix_length, ip_addr *prefix)
+{
+  struct mrt_msg *msg = rt_msg->msg;
+
+  rt_msg->entry_count = 0;
+
+  mrt_write_to_msg_(msg, sequence_number);
+  mrt_write_to_msg_(msg, prefix_length);
+  mrt_write_to_msg_(msg, *prefix);
+  mrt_write_to_msg_(msg, rt_msg->entry_count);
+  debug("\n");
+}
+
+static byte *
+mrt_rib_table_get_entry_count(struct mrt_rib_table *rt_msg)
+{
+  struct mrt_msg *msg = rt_msg->msg;
+  u32 sequence_number_size = 4;
+  u32 prefix_length_size = 1;
+
+  u32 prefix_size = 4;
+  if (rt_msg->type == RIB_IPV4_UNICAST)
+    prefix_size = 4;
+  else if (rt_msg->type == RIB_IPV6_UNICAST)
+    prefix_size = 16;
+  else
+    bug("mrt_rib_table_get_entry_count: unknown RIB type!");
+
+  u32 offset = sequence_number_size + prefix_length_size + prefix_size;
+  return &msg->msg[offset];
+}
+
+static void
+mrt_rib_table_inc_entry_count(struct mrt_rib_table *rt_msg)
+{
+  rt_msg->entry_count++;
+  byte *entry_count = mrt_rib_table_get_entry_count(rt_msg);
+  put_u16(entry_count, rt_msg->entry_count);
+}
+
+void
+mrt_rib_table_add_entry(struct mrt_rib_table *rt_msg, const struct mrt_rib_entry *rib)
+{
+  struct mrt_msg *msg = rt_msg->msg;
+
+  mrt_write_to_msg_(msg, rib->peer_index);
+  mrt_write_to_msg_(msg, rib->originated_time);
+  mrt_write_to_msg_(msg, rib->attributes_length);
+  mrt_write_to_msg(msg, rib->attributes, rib->attributes_length);
+
+  mrt_rib_table_inc_entry_count(rt_msg);
+  debug("\n");
+}
index 7393255379984b29171faa409fe44716b6698b47..53d1c84bd9a89d4f25f3fcfc4ca737128b8ffb20 100644 (file)
@@ -1,31 +1,90 @@
 /*
- *     BIRD -- MRTdump handling
+ *     BIRD -- Multi-Threaded Routing Toolkit (MRT) Routing Information Export Format
  *
+ *     (c) 2015 CZ.NIC z.s.p.o.
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
 
-#ifndef MRTDUMP_H
-#define MRTDUMP_H
+#ifndef _MRTDUMP_H_
+#define _MRTDUMP_H_
+
 #include "nest/protocol.h"
 
 /* MRTDump values */
-
 #define MRTDUMP_HDR_LENGTH     12
+#define PEER_TYPE_AS_32BIT     0b00000010 /* MRT TABLE_DUMP_V2: PEER_INDEX_TABLE: Peer Type: Use 32bit ASN */
+#define PEER_TYPE_IPV6         0b00000001 /* MRT TABLE_DUMP_V2: PEER_INDEX_TABLE: Peer Type: Use IPv6 IP Address */
 
-/* MRTdump types */
+/* MRT Types */
+enum mrt_type
+{
+  TABLE_DUMP_V2                = 13,
+  BGP4MP               = 16,
+};
 
-#define BGP4MP                 16
+/* MRT TABLE_DUMP_V2 Sub-Types */
+enum table_dump_v2_type
+{
+  PEER_INDEX_TABLE     = 1,
+  RIB_IPV4_UNICAST     = 2,
+  RIB_IPV4_MULTICAST   = 3,
+  RIB_IPV6_UNICAST     = 4,
+  RIB_IPV6_MULTICAST   = 5,
+  RIB_GENERIC          = 6,
+};
 
-/* MRTdump subtypes */
+/* MRT BGP4MP Sub-Types */
+enum bgp4mp_subtype
+{
+  BGP4MP_MESSAGE               = 1,
+  BGP4MP_MESSAGE_AS4           = 4,
+  BGP4MP_STATE_CHANGE_AS4      = 5,
+};
 
-#define BGP4MP_MESSAGE         1
-#define BGP4MP_MESSAGE_AS4     4
-#define BGP4MP_STATE_CHANGE_AS4        5
+struct mrt_msg
+{
+  byte  *msg;                  /* Buffer with final formatted data */
+  size_t msg_length;           /* Size of used buffer */
+  size_t msg_capacity;         /* Number of allocated bytes in msg */
+#define MRT_MSG_DEFAULT_CAPACITY 64 /* in bytes */
+  pool *mem_pool;
+};
 
+/* TABLE_DUMP_V2 -> PEER_INDEX_TABLE */
+struct mrt_peer_index_table
+{
+  struct mrt_msg *msg;
+  u16 peer_count;
+  u16 name_length;
+};
 
-/* implemented in sysdep */
-void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
+/* TABLE_DUMP_V2 -> RIB_IPV4_UNICAST or RIB_IPV6_UNICAST */
+struct mrt_rib_table
+{
+  struct mrt_msg *msg;
+  enum table_dump_v2_type type;        /* RIB_IPV4_UNICAST or RIB_IPV6_UNICAST */
+  u16 entry_count;             /* Number of RIB Entries */
+  struct bgp_proto *bgp_proto;
+};
 
-#endif
+/* TABLE_DUMP_V2 -> RIB Entry */
+struct mrt_rib_entry
+{
+  u16 peer_index;
+  u32 originated_time;
+  u16 attributes_length;
+  byte *attributes;
+};
+
+void mrt_msg_init(struct mrt_msg *msg, pool *mem_pool);
+void mrt_msg_free(struct mrt_msg *msg);
+void mrt_peer_index_table_init(struct mrt_peer_index_table *pit_msg, u32 collector_bgp_id, const char *name);
+void mrt_peer_index_table_add_peer(struct mrt_peer_index_table *pit_msg, u32 peer_bgp_id, ip_addr *peer_ip_addr, u32 peer_as);
+void mrt_rib_table_init(struct mrt_rib_table *rt_msg, u32 sequence_number, u8 prefix_length, ip_addr *prefix);
+void mrt_rib_table_add_entry(struct mrt_rib_table *rt_msg, const struct mrt_rib_entry *rib);
+
+/* implemented in sysdep */
+void mrt_dump_message(const struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
 
+#endif /* _MRTDUMP_H_ */
diff --git a/nest/mrtdump_test.c b/nest/mrtdump_test.c
new file mode 100644 (file)
index 0000000..df6ffd7
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *     BIRD -- Multi-Threaded Routing Toolkit (MRT) Routing Information Export Format Tests
+ *
+ *     (c) 2015 CZ.NIC z.s.p.o.
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/birdtest_support.h" /* REMOVE ME */
+#include "nest/mrtdump.h"
+#include "nest/mrtdump.c" /* REMOVE ME */
+
+static void
+show_mrt_msg(struct mrt_msg *msg)
+{
+  uint i;
+  bt_debug("show_mrt_msg: \n  ");
+  for(i = 0; i < msg->msg_length; i++)
+  {
+    if (i && (i % 16) == 0)
+      bt_debug("\n  ");
+    bt_debug("%02X ", msg->msg[i]);
+  }
+  bt_debug("\n");
+}
+
+static int
+t_peer_index_table(void)
+{
+  resource_init();
+
+  struct mrt_msg msg;
+  mrt_msg_init(&msg, &root_pool);
+
+  struct mrt_peer_index_table pit_msg = {
+      .msg = &msg,
+  };
+  u32 collector_bgp_id = 0x12345678;
+  const char *collector_name = "test";
+  mrt_peer_index_table_init(&pit_msg, collector_bgp_id, collector_name);
+
+  u32 i;
+  for(i = 0; i < 50; i++)
+  {
+    ip_addr addr;
+#ifdef IPV6
+    ip6_pton("1234:5678::9abc:def0", &addr);
+#else
+    ip4_pton("12.34.56.78", &addr);
+#endif
+    mrt_peer_index_table_add_peer(&pit_msg, i | 0x30303030, &addr, i | 0x08080808);
+  }
+
+  show_mrt_msg(&msg);
+
+  mrt_msg_free(&msg);
+
+  return BT_SUCCESS;
+}
+
+static int
+t_rib_table(void)
+{
+  resource_init();
+
+  struct mrt_msg msg;
+  mrt_msg_init(&msg, &root_pool);
+
+  struct mrt_rib_table rt_msg = {
+      .bgp_proto = NULL,
+      .msg = &msg,
+  };
+  u32 sequence_number = 0x12345678;
+  u8 prefix_len = 24;
+  ip_addr prefix;
+#ifdef IPV6
+  rt_msg.type = RIB_IPV6_UNICAST;
+  ip6_pton("1234:5678::9abc:def0", &prefix);
+#else
+  rt_msg.type = RIB_IPV4_UNICAST;
+  ip4_pton("12.34.56.78", &prefix);
+#endif
+  mrt_rib_table_init(&rt_msg, sequence_number, prefix_len, &prefix);
+
+  u32 i;
+
+  for(i = 0; i < 50; i++)
+  {
+    struct mrt_rib_entry entry = {
+       .peer_index =      i,
+       .originated_time = i | 0x08080808,
+       .attributes_length = 7,
+       .attributes = "abcdefg",
+    };
+    mrt_rib_table_add_entry(&rt_msg, &entry);
+  }
+
+  show_mrt_msg(&msg);
+
+  mrt_msg_free(&msg);
+
+  return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+  bt_init(argc, argv);
+
+  bt_test_suite(t_peer_index_table,    "TABLE_DUMP_V2: Peer index table");
+  bt_test_suite(t_rib_table,           "TABLE_DUMP_V2: RIB table");
+
+  return bt_end();
+}
index 3af75ad8fb958f4402e122deb9e9be086d4d3768..821f5cdb1b4fb9489f81973fb6539f12de13f940 100644 (file)
@@ -72,13 +72,13 @@ void fib_delete(struct fib *, void *);      /* Remove fib entry */
 void fib_free(struct fib *);           /* Destroy the fib */
 void fib_check(struct fib *);          /* Consistency check for debugging */
 
-void fit_init(struct fib_iterator *, struct fib *); /* Internal functions, don't call */
-struct fib_node *fit_get(struct fib *, struct fib_iterator *);
+void fit_init(struct fib_iterator *, const struct fib *); /* Internal functions, don't call */
+struct fib_node *fit_get(const struct fib *, struct fib_iterator *);
 void fit_put(struct fib_iterator *, struct fib_node *);
 
 #define FIB_WALK(fib, z) do {                                  \
        struct fib_node *z, **ff = (fib)->hash_table;           \
-       uint count = (fib)->hash_size;                  \
+       uint count = (fib)->hash_size;                          \
        while (count--)                                         \
          for(z = *ff++; z; z=z->next)
 
@@ -88,11 +88,11 @@ void fit_put(struct fib_iterator *, struct fib_node *);
 
 #define FIB_ITERATE_START(fib, it, z) do {                     \
        struct fib_node *z = fit_get(fib, it);                  \
-       uint count = (fib)->hash_size;                  \
-       uint hpos = (it)->hash;                         \
+       uint count = (fib)->hash_size;                          \
+       uint hpos = (it)->hash;                                 \
        for(;;) {                                               \
          if (!z)                                               \
-            {                                                  \
+                                                             \
               if (++hpos >= count)                             \
                 break;                                         \
               z = (fib)->hash_table[hpos];                     \
index aa5e2357f5cb684c61e9e49105521bfb5274d0b3..ec77311c8a620b37c78e03ce61b23f22e086c2ef 100644 (file)
@@ -73,7 +73,7 @@ fib_ht_free(struct fib_node **h)
 }
 
 static inline unsigned
-fib_hash(struct fib *f, ip_addr *a)
+fib_hash(const struct fib *f, ip_addr *a)
 {
   return ipa_hash(*a) >> f->hash_shift;
 }
@@ -368,7 +368,7 @@ fib_free(struct fib *f)
 }
 
 void
-fit_init(struct fib_iterator *i, struct fib *f)
+fit_init(struct fib_iterator *i, const struct fib *f)
 {
   unsigned h;
   struct fib_node *n;
@@ -390,7 +390,7 @@ fit_init(struct fib_iterator *i, struct fib *f)
 }
 
 struct fib_node *
-fit_get(struct fib *f, struct fib_iterator *i)
+fit_get(const struct fib *f, struct fib_iterator *i)
 {
   struct fib_node *n;
   struct fib_iterator *j, *k;
index 7cb26360a520e0a587e123526112bbfe059329d1..6d623f9537ab8bbb37a51bca1db22c7d3d79f982 100644 (file)
@@ -316,7 +316,7 @@ log_init_debug(char *f)
 }
 
 void
-mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
+mrt_dump_message(const struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
 {
   /* Prepare header */
   put_u32(buf+0, now_real);
index 8fb76fecf7c9e19379e364b6d319e446878bf048..753cb5902ead5ca7809406f1c92f4c67ef7f9257 100644 (file)
@@ -1,12 +1,14 @@
 #include "sysdep/config.h"
-#include "lib/event.c"                 /* REMOVE ME */
+#include "lib/event.c"         /* REMOVE ME */
 #include "lib/ip.c"            /* REMOVE ME */
 #include "lib/resource.c"      /* REMOVE ME */
 #include "lib/printf.c"                /* REMOVE ME */
 #include "lib/xmalloc.c"       /* REMOVE ME */
 #include "lib/bitops.c"                /* REMOVE ME */
+#include "lib/mempool.c"       /* REMOVE ME */
 
-#define bug(msg, ...)          debug("BUG: " msg, ##__VA_ARGS__)
+#define bug(msg, ...)          debug("BUG: "     msg, ##__VA_ARGS__)
+#define log_msg(msg, ...)      debug("LOG_MSG: " msg, ##__VA_ARGS__)
 
 void
 debug(const char *msg, ...)
@@ -32,3 +34,5 @@ io_log_event(void *hook, void *data)
 {
   bt_debug("This is io_log_event mockup. \n");
 };
+
+#include "lib/slab.c"          /* REMOVE ME */