]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
mrt: first version of mrt parse. Not parsing bgp routes, but all of the other mrt...
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Wed, 21 May 2025 10:09:49 +0000 (12:09 +0200)
committerKaterina Kubecova <katerina.kubecova@nic.cz>
Tue, 10 Jun 2025 11:34:31 +0000 (13:34 +0200)
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/packets.c
proto/mrt/Makefile
proto/mrt/mrt.c
proto/mrt/mrt.h
proto/mrt/mrt_parse.c [new file with mode: 0644]

index e853624b803c3cf2fa9ebfede654b7eff365827d..51193d1707a80fafe4e854d791f68608ac51c3e6 100644 (file)
@@ -1366,7 +1366,7 @@ bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, ui
  * by an (uncached) &rta.
  */
 ea_list *
-bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
+bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len, void (*parse_error)(struct bgp_parse_state *, uint))
 {
   struct bgp_proto *p = s->proto;
   ea_list *attrs = NULL;
@@ -1464,7 +1464,7 @@ framing_error:
 withdraw:
   /* RFC 7606 5.2 - handle missing NLRI during errors */
   if (!s->ip_reach_len && !s->mp_reach_len)
-    bgp_parse_error(s, 1);
+    parse_error(s, 1);
 
   s->err_withdraw = 1;
   return NULL;
index 515ef2754c74f26fdee6c84f0070f706775039ca..017677f5c4d3aaf6990015db50e42e38ff74635f 100644 (file)
@@ -497,6 +497,9 @@ struct bgp_parse_state {
   struct bgp_channel *channel;
   struct linpool *pool;
 
+, void (*parse_error)(struct bgp_parse_state *, uint);
+  void (*rte_update)(struct bgp_parse_state *, ...);
+
   int as4_session;
   int add_path;
   int mpls;
@@ -661,6 +664,7 @@ int bgp_encode_mp_reach_mrt(struct bgp_write_state *s, eattr *a, byte *buf, uint
 const char * bgp_attr_name(uint code);
 int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end);
 ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
+int bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea);
 void bgp_finish_attrs(struct bgp_parse_state *s, rta *a);
 
 void bgp_init_bucket_table(struct bgp_channel *c);
index 2eabe6ec13c36f58098b8834d25caa46867f249f..b93d4a385bc112fa2095d8cd60895629adb59dbc 100644 (file)
@@ -2788,9 +2788,56 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
   s->cached_rta = NULL;
 }
 
+int
+bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea, void (*parse_error)(struct bgp_parse_state *, uint))
+{
+  /*
+   *   UPDATE message format
+   *
+   *   2 B     IPv4 Withdrawn Routes Length
+   *   var     IPv4 Withdrawn Routes NLRI
+   *   2 B     Total Path Attribute Length
+   *   var     Path Attributes
+   *   var     IPv4 Reachable Routes NLRI
+   */
+  log("in parse update, len %i", len);
+  uint pos = 0;
+  s->ip_unreach_len = get_u16(pkt + pos);
+  log("s->ip_unreach_len %i", s->ip_unreach_len);
+  s->ip_unreach_nlri = pkt + pos + 2;
+  pos += 2 + s->ip_unreach_len;
+
+  if (pos + 2 > len)
+  {
+    parse_error(s, 1);
+    return 0;
+  }
+
+  s->attr_len = get_u16(pkt + pos);
+  log("s->attr_len %i", s->attr_len);
+  s->attrs = pkt + pos + 2;
+  pos += 2 + s->attr_len;
+
+  if (pos > len)
+  {
+    parse_error(s, 1);
+    return 0;
+  }
+
+  s->ip_reach_len = len - pos;
+  s->ip_reach_nlri = pkt + pos;
+
+  if (s->attr_len)
+    *ea = bgp_decode_attrs(s, s->attrs, s->attr_len, parse_error);
+  else
+    *ea = NULL;
+  return 1;
+}
+
 static void
 bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
 {
+  log("bgp_rx_update");
   struct bgp_proto *p = conn->bgp;
   ea_list *ea = NULL;
 
@@ -2828,40 +2875,8 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
   if (len < 23)
   { bgp_error(conn, 1, 2, pkt+16, 2); return; }
 
-  /* Skip fixed header */
-  uint pos = 19;
-
-  /*
-   *   UPDATE message format
-   *
-   *   2 B     IPv4 Withdrawn Routes Length
-   *   var     IPv4 Withdrawn Routes NLRI
-   *   2 B     Total Path Attribute Length
-   *   var     Path Attributes
-   *   var     IPv4 Reachable Routes NLRI
-   */
-
-  s.ip_unreach_len = get_u16(pkt + pos);
-  s.ip_unreach_nlri = pkt + pos + 2;
-  pos += 2 + s.ip_unreach_len;
-
-  if (pos + 2 > len)
-    bgp_parse_error(&s, 1);
-
-  s.attr_len = get_u16(pkt + pos);
-  s.attrs = pkt + pos + 2;
-  pos += 2 + s.attr_len;
-
-  if (pos > len)
-    bgp_parse_error(&s, 1);
-
-  s.ip_reach_len = len - pos;
-  s.ip_reach_nlri = pkt + pos;
-
-  if (s.attr_len)
-    ea = bgp_decode_attrs(&s, s.attrs, s.attr_len);
-  else
-    ea = NULL;
+  bgp_parse_update(&s, pkt + 19, len - 19, &ea, bgp_parse_error); /* add 19 to skip fixed header */
+  log("yay update parsed");
 
   /* Check for End-of-RIB marker */
   if (!s.attr_len && !s.ip_unreach_len && !s.ip_reach_len)
@@ -3489,9 +3504,11 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
   byte type = pkt[18];
 
   DBG("BGP: Got packet %02x (%d bytes)\n", type, len);
+  log("BGP: Got packet %02x (%d bytes)        !!!!!!!!!!!!!!!!!!\n", type, len);
   conn->bgp->stats.rx_messages++;
   conn->bgp->stats.rx_bytes += len;
 
+  log("do we want to do mrt dump ? conn->bgp->p.mrtdump %x & MD_MESSAGES %x", conn->bgp->p.mrtdump, MD_MESSAGES);
   if (conn->bgp->p.mrtdump & MD_MESSAGES)
     bgp_dump_message(conn, pkt, len);
 
index 8cd44ac18f0469092d7013f336320bdb86552f38..a78f11a5a28587850451ac26ea28ff5615d24d29 100644 (file)
@@ -1,4 +1,4 @@
-src := mrt.c
+src := mrt.c mrt_parse.c
 obj := $(src-o-files)
 $(all-daemon)
 $(cf-local)
index 1336837a80f4621fc7512db3f38b33b2706af7f9..3369c9de9dd3076dfebd80d05041824889c3d649 100644 (file)
@@ -710,6 +710,10 @@ mrt_dump_cont(struct cli *c)
   cli_printf(c, 0, "");
   mrt_table_dump_free(c->rover);
   c->cont = c->cleanup = c->rover = NULL;
+  mrt_load("mrt_dump.txt");
+  log("____________________________");
+  mrt_load("dump.mrt");
+  mrt_load("dump_bgp.mrt");
 }
 
 static void
@@ -796,6 +800,7 @@ mrt_bgp_header(buffer *b, struct mrt_bgp_data *d)
 void
 mrt_dump_bgp_message(struct mrt_bgp_data *d)
 {
+  log("mrt_dump_bgp_message");
   const u16 subtypes[] = {
     MRT_BGP4MP_MESSAGE,                        MRT_BGP4MP_MESSAGE_AS4,
     MRT_BGP4MP_MESSAGE_LOCAL,          MRT_BGP4MP_MESSAGE_AS4_LOCAL,
index 4ff94c120dbf8768d5b8147a743f322bfa93588a..9371ce16c0d730e444ef4716e6e26d07cd16a760 100644 (file)
@@ -16,6 +16,7 @@
 #include "nest/route.h"
 #include "lib/event.h"
 #include "lib/hash.h"
+#include "proto/bgp/bgp.h"
 
 
 struct mrt_config {
@@ -155,4 +156,6 @@ static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED) { }
 static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED) { }
 #endif
 
+void mrt_load(char *file);
+
 #endif /* _BIRD_MRT_H_ */
diff --git a/proto/mrt/mrt_parse.c b/proto/mrt/mrt_parse.c
new file mode 100644 (file)
index 0000000..e7f2b45
--- /dev/null
@@ -0,0 +1,387 @@
+
+#include "mrt.h"
+#include <stdio.h>
+
+
+byte
+mrt_load_one(FILE *fp, u64 *remains)
+{
+  remains[0]--;
+  return fgetc(fp);
+}
+
+void
+mrt_load_n_octet(FILE *fp, u64 *remains, byte *buff, int n)
+{
+  for (int i = 0; i < n; i++)
+    buff[i] = fgetc(fp);
+  remains[0] = remains[0] - n;
+}
+
+u64
+mrt_load_four_octet(FILE *fp, u64 *remains)
+{
+  u64 ret = 0;
+  for (int i = 0; i < 4; i++)
+  {
+    ret = ret << 8;
+    ret += fgetc(fp);
+  }
+  remains[0] = remains[0] - 4;
+  return ret;
+}
+
+void
+mrt_load_ip(FILE *fp, u64 *remains, ip_addr *addr, bool is_ip6)
+{
+  if (is_ip6)
+    for (int i = 0; i < 4; i++)
+      addr->addr[i] = mrt_load_four_octet(fp, remains);
+  else
+  {
+    addr->addr[0] = addr->addr[1] = addr->addr[2] = 0;
+    addr->addr[3] = mrt_load_four_octet(fp, remains);
+  }
+}
+
+u32
+mrt_load_two_octet(FILE *fp, u64 *remains)
+{
+  remains[0] = remains[0] - 2;
+  return (fgetc(fp) << 8) + fgetc(fp);
+}
+
+/*
+        0                   1                   2                   3
+        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |   Peer Type   |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                         Peer BGP ID                           |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                   Peer IP Address (variable)                  |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                        Peer AS (variable)                     |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+                          Figure 6: Peer Entries
+*/
+
+void
+mrt_parse_peer(FILE *fp, u64 *remains)
+{
+  int peer_type = mrt_load_one(fp, remains);
+  u64 peer_bgp_id = mrt_load_four_octet(fp, remains);
+  ip_addr addr;
+  u64 peer_as;
+  mrt_load_ip(fp, remains, &addr, peer_type & MRT_PEER_TYPE_IPV6);
+
+  if (peer_type & MRT_PEER_TYPE_32BIT_ASN)
+    peer_as = mrt_load_four_octet(fp,remains);
+  else
+    peer_as = mrt_load_two_octet(fp, remains);
+  log("peer type %i, bgp id %li adddr %I as %li", peer_type, peer_bgp_id, addr, peer_as);
+}
+
+/*
+        0                   1                   2                   3
+        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                      Collector BGP ID                         |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |       View Name Length        |     View Name (variable)      |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |          Peer Count           |    Peer Entries (variable)
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+                    Figure 5: PEER_INDEX_TABLE Subtype
+*/
+
+void
+mrt_parse_peer_index_table(FILE *fp, u64 *remains)
+{
+  u64 collector = mrt_load_four_octet(fp, remains);
+  int name_len = mrt_load_two_octet(fp, remains);
+  log("name len %i collector %lx", name_len, collector);
+  char name[name_len + 1];
+  name[name_len] = 0;
+  mrt_load_n_octet(fp, remains, name, name_len);
+  int peer_count = mrt_load_two_octet(fp, remains);
+  log("name %s, count %i", name, peer_count);
+
+  for (int i = 0; i < peer_count; i++)
+    mrt_parse_peer(fp, remains);
+}
+
+/*
+0                   1                   2                   3
+        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |         Peer Index            |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                         Originated Time                       |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |      Attribute Length         |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                    BGP Attributes... (variable)
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+void
+mrt_parse_rib_entry(FILE *fp, u64 *remains, bool add_path)
+{
+  int peer_index = mrt_load_two_octet(fp, remains);
+  u64 orig_time = mrt_load_four_octet(fp, remains);
+  u64 path_id;
+
+  if (add_path)
+    path_id = mrt_load_four_octet(fp, remains);
+
+  int attr_len = mrt_load_two_octet(fp, remains);
+  log("rib entry index %lx, time %lx, attr len %i (rem %li) path %li", peer_index, orig_time, attr_len, *remains, path_id);
+  //TODO how are encoded the attrs?
+  remains[0] = remains[0] - attr_len;
+
+  for (int i = 0; i < attr_len; i++)
+    fgetc(fp);
+}
+
+
+void
+mrt_parse_rib_generic(FILE *fp, u64 *remains)
+{
+  u64 seq_num = mrt_load_four_octet(fp, remains);
+  int addr_fam_id = mrt_load_two_octet(fp, remains);
+  int subs_afi = mrt_load_one(fp, remains);
+  log("seq num %lx, fam %i, subs %i", seq_num, addr_fam_id, subs_afi);
+  //TODO length of Network layer reachebility
+}
+
+
+/*
+        0                   1                   2                   3
+        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                         Sequence Number                       |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       | Prefix Length |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                        Prefix (variable)                      |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |         Entry Count           |  RIB Entries (variable)
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+void
+mrt_parse_rib4_unicast(FILE *fp, u64 *remains, bool add_path)
+{
+  u64 seq_num = mrt_load_four_octet(fp, remains);
+  int pref_len = mrt_load_one(fp, remains);
+  byte prefix[pref_len/8];
+  mrt_load_n_octet(fp, remains, prefix, pref_len/8);
+  int entry_count = mrt_load_two_octet(fp, remains);
+  log("seq %lx, pref len %i, enties %i", seq_num, pref_len, entry_count);
+
+  for (int i = 0; i < entry_count; i++)
+    mrt_parse_rib_entry(fp, remains, add_path);
+}
+
+
+void
+mrt_parse_error(struct bgp_parse_state * UNUSED, uint UNUSED)
+{
+  log("run into a parsing error");
+}
+
+/*
+        0                   1                   2                   3
+        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |         Peer AS Number        |        Local AS Number        |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |        Interface Index        |        Address Family         |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                      Peer IP Address (variable)               |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                      Local IP Address (variable)              |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                    BGP Message... (variable)
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+                     Figure 12: BGP4MP_MESSAGE Subtype
+*/
+void
+mrt_parse_bgp_message(FILE *fp, u64 *remains, bool as4)
+{
+  u64 peer_as, local_as;
+  if (as4)
+  {
+    peer_as = mrt_load_four_octet(fp, remains);
+    local_as = mrt_load_four_octet(fp, remains);
+  } else
+  {
+    peer_as = mrt_load_two_octet(fp, remains);
+    local_as = mrt_load_two_octet(fp, remains);
+  }
+
+  int interface_id = mrt_load_two_octet(fp, remains);
+  int addr_fam = mrt_load_two_octet(fp, remains);
+
+  ip_addr peer_addr, local_addr;
+  mrt_load_ip(fp, remains, &peer_addr, addr_fam == 2);
+  mrt_load_ip(fp, remains, &local_addr, addr_fam == 2);
+
+  log("peer as %lx local as %lx interface %x add fam %i peer %I loc %I", peer_as, local_as, interface_id, addr_fam, peer_addr, local_addr);
+}
+
+
+void
+mrt_parse_bgp4mp_message(FILE *fp, u64 *remains, bool as4)
+{
+  log("hereeeee bgp message");
+  mrt_parse_bgp_message(fp, remains, as4);
+
+  if (*remains < 23)
+  {
+    log(L_WARN "MRT parse BGP message: BGP message is too short (%i)", *remains);
+    return;
+  }
+
+  for (int i = 0; i < 16; i++) // marker
+    fgetc(fp);
+
+  remains[0] = remains[0] - 16;
+  int length = mrt_load_two_octet(fp, remains);
+  int type = mrt_load_one(fp, remains);
+  log("message type %i", type);
+
+  if (type != PKT_UPDATE)
+  {
+    log("Another BGP type");
+    return;
+  }
+
+  struct bgp_parse_state s = {
+    .pool = lp_new(&root_pool),
+  };
+  byte buf[length];
+  mrt_load_n_octet(fp, remains, buf, length);
+  ea_list *ea = NULL;
+  log("try to parse bgp update");
+  bgp_parse_update(&s, buf, length, &ea, bgp_parse_error);
+  log("ok, seems parsed?");
+}
+
+
+void
+mrt_parse_bgp4mp_change_state(FILE *fp, u64 *remains, bool as4)
+{
+  mrt_parse_bgp_message(fp, remains, as4);
+  int old_state = mrt_load_two_octet(fp, remains);
+  int new_state = mrt_load_two_octet(fp, remains);
+  log("old state %i new state %i", old_state, new_state);
+}
+
+
+int
+mrt_parse_general_header(FILE *fp)
+{
+  char is_eof = fgetc(fp);
+  u64 timestamp = is_eof;
+
+  if (is_eof == EOF)
+    return 0;
+  else
+  {
+    for (int i = 0; i < 3; i++)
+    {
+      log("t %lx", timestamp);
+      timestamp = timestamp << 8;
+      timestamp += fgetc(fp);
+    }
+  }
+
+  log("timestamp is %lx", timestamp);
+  int type = (fgetc(fp) << 8) + fgetc(fp);
+  int subtype = (fgetc(fp) << 8) + fgetc(fp);
+  log("type is %i, subtype %x", type, subtype);
+  u64 length = 0;
+
+  for (int i = 0; i < 4; i++)
+  {
+    length = length << 8;
+    length += fgetc(fp);
+  }
+  u64 remains = length;
+  log("remains is %li", remains);
+
+  if (type == MRT_TABLE_DUMP_V2)
+  {
+    switch (subtype)
+    {
+    case (MRT_PEER_INDEX_TABLE):
+      mrt_parse_peer_index_table(fp, &remains);
+      break;
+    case (MRT_RIB_IPV4_UNICAST):
+    case (MRT_RIB_IPV6_UNICAST):
+    case (MRT_RIB_IPV4_MULTICAST):
+    case (MRT_RIB_IPV6_MULTICAST):
+      mrt_parse_rib4_unicast(fp, &remains, false);
+      break;
+    case (MRT_RIB_IPV4_UNICAST_ADDPATH):
+    case (MRT_RIB_IPV6_UNICAST_ADDPATH):
+    case (MRT_RIB_IPV4_MULTICAST_ADDPATH):
+    case (MRT_RIB_IPV6_MULTICAST_ADDPATH):
+      mrt_parse_rib4_unicast(fp, &remains, true);
+      break;
+    case (MRT_RIB_GENERIC):
+    case (MRT_RIB_GENERIC_ADDPATH):
+      mrt_parse_rib_generic(fp, &remains);
+      break;
+    default:
+      bug("mrt: unknown mrt table dump subtype");
+    }
+  } else
+  {
+    ASSERT_DIE(type == MRT_BGP4MP);
+
+    switch (subtype)
+    {
+      case (MRT_BGP4MP_MESSAGE):
+      case (MRT_BGP4MP_MESSAGE_LOCAL):
+      case (MRT_BGP4MP_MESSAGE_ADDPATH):
+        mrt_parse_bgp4mp_message(fp, &remains, false);
+        break;
+      case (MRT_BGP4MP_STATE_CHANGE_AS4):
+        mrt_parse_bgp4mp_change_state(fp, &remains, true);
+        break;
+      case (MRT_BGP4MP_MESSAGE_AS4):
+      case (MRT_BGP4MP_MESSAGE_AS4_LOCAL):
+      case (MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH):
+      case (MRT_BGP4MP_MESSAGE_AS4_ADDPATH):
+        mrt_parse_bgp4mp_message(fp, &remains, true);
+        break;
+    }
+  }
+
+  ASSERT_DIE(remains < length);
+
+  for (u64 i = 0; i < remains; i++)
+    fgetc(fp);
+
+  return 1;
+}
+
+
+void
+mrt_load(char *file)
+{
+  FILE *fp = fopen(file, "r");
+
+  if (fp == NULL)
+  {
+    log(L_WARN "Can not open file %s", fp);
+    return;
+  }
+  
+  while (mrt_parse_general_header(fp));
+}