Commit de77e5cd authored by Pavel Tvrdík's avatar Pavel Tvrdík
Browse files

Add core support for MRT Table Dump (RFC 6396)

parent 700cf1c2
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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 :: */
  {
+2 −2
Original line number Diff line number Diff line
@@ -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
+3 −3
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ 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);
@@ -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);

nest/mrtdump.c

0 → 100644
+159 −0
Original line number Diff line number Diff line
/*
 *	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");
}
+72 −13
Original line number Diff line number Diff line
/*
 *	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_ */
Loading