mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-01-03 15:41:54 +00:00
Add core support for MRT Table Dump (RFC 6396)
This commit is contained in:
parent
700cf1c203
commit
de77e5cdd0
6
lib/ip.c
6
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 :: */
|
||||
{
|
||||
|
4
lib/ip.h
4
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
|
||||
|
@ -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);
|
||||
|
159
nest/mrtdump.c
Normal file
159
nest/mrtdump.c
Normal file
@ -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");
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* 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(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
|
||||
|
||||
#endif
|
||||
void mrt_dump_message(const struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
|
||||
|
||||
#endif /* _MRTDUMP_H_ */
|
||||
|
115
nest/mrtdump_test.c
Normal file
115
nest/mrtdump_test.c
Normal file
@ -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();
|
||||
}
|
12
nest/route.h
12
nest/route.h
@ -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]; \
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user