0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

mrt: merged mrt protocol from bird v2

This commit is contained in:
Katerina Kubecova 2024-09-27 13:58:46 +02:00 committed by Maria Matejka
parent 826191080d
commit 7c04201390
9 changed files with 126 additions and 86 deletions

View File

@ -320,8 +320,7 @@ else
AC_DEFINE([HAVE_CLOCK_MONOTONIC_COARSE], [1], [Define to 1 if coarse clock is available])
fi
# temporarily removed "mrt" from all_protocols to speed up 3.0-alpha1 release
all_protocols="aggregator bfd babel bgp l3vpn ospf pipe radv rip rpki static"
all_protocols="aggregator bfd babel bgp l3vpn ospf pipe radv rip rpki static mrt"
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
if test "$with_protocols" = all ; then

View File

@ -1413,7 +1413,10 @@ static inline int
bgp_encode_attr(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
{
const union bgp_attr_desc *desc = bgp_find_attr_desc(a);
if (s->ignore_non_bgp_attrs == 0)
ASSERT_DIE(desc);
else if (desc == NULL)
return 0;
return desc->encode(s, a, buf, size);
}

View File

@ -513,6 +513,7 @@ struct bgp_write_state {
int as4_session;
int add_path;
int mpls;
int ignore_non_bgp_attrs;
eattr *mp_next_hop;
const adata *mpls_labels;

View File

@ -145,7 +145,7 @@ bgp_dump_message(struct bgp_conn *conn, byte *pkt, uint len)
d.msg_len = len;
d.add_path = bgp_estimate_add_path(conn->bgp, pkt, len);
mrt_dump_bgp_message(&d);
mrt_dump_bgp_message(&d, conn->bgp->p.pool);
}
void
@ -157,7 +157,7 @@ bgp_dump_state_change(struct bgp_conn *conn, uint old, uint new)
d.old_state = old;
d.new_state = new;
mrt_dump_bgp_state_change(&d);
mrt_dump_bgp_state_change(&d, conn->bgp->p.pool);
}
static byte *

View File

@ -28,6 +28,7 @@ proto: mrt_proto ;
mrt_proto_start: proto_start MRT
{
this_proto = proto_config_new(&proto_mrt, $1);
this_proto->loop_order = DOMAIN_ORDER(proto);
};
mrt_proto_item:

View File

@ -38,6 +38,7 @@
* - RFC 6396 - MRT format standard
* - RFC 8050 - ADD_PATH extension
*/
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
@ -45,10 +46,13 @@
#include "mrt.h"
#include "lib/io-loop.h"
#include "nest/cli.h"
#include "filter/filter.h"
#include "proto/bgp/bgp.h"
#include "sysdep/unix/unix.h"
#include "sysdep/unix/io-loop.h"
#include "conf/conf.h"
#ifdef PATH_MAX
@ -65,6 +69,7 @@
log(L_ERR "%s: " msg, s->proto->p.name, ## args); \
})
extern proto_state_table proto_state_table_pub;
/*
* MRT buffer code
@ -78,6 +83,13 @@ mrt_buffer_init(buffer *b, pool *pool, size_t n)
b->end = b->start + n;
}
static void
mrt_buffer_free(buffer *b)
{
mb_free(b->start);
b->start = b->pos = b->end = NULL;
}
static void
mrt_buffer_grow(buffer *b, size_t n)
{
@ -169,6 +181,15 @@ mrt_init_message(buffer *b, u16 type, u16 subtype)
mrt_put_u32_(b, 0);
}
rtable *
get_tab(struct mrt_table_dump_state *s)
{
if (s->table->head)
return (rtable*)SKIP_BACK(rtable, n, s->table->head);
else
return NULL;
}
static void
mrt_dump_message(buffer *b, int fd)
{
@ -240,20 +261,28 @@ mrt_next_table_(rtable *tab, rtable *tab_ptr, const char *pattern)
static rtable *
mrt_next_table(struct mrt_table_dump_state *s)
{
rtable *tab = mrt_next_table_(s->table, s->table_ptr, s->table_expr);
rtable *tab = mrt_next_table_(get_tab(s), s->table_ptr, s->table_expr);
if (s->table)
RT_LOCKED(s->table, tab)
if (s->table->head)
RT_LOCKED(get_tab(s), tab)
rt_unlock_table(tab);
s->table = tab;
if (tab == NULL)
{
s->ipv4 = 0;
return NULL;
}
s->table->head = &tab->n;
s->ipv4 = tab ? (tab->addr_type == NET_IP4) : 0;
if (s->table)
RT_LOCKED(s->table, tab)
if (s->table->head)
{
rtable *t = get_tab(s);
RT_LOCKED(t, tab)
rt_lock_table(tab);
}
return s->table;
return get_tab(s);
}
static int
@ -263,15 +292,16 @@ mrt_open_file(struct mrt_table_dump_state *s)
char name[BIRD_PATH_MAX];
btime now = current_time();
btime now_real = current_real_time();
rtable *tab = get_tab(s);
if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", s->table->name) ||
if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", tab->name) ||
!tm_format_real_time(name, sizeof(name), fmt1, now_real))
{
mrt_log(s, "Invalid filename '%s'", s->filename);
return 0;
}
s->file = rf_open(s->pool, name, "a");
s->file = rf_open(s->pool, name, RF_APPEND, 0);
if (!s->file)
{
mrt_log(s, "Unable to open MRT file '%s': %m", name);
@ -354,23 +384,38 @@ static void
mrt_peer_table_dump(struct mrt_table_dump_state *s)
{
mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, MRT_PEER_INDEX_TABLE);
mrt_peer_table_header(s, config->router_id, s->table->name);
mrt_peer_table_header(s, OBSREF_GET(config)->router_id, get_tab(s)->name);
/* 0 is fake peer for non-BGP routes */
mrt_peer_table_entry(s, 0, 0, IPA_NONE);
#ifdef CONFIG_BGP
struct proto *P;
WALK_LIST(P, proto_list)
if ((P->proto == &proto_bgp) && (P->proto_state != PS_DOWN))
PST_LOCKED(ts)
{
struct bgp_proto *p = (void *) P;
mrt_peer_table_entry(s, p->remote_id, p->remote_as, p->remote_ip);
for(u32 i = 0; i < ts->length_states; i++)
{
ea_list *eal = ts->states[i];
if (eal)
ea_free_later(ea_ref(eal));
else
continue;
struct protocol *type = (struct protocol *)ea_get_ptr(eal, &ea_protocol_type, 0);
int state = ea_get_int(eal, &ea_state, 0);
if ((type == &proto_bgp) && (state != PS_DOWN))
{
int rem_id = ea_get_int(eal, &ea_bgp_rem_id, 0);
int rem_as = ea_get_int(eal, &ea_bgp_rem_as, 0);
ip_addr *rem_ip = (ip_addr *)ea_get_adata(eal, &ea_bgp_rem_ip)->data;
mrt_peer_table_entry(s, rem_id, rem_as, *rem_ip);
}
}
}
#endif
/* Fix Peer Count */
put_u16(s->buf.start + s->peer_count_offset, s->peer_count);
log("peer count %i", s->peer_count);
mrt_dump_message(&s->buf, s->fd);
}
@ -388,7 +433,7 @@ mrt_peer_table_flush(struct mrt_table_dump_state *s)
*/
static void
mrt_rib_table_header(struct mrt_table_dump_state *s, net_addr *n)
mrt_rib_table_header(struct mrt_table_dump_state *s, const net_addr *n)
{
buffer *b = &s->buf;
@ -432,7 +477,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r)
return;
/* Attribute list must be normalized for bgp_encode_attrs() */
if (!rta_is_cached(r->attrs))
if (!r->attrs->stored)
eattrs = ea_normalize(eattrs, 0);
mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
@ -440,6 +485,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r)
s->bws->mp_reach = !s->ipv4;
s->bws->mp_next_hop = NULL;
s->bws->ignore_non_bgp_attrs = 1;
/* Encode BGP attributes */
int len = bgp_encode_attrs(s->bws, eattrs, pos, b->end);
@ -503,7 +549,7 @@ mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
}
static void
mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
mrt_rib_table_dump(struct mrt_table_dump_state *s, const struct rt_export_feed *feed, int add_path)
{
s->add_path = s->bws->add_path = add_path;
@ -512,23 +558,23 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
(!add_path ? MRT_RIB_IPV6_UNICAST : MRT_RIB_IPV6_UNICAST_ADDPATH);
mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, subtype);
mrt_rib_table_header(s, n->n.addr);
mrt_rib_table_header(s, feed->block[0].net);
for (struct rte_storage *rt, *rt0 = n->routes; rt = rt0; rt0 = rt0->next)
for (uint i = 0; i < feed->count_routes; i++)
{
if (rte_is_filtered(&rt->rte))
rte *rte = &feed->block[i];
if (rte_is_filtered(rte))
continue;
/* Skip routes that should be reported in the other phase */
if (!s->always_add_path && (!rt->rte.src->private_id != !s->add_path))
if (!s->always_add_path && (!rte->src->private_id != !s->add_path))
{
s->want_add_path = 1;
continue;
}
rte e = rt->rte;
if (f_run(s->filter, &e, 0) <= F_ACCEPT)
mrt_rib_table_entry(s, &e);
if (f_run(s->filter, rte, 0) <= F_ACCEPT)
mrt_rib_table_entry(s, rte);
lp_flush(s->linpool);
}
@ -555,8 +601,9 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
static struct mrt_table_dump_state *
mrt_table_dump_init(pool *pp)
{
pool *pool = rp_new(pp, "MRT Table Dump");
pool *pool = rp_new(pp, pp->domain, "MRT Table Dump");
struct mrt_table_dump_state *s = mb_allocz(pool, sizeof(struct mrt_table_dump_state));
s->table = (list*)mb_allocz(pool, sizeof(list));
s->pool = pool;
s->linpool = lp_new(pool);
@ -564,8 +611,8 @@ mrt_table_dump_init(pool *pp)
mrt_buffer_init(&s->buf, pool, 2 * MRT_ATTR_BUFFER_SIZE);
/* We lock the current config as we may reference it indirectly by filter */
s->config = config;
config_add_obstacle(s->config);
OBSREF_SET(s->config, OBSREF_GET(config));
s->fd = -1;
@ -575,20 +622,7 @@ mrt_table_dump_init(pool *pp)
static void
mrt_table_dump_free(struct mrt_table_dump_state *s)
{
if (s->table)
RT_LOCKED(s->table, tab)
{
if (s->table_open)
FIB_ITERATE_UNLINK(&s->fit, &tab->fib);
rt_unlock_table(tab);
}
if (s->table_ptr)
RT_LOCKED(s->table_ptr, tab)
rt_unlock_table(tab);
config_del_obstacle(s->config);
OBSREF_CLEAR(s->config);
rp_free(s->pool);
}
@ -612,37 +646,33 @@ mrt_table_dump_step(struct mrt_table_dump_state *s)
mrt_peer_table_dump(s);
RT_LOCKED(s->table, tab)
{
FIB_ITERATE_INIT(&s->fit, &tab->fib);
s->table_open = 1;
step:
FIB_ITERATE_START(&tab->fib, &s->fit, net, n)
step: ;
struct rt_export_feeder feeder = (struct rt_export_feeder) {
.name = "cli.feeder",
};
RT_LOCKED(get_tab(s), tab)
rt_feeder_subscribe(&tab->export_all, &feeder);
RT_FEED_WALK(&feeder, route_feed)
{
if (s->max < 0)
{
FIB_ITERATE_PUT(&s->fit);
RT_RETURN(tab, 0);
}
return 0;
/* With Always ADD_PATH option, we jump directly to second phase */
s->want_add_path = s->always_add_path;
if (s->want_add_path == 0)
mrt_rib_table_dump(s, n, 0);
mrt_rib_table_dump(s, route_feed, 0);
if (s->want_add_path == 1)
mrt_rib_table_dump(s, n, 1);
mrt_rib_table_dump(s, route_feed, 1);
}
FIB_ITERATE_END;
s->table_open = 0;
}
s->table_open = 0;
mrt_close_file(s);
mrt_peer_table_flush(s);
rt_feeder_unsubscribe(&feeder);
}
return 1;
@ -676,7 +706,7 @@ mrt_timer(timer *t)
rt_lock_table(tab);
p->table_dump = s;
ev_schedule(p->event);
ev_send_loop(p->p.loop, p->event);
}
static void
@ -720,12 +750,11 @@ mrt_dump_cont(struct cli *c)
c->rover = NULL;
}
static int
void
mrt_dump_cleanup(struct cli *c)
{
mrt_table_dump_free(c->rover);
c->rover = NULL;
return 0;
}
void
@ -763,14 +792,12 @@ mrt_dump_cmd(struct mrt_dump_data *d)
*/
static buffer *
mrt_bgp_buffer(void)
mrt_bgp_buffer(pool *p)
{
/* Static buffer for BGP4MP dump, TODO: change to use MRT protocol */
static buffer b;
if (!b.start)
mrt_buffer_init(&b, &root_pool, 1024);
static _Thread_local buffer b;
mrt_buffer_init(&b, p, 1024);
return &b;
}
@ -804,7 +831,7 @@ mrt_bgp_header(buffer *b, struct mrt_bgp_data *d)
}
void
mrt_dump_bgp_message(struct mrt_bgp_data *d)
mrt_dump_bgp_message(struct mrt_bgp_data *d, pool *p)
{
const u16 subtypes[] = {
MRT_BGP4MP_MESSAGE, MRT_BGP4MP_MESSAGE_AS4,
@ -813,15 +840,16 @@ mrt_dump_bgp_message(struct mrt_bgp_data *d)
MRT_BGP4MP_MESSAGE_LOCAL_ADDPATH, MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH,
};
buffer *b = mrt_bgp_buffer();
buffer *b = mrt_bgp_buffer(p);
mrt_init_message(b, MRT_BGP4MP, subtypes[d->as4 + 4*d->add_path]);
mrt_bgp_header(b, d);
mrt_put_data(b, d->message, d->msg_len);
mrt_dump_message(b, config->mrtdump_file);
mrt_dump_message(b, rf_fileno(OBSREF_GET(config)->mrtdump_file));
mrt_buffer_free(b);
}
void
mrt_dump_bgp_state_change(struct mrt_bgp_data *d)
mrt_dump_bgp_state_change(struct mrt_bgp_data *d, pool *p)
{
/* Convert state from our BS_* values to values used in MRTDump */
const u16 states[BS_MAX] = {1, 2, 3, 4, 5, 6, 1};
@ -832,12 +860,13 @@ mrt_dump_bgp_state_change(struct mrt_bgp_data *d)
/* Always use AS4 mode for STATE_CHANGE */
d->as4 = 1;
buffer *b = mrt_bgp_buffer();
buffer *b = mrt_bgp_buffer(p);
mrt_init_message(b, MRT_BGP4MP, MRT_BGP4MP_STATE_CHANGE_AS4);
mrt_bgp_header(b, d);
mrt_put_u16(b, states[d->old_state]);
mrt_put_u16(b, states[d->new_state]);
mrt_dump_message(b, config->mrtdump_file);
mrt_dump_message(b, rf_fileno(OBSREF_GET(config)->mrtdump_file));
mrt_buffer_free(b);
}
@ -877,7 +906,7 @@ mrt_start(struct proto *P)
p->timer = tm_new_init(P->pool, mrt_timer, p, cf->period S, 0);
p->event = ev_new_init(P->pool, mrt_event, p);
tm_start(p->timer, cf->period S);
tm_start_in(p->timer, cf->period S, p->p.loop);
return PS_UP;
}
@ -904,7 +933,7 @@ mrt_reconfigure(struct proto *P, struct proto_config *CF)
btime now = current_time();
btime new_time = p->timer->expires - (old->period S) + (new->period S);
p->timer->recurrent = new->period S;
tm_set(p->timer, MAX(now, new_time));
tm_set_in(p->timer, MAX(now, new_time), p->p.loop);
}
return 1;

View File

@ -56,7 +56,7 @@ struct mrt_peer_entry {
struct mrt_table_dump_state {
struct mrt_proto *proto; /* Protocol for regular MRT dumps (or NULL) */
struct cli *cli; /* CLI for irregular MRT dumps (or NULL) */
struct config *config; /* Config valid during start of dump, locked */
config_ref config; /* Config valid during start of dump, locked */
/* Configuration information */
const char *table_expr; /* Wildcard for table name (or NULL) */
@ -73,8 +73,8 @@ struct mrt_table_dump_state {
HASH(struct mrt_peer_entry) peer_hash; /* Hash for peers to find the index */
rtable *table; /* Processed table, NULL initially */
struct fib_iterator fit; /* Iterator in processed table */
list *table; /* Processed table, NULL initially - changed to list for v3*/
node *fit; /* Iterator in processed table - changed to node for v3*/
int table_open; /* Whether iterator is linked */
int ipv4; /* Processed table is IPv4 */
@ -147,12 +147,12 @@ struct mrt_bgp_data {
#ifdef CONFIG_MRT
void mrt_dump_cmd(struct mrt_dump_data *d);
void mrt_dump_bgp_message(struct mrt_bgp_data *d);
void mrt_dump_bgp_state_change(struct mrt_bgp_data *d);
void mrt_dump_bgp_message(struct mrt_bgp_data *d, pool *p);
void mrt_dump_bgp_state_change(struct mrt_bgp_data *d, pool *p);
void mrt_check_config(struct proto_config *C);
#else
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) { }
static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED, pool *p UNUSED) { }
static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED, pool *p UNUSED) { }
#endif
#endif /* _BIRD_MRT_H_ */

View File

@ -106,6 +106,12 @@ static struct resclass rf_class = {
NULL
};
int
rf_fileno(struct rfile *f)
{
return f->fd;
}
static int
rf_open_get_fd(const char *name, enum rf_mode mode)
{

View File

@ -126,6 +126,7 @@ off_t rf_size(struct rfile *);
int rf_same(struct rfile *, struct rfile *);
int rf_writev(struct rfile *, struct iovec *, int);
void rf_write_crude(struct rfile *, const char *, int);
int rf_fileno(struct rfile *f);
extern struct rfile rf_stderr;