diff --git a/lib/route.h b/lib/route.h index b9bbd2ae..783ef34a 100644 --- a/lib/route.h +++ b/lib/route.h @@ -423,7 +423,7 @@ ea_set_attr_u32(ea_list **to, const struct ea_class *def, uint flags, u64 data) { ea_set_attr(to, EA_LITERAL_EMBEDDED(def, flags, data)); } static inline void -ea_set_attr_ptr(ea_list **to, const struct ea_class *def, uint flags, const void *data) +ea_set_attr_ptr(ea_list **to, const struct ea_class *def, uint flags, void *data) { ea_set_attr(to, EA_LITERAL_STORE_PTR(def, flags, data)); } static inline void diff --git a/lib/type.h b/lib/type.h index e42c6728..9244ea40 100644 --- a/lib/type.h +++ b/lib/type.h @@ -24,7 +24,7 @@ union bval { }; \ const struct adata *ptr; /* Generic attribute data inherited from eattrs */ \ const struct adata *ad; /* Generic attribute data inherited from filters */ \ - const void * v_ptr; /* Stored pointer */ \ + void * v_ptr; /* Stored pointer */ \ BVAL_ITEMS; }; diff --git a/nest/proto.c b/nest/proto.c index 670ee506..5a46514b 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -2146,6 +2146,10 @@ protos_build(void) hmap_init(&ts->proto_id_map, p, ts->proto_len); /* for proto ids. Value of proto id is the same as index of that proto in ptoto_state_table->attrs */ hmap_init(&ts->channel_id_map, p, ts->channels_len); + /* Zeros should be reserved for easier undef manipulation */ + hmap_set(&ts->proto_id_map, 0); + hmap_set(&ts->channel_id_map, 0); + ts->pool = p; ts->proto_states = mb_allocz(p, sizeof(ea_list *) * ts->proto_len); ts->channel_states = mb_allocz(p, sizeof(ea_list *) * ts->channels_len * 2); @@ -2992,7 +2996,7 @@ struct proto_announce_state_deferred { struct proto *p; }; -void +static void proto_announce_state_locked(struct proto_state_table_private* ts, struct proto *p, ea_list *new_state) { ASSERT_DIE(birdloop_inside(p->loop)); diff --git a/nest/protocol.h b/nest/protocol.h index 5526d48f..171a0a5b 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -442,9 +442,7 @@ struct proto_pending_update { ea_list *new, *old; }; -void proto_announce_state_locked(struct proto_state_table_private *ts, struct proto *p, ea_list *attr); void proto_announce_state(struct proto *p, ea_list *attr); - void proto_announce_state_later_internal(struct proto *p, ea_list *attr); #if 0 #define proto_announce_state_later(p, a) ( log(L_INFO "proto_announce_state_later(%s (%p), %p) at %s:%d", (p)->name, (p), (a), __FILE__, __LINE__), proto_announce_state_later_internal((p), (a)) ) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 0e843b50..957fe108 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1318,6 +1318,16 @@ struct ea_class ea_bgp_as4_out_conn = { .type = T_INT, }; +struct ea_class ea_bgp_extended_next_hop = { + .name = "bgp_extended_next_hop", + .type = T_INT, +}; + +struct ea_class ea_bgp_add_path_rx = { + .name = "bgp_add_path_rx", + .type = T_INT, +}; + void bgp_register_attrs(void) { @@ -1340,6 +1350,7 @@ bgp_register_attrs(void) EA_REGISTER_ALL( &ea_bgp_rem_id, &ea_bgp_rem_as, &ea_bgp_loc_as, &ea_bgp_rem_ip, &ea_bgp_peer_type, &ea_bgp_afi, + &ea_bgp_extended_next_hop, &ea_bgp_add_path_rx, &ea_bgp_in_conn_local_open_msg, &ea_bgp_out_conn_local_open_msg, &ea_bgp_in_conn_remote_open_msg, &ea_bgp_out_conn_remote_open_msg, &ea_bgp_close_bmp, &ea_bgp_as4_session, &ea_bgp_state_startup, &ea_bgp_in_conn_state, &ea_bgp_out_conn_state, diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index e87ec287..ea9392ff 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -801,6 +801,24 @@ bgp_conn_enter_established_state(struct bgp_conn *conn) c->c.ra_mode = RA_ACCEPTED; else c->c.ra_mode = RA_OPTIMAL; + + ea_list *state = NULL; + if (c->ext_next_hop) + ea_set_attr_u32(&state, &ea_bgp_extended_next_hop, 0, 1); + if (c->add_path_rx) + ea_set_attr_u32(&state, &ea_bgp_add_path_rx, 0, 1); + + if (state) + { + ea_list *sb = state; + while (sb->next) + sb = sb->next; + + PST_LOCKED(ts) { + sb->next = ea_free_later(ts->channel_states[c->c.id]); + ts->channel_states[c->c.id] = ea_lookup_slow(state, 0, EALS_IN_TABLE); + } + } } p->afi_map = mb_alloc(p->p.pool, num * sizeof(u32)); diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 05aae612..c12942ec 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -508,7 +508,6 @@ struct bgp_export_state { }; struct bgp_write_state { - struct bgp_proto *proto; struct bgp_ptx_private *ptx; struct linpool *pool; @@ -703,7 +702,7 @@ static inline struct bgp_proto *bgp_rte_proto(const rte *rte) SKIP_BACK(struct bgp_proto, p.sources, rte->src->owner) : NULL; } -byte * bgp_bmp_encode_rte(ea_list *c, struct bgp_proto *bgp_p, byte *buf, byte *end, const struct rte *new); +byte * bgp_bmp_encode_rte(ea_list *channel_state, byte *buf, byte *end, const struct rte *new); #define BGP_AIGP_METRIC 1 #define BGP_AIGP_MAX U64(0xffffffffffffffff) @@ -722,6 +721,7 @@ bgp_total_aigp_metric(const rte *e) extern struct ea_class ea_bgp_rem_id, ea_bgp_rem_as, ea_bgp_loc_as, ea_bgp_rem_ip, ea_bgp_peer_type, ea_bgp_afi, ea_bgp_in_conn_local_open_msg, ea_bgp_out_conn_local_open_msg, ea_bgp_in_conn_remote_open_msg, ea_bgp_out_conn_remote_open_msg, ea_bgp_close_bmp, ea_bgp_close_bmp_set, ea_bgp_as4_session, + ea_bgp_extended_next_hop, ea_bgp_add_path_rx, ea_bgp_state_startup, ea_bgp_in_conn_state, ea_bgp_out_conn_state, ea_bgp_in_conn_sk, ea_bgp_out_conn_sk, ea_bgp_as4_out_conn, ea_bgp_as4_in_conn; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 157843a6..f236eeab 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2480,32 +2480,27 @@ bgp_create_mp_unreach(struct bgp_write_state *s, struct bgp_bucket *buck, byte * #ifdef CONFIG_BMP static byte * -bgp_create_update_bmp(ea_list *channel_ea, struct bgp_proto *bgp_p, byte *buf, byte *end, struct bgp_bucket *buck, bool update) +bgp_create_update_bmp(ea_list *channel_ea, byte *buf, byte *end, struct bgp_bucket *buck, bool update) { - struct bgp_channel *c; - u32 c_id = ea_get_int(channel_ea, &ea_channel_id, 0); - BGP_WALK_CHANNELS(bgp_p, c) - if (c->c.id == c_id) - break; - byte *res = NULL; - struct bgp_caps *peer = bgp_p->conn->remote_caps; - const struct bgp_af_caps *rem = bgp_find_af_caps(peer, c->afi); - struct bgp_ptx_private ptx = { .bmp = 1, - .c = c, }; + u32 afi = ea_get_int(channel_ea, &ea_bgp_afi, 0); + ASSERT_DIE(afi); + + const struct bgp_af_desc *desc = bgp_get_af_desc(afi); + ASSERT_DIE(desc); + struct bgp_write_state s = { - .proto = bgp_p, .ptx = &ptx, .pool = tmp_linpool, - .mp_reach = (c->afi != BGP_AF_IPV4) || rem->ext_next_hop, + .mp_reach = (afi != BGP_AF_IPV4) || ea_get_int(channel_ea, &ea_bgp_extended_next_hop, 0), .as4_session = 1, - .add_path = c->add_path_rx, - .mpls = c->desc->mpls, + .add_path = ea_get_int(channel_ea, &ea_bgp_add_path_rx, 0), + .mpls = desc->mpls, .ignore_non_bgp_attrs = 1, }; @@ -2526,7 +2521,7 @@ bgp_create_update_bmp(ea_list *channel_ea, struct bgp_proto *bgp_p, byte *buf, b } byte * -bgp_bmp_encode_rte(ea_list *c, struct bgp_proto *bgp_p, byte *buf, byte *end, const struct rte *new) +bgp_bmp_encode_rte(ea_list *c, byte *buf, byte *end, const struct rte *new) { uint ea_size = new->attrs ? (sizeof(ea_list) + new->attrs->count * sizeof(eattr)) : 0; uint prefix_size = sizeof(struct bgp_prefix) + new->net->length; @@ -2548,7 +2543,7 @@ bgp_bmp_encode_rte(ea_list *c, struct bgp_proto *bgp_p, byte *buf, byte *end, co px->ni = NET_TO_INDEX(new->net); add_tail(&b->prefixes, &px->buck_node); - end = bgp_create_update_bmp(c, bgp_p, buf, end, b, !!new->attrs); + end = bgp_create_update_bmp(c, buf, end, b, !!new->attrs); lp_restore(tmp_linpool, tmpp); @@ -2577,7 +2572,6 @@ again: /* Initialize write state */ struct bgp_write_state s = { - .proto = p, .ptx = ptx, .pool = tmp_linpool, .mp_reach = (c->afi != BGP_AF_IPV4) || c->ext_next_hop, diff --git a/proto/bmp/Makefile b/proto/bmp/Makefile index e34f3822..1fb0ce43 100644 --- a/proto/bmp/Makefile +++ b/proto/bmp/Makefile @@ -1,4 +1,4 @@ -src := bmp.c map.c +src := bmp.c obj := $(src-o-files) $(all-daemon) $(cf-local) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index e38b9764..d5e546d2 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -29,7 +29,6 @@ */ #include "proto/bmp/bmp.h" -#include "proto/bmp/map.h" #include #include @@ -57,17 +56,15 @@ #include "nest/iface.h" #include "nest/route.h" -#define HASH_PEER_KEY(n) n->bgp +#define HASH_PEER_KEY(n) n->info.proto_id #define HASH_PEER_NEXT(n) n->next #define HASH_PEER_EQ(b1,b2) b1 == b2 -#define HASH_PEER_FN(b) ptr_hash(b) +#define HASH_PEER_FN(b) u32_hash(b) -#define BMP_STREAM_KEY_POLICY 0x100 - -#define HASH_STREAM_KEY(n) n->bgp, n->key +#define HASH_STREAM_KEY(n) &n->info #define HASH_STREAM_NEXT(n) n->next -#define HASH_STREAM_EQ(b1,k1,b2,k2) b1 == b2 && k1 == k2 -#define HASH_STREAM_FN(b,k) ptr_hash(b) ^ u32_hash(k) +#define HASH_STREAM_EQ(k1,k2) ((k1)->channel_id == (k2)->channel_id) && ((k1)->afi == (k2)->afi) && ((k1)->mode == (k2)->mode) +#define HASH_STREAM_FN(k) u32_hash((k)->channel_id) ^ u32_hash((k)->afi) ^ u32_hash((k)->mode) #define HASH_TABLE_KEY(n) n->table #define HASH_TABLE_NEXT(n) n->next @@ -107,7 +104,7 @@ struct bmp_peer_hdr_info { u32 as; u32 id; bool global; - bool policy; + enum bmp_stream_policy policy; bool no_as4; btime timestamp; }; @@ -220,8 +217,6 @@ static void bmp_send_peer_up_notif_msg(struct bmp_proto *p, ea_list *bgp, const adata *tx_data, const adata *rx_data, struct bgp_conn_sk_ad *sk); -static void bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_stream *bs); - // Stores TX data struct bmp_tx_buffer { struct bmp_tx_buffer *next; @@ -463,7 +458,7 @@ bmp_put_per_peer_hdr(buffer *stream, const struct bmp_peer_hdr_info *peer) u8 peer_flags = (ipa_is_ip6(peer->address) ? BMP_PEER_FLAG_V_IPV6 : 0) | - (peer->policy ? BMP_PEER_FLAG_L_POLICY : 0) | + ((peer->policy == BMP_STREAM_POST_POLICY) ? BMP_PEER_FLAG_L_POLICY : 0) | (peer->no_as4 ? BMP_PEER_FLAG_A_NO_AS4 : 0); u32 ts_sec = peer->timestamp TO_S; @@ -601,21 +596,13 @@ bmp_get_table(struct bmp_proto *p, rtable *tab) * BMP streams */ -static inline u32 bmp_stream_key(u32 afi, bool policy) -{ return afi ^ (policy ? BMP_STREAM_KEY_POLICY : 0); } - -static inline bool bmp_stream_policy(struct bmp_stream *bs) -{ return !!(bs->key & BMP_STREAM_KEY_POLICY); } - static struct bmp_stream * -bmp_find_stream(struct bmp_proto *p, const struct bgp_proto *bgp, u32 afi, bool policy) +bmp_find_stream(struct bmp_proto *p, struct bmp_stream_info *bsi) { - ea_list *bgp_attr = proto_get_state(bgp->p.id); - - while (1) + while (true) { /* Is there a stream? */ - struct bmp_stream *s = HASH_FIND(p->stream_map, HASH_STREAM, bgp_attr, bmp_stream_key(afi, policy)); + struct bmp_stream *s = HASH_FIND(p->stream_map, HASH_STREAM, bsi); if (s) return s; @@ -632,22 +619,15 @@ bmp_find_stream(struct bmp_proto *p, const struct bgp_proto *bgp, u32 afi, bool } static struct bmp_stream * -bmp_add_stream(struct bmp_proto *p, struct bmp_peer *bp, u32 afi, bool policy, rtable *tab, ea_list *sender, int in_pre_policy) +bmp_add_stream(struct bmp_proto *p, struct bmp_peer *bp, struct bmp_table *bt, const struct bmp_stream_info *bsi) { struct bmp_stream *bs = mb_allocz(p->p.pool, sizeof(struct bmp_stream)); - bs->bgp = bp->bgp; - bs->key = bmp_stream_key(afi, policy); + bs->info = *bsi; + bmp_table_stream_add_tail(&bt->streams, bs); bmp_peer_stream_add_tail(&bp->streams, bs); HASH_INSERT(p->stream_map, HASH_STREAM, bs); - struct bmp_table *bt = bmp_get_table(p, tab); - bmp_table_stream_add_tail(&bt->streams, bs); - - bs->sender = sender; - bs->sync = false; - bs->in_pre_policy = in_pre_policy; - return bs; } @@ -671,58 +651,63 @@ bmp_remove_stream(struct bmp_proto *p, struct bmp_stream *bs) */ static struct bmp_peer * -bmp_find_peer(struct bmp_proto *p, ea_list *bgp_attr) +bmp_find_peer(struct bmp_proto *p, const struct bmp_peer_info *bpi) { - return HASH_FIND(p->peer_map, HASH_PEER, bgp_attr); + return HASH_FIND(p->peer_map, HASH_PEER, bpi->proto_id); } static struct bmp_peer * -bmp_add_peer(struct bmp_proto *p, ea_list *bgp_attr) +bmp_add_peer(struct bmp_proto *p, struct bmp_peer_info *bpi, ea_list **cached_channels) { - struct bmp_peer *bp; - if (DG_IS_LOCKED(p->p.pool->domain)) - bp = mb_allocz(p->p.pool, sizeof(struct bmp_peer)); - else - { - DG_LOCK(p->p.pool->domain); - bp = mb_allocz(p->p.pool, sizeof(struct bmp_peer)); - DG_UNLOCK(p->p.pool->domain); - } - bp->bgp = bgp_attr; - - bp->streams = (TLIST_LIST(bmp_peer_stream)) {}; - + struct bmp_peer *bp = mb_allocz(p->p.pool, sizeof(struct bmp_peer)); + bp->info = *bpi; + ea_ref(bpi->proto_state); HASH_INSERT(p->peer_map, HASH_PEER, bp); - const adata *channels_adata = ea_get_adata(bgp_attr, &ea_proto_channel_list); - int id_count = channels_adata->length / sizeof(u32); - u32 *chann_ids = (u32 *) channels_adata->data; + const adata *channels_adata = ea_get_adata(bpi->proto_state, &ea_proto_channel_list); - for (int i = 0; i < id_count; i++) + if (!cached_channels) { - ea_list *chan_attr; - PST_LOCKED(ts) - chan_attr = ts->channel_states[chann_ids[i]]; + u32 max_channel_id; + ASSERT_DIE(int_set_max(channels_adata, &max_channel_id)); + cached_channels = tmp_alloc((max_channel_id + 1) * sizeof(ea_list *)); - if (chan_attr == NULL) + PST_LOCKED(ts) + for (u32 pos = 0, val; int_set_walk(channels_adata, &pos, &val); ) + { + ASSERT_DIE(val < ts->channels_len); + cached_channels[val] = ts->channel_states[val] ? ea_ref_tmp(ts->channel_states[val]) : NULL; + } + } + + struct bmp_stream_info bsi; + for (u32 pos = 0; int_set_walk(channels_adata, &pos, &bsi.channel_id); ) + { + if (!(bsi.channel_state = cached_channels[bsi.channel_id])) continue; - rtable *ch_table = (rtable *) ea_get_ptr(chan_attr, &ea_rtable, 0); - int in_keep = ea_get_int(chan_attr, &ea_in_keep, 0); + bsi.afi = ea_get_int(bsi.channel_state, &ea_bgp_afi, 0); + bsi.channel_name = ea_get_adata(bsi.channel_state, &ea_name)->data; - if (p->monitoring_rib.in_pre_policy && ch_table) + struct bmp_table *bt = bmp_get_table(p, ea_get_ptr(bsi.channel_state, &ea_rtable, NULL)); + + if (p->monitoring_rib.in_pre_policy) { - if (in_keep == RIK_PREFILTER) - bmp_add_stream(p, bp, ea_get_int(chan_attr, &ea_bgp_afi, 0), false, ch_table, chan_attr, 1); + bsi.mode = BMP_STREAM_PRE_POLICY; + if ((ea_get_int(bsi.channel_state, &ea_in_keep, 0) & RIK_PREFILTER) == RIK_PREFILTER) + bmp_add_stream(p, bp, bt, &bsi); else log(L_WARN "%s: Failed to request pre-policy for %s.%s, import table disabled", p->p.name, - ea_get_adata(bgp_attr, &ea_name)->data, - ea_get_adata(chan_attr, &ea_name)->data); + bpi->proto_name, + bsi.channel_name); } - if (p->monitoring_rib.in_post_policy && ch_table) - bmp_add_stream(p, bp, ea_get_int(chan_attr, &ea_bgp_afi, 0), true, ch_table, chan_attr, 0); + if (p->monitoring_rib.in_post_policy) + { + bsi.mode = BMP_STREAM_POST_POLICY; + bmp_add_stream(p, bp, bt, &bsi); + } } return bp; @@ -735,57 +720,62 @@ bmp_remove_peer(struct bmp_proto *p, struct bmp_peer *bp) bmp_remove_stream(p, bs); HASH_REMOVE(p->peer_map, HASH_PEER, bp); + ea_free_later(bp->info.proto_state); mb_free(bp); } static struct bmp_peer * -bmp_peer_up_(struct bmp_proto *p, ea_list *bgp_attr, +bmp_peer_up_(struct bmp_proto *p, struct bmp_peer_info *bpi, ea_list **cached_channels, const adata *tx_open_msg, const adata *rx_open_msg, struct bgp_conn_sk_ad *sk) { if (!p->started) return NULL; - struct bmp_peer *bp = bmp_find_peer(p, bgp_attr); + struct bmp_peer *bp = bmp_find_peer(p, bpi); if (bp) + { + /* Update the locally cached proto_state */ + ea_free_later(bp->info.proto_state); + bp->info.proto_state = ea_ref(bpi->proto_state); return bp; + } - const char *name = ea_get_adata(bgp_attr, &ea_name)->data; - TRACE(D_STATES, "Peer up for %s", name); + TRACE(D_STATES, "Peer up for %s", bpi->proto_name); - bp = bmp_add_peer(p, bgp_attr); + bp = bmp_add_peer(p, bpi, cached_channels); - bmp_send_peer_up_notif_msg(p, bgp_attr, tx_open_msg, rx_open_msg, sk); + bmp_send_peer_up_notif_msg(p, bpi->proto_state, tx_open_msg, rx_open_msg, sk); return bp; } static struct bmp_peer * -bmp_peer_up_inout(struct bmp_proto *p, ea_list *bgp_attr) +bmp_peer_up_inout(struct bmp_proto *p, struct bmp_peer_info *bpi, ea_list **cached_channels) { - int in_state = ea_get_int(bgp_attr, &ea_bgp_in_conn_state, 0); - int out_state = ea_get_int(bgp_attr, &ea_bgp_out_conn_state, 0); + int in_state = ea_get_int(bpi->proto_state, &ea_bgp_in_conn_state, 0); + int out_state = ea_get_int(bpi->proto_state, &ea_bgp_out_conn_state, 0); if (in_state == BS_ESTABLISHED) { ASSERT_DIE(out_state != BS_ESTABLISHED); - const adata *loc_open = ea_get_adata(bgp_attr, &ea_bgp_in_conn_local_open_msg); - const adata *rem_open = ea_get_adata(bgp_attr, &ea_bgp_in_conn_remote_open_msg); - SKIP_BACK_DECLARE(struct bgp_conn_sk_ad, sk, ad, ea_get_adata(bgp_attr, &ea_bgp_in_conn_sk)); + const adata *loc_open = ea_get_adata(bpi->proto_state, &ea_bgp_in_conn_local_open_msg); + const adata *rem_open = ea_get_adata(bpi->proto_state, &ea_bgp_in_conn_remote_open_msg); + SKIP_BACK_DECLARE(struct bgp_conn_sk_ad, sk, ad, ea_get_adata(bpi->proto_state, &ea_bgp_in_conn_sk)); ASSERT_DIE(loc_open && rem_open); - return bmp_peer_up_(p, bgp_attr, loc_open, rem_open, sk); + return bmp_peer_up_(p, bpi, cached_channels, loc_open, rem_open, sk); } if (out_state == BS_ESTABLISHED) { - const adata *loc_open = ea_get_adata(bgp_attr, &ea_bgp_out_conn_local_open_msg); - const adata *rem_open = ea_get_adata(bgp_attr, &ea_bgp_out_conn_remote_open_msg); - SKIP_BACK_DECLARE(struct bgp_conn_sk_ad, sk, ad, ea_get_adata(bgp_attr, &ea_bgp_out_conn_sk)); + const adata *loc_open = ea_get_adata(bpi->proto_state, &ea_bgp_out_conn_local_open_msg); + const adata *rem_open = ea_get_adata(bpi->proto_state, &ea_bgp_out_conn_remote_open_msg); + SKIP_BACK_DECLARE(struct bgp_conn_sk_ad, sk, ad, ea_get_adata(bpi->proto_state, &ea_bgp_out_conn_sk)); ASSERT_DIE(loc_open && rem_open); - return bmp_peer_up_(p, bgp_attr, loc_open, rem_open, sk); + return bmp_peer_up_(p, bpi, cached_channels, loc_open, rem_open, sk); } return NULL; @@ -825,19 +815,14 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, ea_list *bgp, } static void -bmp_route_monitor_notify(struct bmp_proto *p, struct bgp_proto *bgp_p, u32 afi, bool policy, const rte *new, ea_list *old) +bmp_route_monitor_notify(struct bmp_proto *p, struct bmp_peer *bp, struct bmp_stream *bs, const rte *new, ea_list *old) { /* Idempotent update */ if ((old == new->attrs) || old && new->attrs && ea_same(old, new->attrs)) return; - /* No stream, probably flushed already */ - struct bmp_stream *bs = bmp_find_stream(p, bgp_p, afi, policy); - if (!bs) - return; - - ea_list *bgp = bs->bgp; - ea_list *c = bs->sender; + ea_list *bgp = bp->info.proto_state; + ea_list *c = bs->info.channel_state; btime delta_t = new ? current_time() - new->lastmod : 0; @@ -846,7 +831,7 @@ bmp_route_monitor_notify(struct bmp_proto *p, struct bgp_proto *bgp_p, u32 afi, .as = ea_get_int(bgp, &ea_bgp_rem_as, 0), .id = ea_get_int(bgp, &ea_bgp_rem_id, 0), .global = bmp_is_peer_global_instance(bgp), - .policy = bmp_stream_policy(bs), + .policy = bs->info.mode, .timestamp = current_real_time() - delta_t, }; @@ -855,7 +840,7 @@ bmp_route_monitor_notify(struct bmp_proto *p, struct bgp_proto *bgp_p, u32 afi, bmp_put_per_peer_hdr(&msg, &peer); bmp_buffer_need(&msg, BGP_MAX_EXT_MSG_LENGTH); - byte *pos = bgp_bmp_encode_rte(c, bgp_p, msg.pos + BGP_HEADER_LENGTH, msg.end, new); + byte *pos = bgp_bmp_encode_rte(c, msg.pos + BGP_HEADER_LENGTH, msg.end, new); if (!pos) { log(L_WARN "%s: Cannot encode update for %N", p->p.name, new->net); @@ -869,17 +854,17 @@ bmp_route_monitor_notify(struct bmp_proto *p, struct bgp_proto *bgp_p, u32 afi, } static void -bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_stream *bs) +bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_peer *bp, struct bmp_stream *bs) { - ea_list *bgp = bs->bgp; - ea_list *c = bs->sender; + ea_list *bgp = bp->info.proto_state; + ea_list *c = bs->info.channel_state; struct bmp_peer_hdr_info peer = { .address = ea_get_ip(bgp, &ea_bgp_rem_ip, IPA_NONE), .as = ea_get_int(bgp, &ea_bgp_rem_as, 0), .id = ea_get_int(bgp, &ea_bgp_rem_id, 0), .global = bmp_is_peer_global_instance(bgp), - .policy = bmp_stream_policy(bs), + .policy = bs->info.mode, .timestamp = current_real_time(), }; @@ -920,7 +905,7 @@ bmp_send_peer_down_notif_msg(struct bmp_proto *p, ea_list *bgp, .as = ea_get_int(bgp, &ea_bgp_rem_as, 0), .id = ea_get_int(bgp, &ea_bgp_rem_id, 0), .global = bmp_is_peer_global_instance(bgp), - .policy = false, // Hardcoded pre-policy Adj-RIB-In + .policy = BMP_STREAM_PRE_POLICY, // Hardcoded pre-policy Adj-RIB-In .no_as4 = !as4_session, .timestamp = 0, // No timestamp provided }; @@ -931,16 +916,16 @@ bmp_send_peer_down_notif_msg(struct bmp_proto *p, ea_list *bgp, } static void -bmp_peer_down_(struct bmp_proto *p, ea_list *bgp, struct bgp_session_close_ad *bscad) +bmp_peer_down_(struct bmp_proto *p, struct bmp_peer_info *bpi, struct bgp_session_close_ad *bscad) { if (!p->started) return; - struct bmp_peer *bp = bmp_find_peer(p, bgp); + struct bmp_peer *bp = bmp_find_peer(p, bpi); if (!bp) return; - TRACE(D_STATES, "Peer down for %s", ea_find(bgp, &ea_name)->u.ad->data); + TRACE(D_STATES, "Peer down for %s", bpi->proto_name); struct bmp_peer_down_info info = { .err_code = bscad->notify_code, @@ -967,7 +952,7 @@ bmp_peer_down_(struct bmp_proto *p, ea_list *bgp, struct bgp_session_close_ad *b break; } - bmp_send_peer_down_notif_msg(p, bgp, &info); + bmp_send_peer_down_notif_msg(p, bpi->proto_state, &info); bmp_remove_peer(p, bp); } @@ -999,26 +984,39 @@ bmp_split_policy(struct bmp_proto *p, const rte *new, const rte *old) { rte loc = *(new ?: old); - struct proto *rte_proto = (struct proto*) SKIP_BACK(struct proto, sources, loc.src->owner); - struct bgp_proto *bgp = (struct bgp_proto *) rte_proto; - struct bgp_channel *src_ch = SKIP_BACK(struct bgp_channel, c.in_req, loc.sender->req); - /* Ignore piped routes */ - if (src_ch->c.proto != rte_proto) + if (loc.generation) return; /* Ignore non-BGP routes */ - if (rte_proto->proto != &proto_bgp) + if (rt_get_source_attr(&loc) != RTS_BGP) return; + /* Get the protocol and channel information. Here we _can_ access + * the protocol and channel structures but only to read the ID. */ + SKIP_BACK_DECLARE(struct channel, c, in_req, loc.sender->req); + struct bmp_peer_info bpi = { + .proto_id = c->proto->id, + }; + struct bmp_peer *bp = bmp_find_peer(p, &bpi); + + struct bmp_stream_info bsi = { + .channel_id = c->id, + }; + /* Checking the pre policy */ if (p->monitoring_rib.in_pre_policy) { - /* Compute the pre policy attributes */ + /* Compute the pre policy route attributes */ loc.attrs = new ? ea_strip_to(new->attrs, BIT32_ALL(EALS_PREIMPORT)) : NULL; ea_list *old_attrs = old ? ea_strip_to(old->attrs, BIT32_ALL(EALS_PREIMPORT)) : NULL; - bmp_route_monitor_notify(p, bgp, src_ch->afi, false, &loc, old_attrs); + bsi.mode = BMP_STREAM_PRE_POLICY; + struct bmp_stream *bs = bmp_find_stream(p, &bsi); + if (!bs) + return; + + bmp_route_monitor_notify(p, bp, bs, &loc, old_attrs); } /* Checking the post policy */ @@ -1028,7 +1026,12 @@ bmp_split_policy(struct bmp_proto *p, const rte *new, const rte *old) loc.attrs = new ? ea_normalize(new->attrs, 0) : NULL; ea_list *old_attrs = old ? ea_normalize(old->attrs, 0) : NULL; - bmp_route_monitor_notify(p, bgp, src_ch->afi, true, &loc, old_attrs); + bsi.mode = BMP_STREAM_POST_POLICY; + struct bmp_stream *bs = bmp_find_stream(p, &bsi); + if (!bs) + return; + + bmp_route_monitor_notify(p, bp, bs, &loc, old_attrs); } } @@ -1075,19 +1078,17 @@ bmp_feed_end(struct rt_export_request *req) * Unsynced streams are added in one moment during BMP session establishment, * therefore we can assume that all unsynced streams (for given channel) * already received full feed now and are synced. - * - * TODO: Use more efficent way to find bmp_stream from bmp_table */ - HASH_WALK(p->stream_map, next, bs) + WALK_TLIST(bmp_table_stream, bs, &bt->streams) { - if ((bmp_table_stream_enlisted(bs) == &bt->streams) && !bs->sync) + if (!bs->sync) { - bmp_route_monitor_end_of_rib(p, bs); + SKIP_BACK_DECLARE(struct bmp_peer, bp, streams, bmp_peer_stream_enlisted(bs)); + bmp_route_monitor_end_of_rib(p, bp, bs); bs->sync = true; } } - HASH_WALK_END; } @@ -1114,11 +1115,6 @@ bmp_startup(struct bmp_proto *p) bmp_init_msg_serialize(&payload, p->sys_descr, p->sys_name); bmp_schedule_tx_packet(p, &payload); - /* Send Peer Up messages */ - u32 length; - PST_LOCKED(ts) /* The size of protos field will never decrease, the inconsistency caused by growing is not important */ - length = ts->proto_len; - /* Subscribe to protocol state changes */ p->proto_state_reader = (struct lfjour_recipient) { .event = &p->proto_state_changed, @@ -1133,19 +1129,55 @@ bmp_startup(struct bmp_proto *p) proto_states_subscribe(&p->proto_state_reader); /* Load protocol states */ - for (u32 i = 0; i < length; i++) + u32 max_proto_id, max_channel_id; + PST_LOCKED(tp) { - ea_list *proto_attr = proto_get_state(i); - if (proto_attr == NULL) - continue; + max_proto_id = tp->proto_len; + max_channel_id = tp->channels_len; + } - struct protocol *proto = (struct protocol *) ea_get_ptr(proto_attr, &ea_protocol_type, 0); - const int state = ea_get_int(proto_attr, &ea_state, 0); + /* We can unlock here as the states array never shrinks + * and growing will be resolved by reading the journal. */ - if (proto != &proto_bgp || state != PS_UP) - continue; + u32 *protos_picked = tmp_allocz(BIRD_ALIGN(max_proto_id, 32) * sizeof *protos_picked); - bmp_peer_up_inout(p, proto_attr); + /* Copy relevant protocol states */ + ea_list **pst = tmp_alloc(max_proto_id * sizeof *pst); + uint *proto_ids = tmp_alloc(max_proto_id * sizeof *proto_ids); + u32 pst_count = 0; + + ea_list **cst = tmp_alloc(max_channel_id * sizeof *cst); + + PST_LOCKED(ts) + { + for (u32 i = 0; i < max_proto_id; i++) + if (ea_get_ptr(ts->proto_states[i], &ea_protocol_type, NULL) == &proto_bgp) + { + BIT32_SET(protos_picked, i); + pst[pst_count] = ea_ref_tmp(ts->proto_states[i]); + proto_ids[pst_count] = i; + pst_count++; + } + for (u32 i = 0; i < max_channel_id; i++) + { + u32 proto_id = ea_get_int(ts->channel_states[i], &ea_proto_id, 0); + if (BIT32_TEST(protos_picked, proto_id)) + cst[i] = ea_ref_tmp(ts->channel_states[i]); + else + cst[i] = NULL; + } + } + + /* Send Peer Up messages */ + for (u32 i = 0; i < pst_count; i++) + { + struct bmp_peer_info bpi = { + .proto_state = pst[i], + .proto_id = proto_ids[i], + .proto_name = ea_get_adata(pst[i], &ea_name)->data, + }; + + bmp_peer_up_inout(p, &bpi, cst); } } @@ -1331,11 +1363,18 @@ bmp_postconfig(struct proto_config *CF) static void bmp_process_proto_state_change(struct bmp_proto *p, struct lfjour_item *last_up) { - struct proto_pending_update *ppu = SKIP_BACK(struct proto_pending_update, li, last_up); - if (!ppu) + if (!last_up) return; - struct bmp_peer *bp = bmp_peer_up_inout(p, ppu->new); + SKIP_BACK_DECLARE(struct proto_pending_update, ppu, li, last_up); + + struct bmp_peer_info bpi = { + .proto_state = ppu->new, + .proto_id = ea_get_int(ppu->new, &ea_proto_id, 0), + .proto_name = ea_get_adata(ppu->new, &ea_name)->data, + }; + + struct bmp_peer *bp = bmp_peer_up_inout(p, &bpi, NULL); if (bp) { /* @@ -1345,7 +1384,7 @@ bmp_process_proto_state_change(struct bmp_proto *p, struct lfjour_item *last_up) */ WALK_TLIST(bmp_peer_stream, bs, &bp->streams) { - bmp_route_monitor_end_of_rib(p, bs); + bmp_route_monitor_end_of_rib(p, bp, bs); bs->sync = true; } @@ -1355,7 +1394,7 @@ bmp_process_proto_state_change(struct bmp_proto *p, struct lfjour_item *last_up) /* This was not a peer-up notification. It may be peer down tho. */ const adata *bscad = ea_get_adata(ppu->new, &ea_bgp_close_bmp); if (bscad) - bmp_peer_down_(p, ppu->new, SKIP_BACK(struct bgp_session_close_ad, ad, bscad)); + bmp_peer_down_(p, &bpi, SKIP_BACK(struct bgp_session_close_ad, ad, bscad)); } static void diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 283c74d0..63ece572 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -18,7 +18,6 @@ #include "lib/hash.h" #include "lib/socket.h" #include "proto/bgp/bgp.h" -#include "proto/bmp/map.h" // Max length of MIB-II description object #define MIB_II_STR_LEN 255 @@ -53,10 +52,6 @@ struct bmp_config { uint tx_pending_limit; // Maximum on pending TX buffer count }; -/* Forward declarations */ -struct bgp_proto; -struct bmp_proto; - struct bmp_proto { struct proto p; // Parent proto const struct bmp_config *cf; // Shortcut to BMP configuration @@ -75,7 +70,6 @@ struct bmp_proto { u16 station_port; // Monitoring station TCP port struct monitoring_rib monitoring_rib; // Below fields are for internal use - // struct bmp_peer_map bgp_peers; // Stores 'bgp_proto' structure per BGP peer struct bmp_tx_buffer *tx_pending;// This buffer waits for socket to flush struct bmp_tx_buffer *tx_last; // This buffer is the last to flush uint tx_pending_count; // How many buffers waiting for flush @@ -95,13 +89,19 @@ struct bmp_proto { struct bmp_stream { TLIST_NODE(bmp_peer_stream, struct bmp_stream) peer_node; TLIST_NODE(bmp_table_stream, struct bmp_stream) table_node; - ea_list *bgp; - u32 key; bool sync; bool shutting_down; struct bmp_stream *next; - ea_list *sender; - int in_pre_policy; + struct bmp_stream_info { + u32 channel_id; + ea_list *channel_state; + const char *channel_name; + u32 afi; + enum bmp_stream_policy { + BMP_STREAM_PRE_POLICY = 1, + BMP_STREAM_POST_POLICY, + } mode; + } info; }; #define TLIST_PREFIX bmp_peer_stream @@ -119,8 +119,12 @@ struct bmp_stream { #include "lib/tlists.h" struct bmp_peer { - ea_list *bgp; struct bmp_peer *next; + struct bmp_peer_info { + u32 proto_id; + ea_list *proto_state; + const char *proto_name; + } info; TLIST_LIST(bmp_peer_stream) streams; }; @@ -134,30 +138,4 @@ struct bmp_table { TLIST_LIST(bmp_table_stream) streams; }; - -#ifdef CONFIG_BMP - -/** - * bmp_peer_up - send notification that BGP peer connection is established - */ -void -bmp_peer_up(struct ea_list *bgp, - const byte *tx_open_msg, uint tx_open_length, - const byte *rx_open_msg, uint rx_open_length); - -/** - * bmp_peer_down - send notification that BGP peer connection is not in - * established state - */ -void -bmp_peer_down(const struct bgp_proto *bgp, int err_class, int code, int subcode, const byte *data, int length); - - -#else /* BMP build disabled */ - -static inline void bmp_peer_up(struct bgp_proto *bgp UNUSED, const byte *tx_open_msg UNUSED, uint tx_open_length UNUSED, const byte *rx_open_msg UNUSED, uint rx_open_length UNUSED) { } -static inline void bmp_peer_down(const struct bgp_proto *bgp UNUSED, const int err_class UNUSED, int code UNUSED, int subcode UNUSED, const byte *data UNUSED, int length UNUSED) { } - -#endif /* CONFIG_BMP */ - #endif /* _BIRD_BMP_H_ */ diff --git a/proto/bmp/map.c b/proto/bmp/map.c deleted file mode 100644 index 16e714fd..00000000 --- a/proto/bmp/map.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * BIRD -- The BGP Monitoring Protocol (BMP) - * - * (c) 2020 Akamai Technologies, Inc. (Pawel Maslanka, pmaslank@akamai.com) - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include "proto/bmp/map.h" - -/* Peer Index Table */ -#define PEER_KEY(n) (n)->peer_as, (n)->peer_ip -#define PEER_NEXT(n) (n)->next -#define PEER_EQ(as1,ip1,as2,ip2) \ - (as1) == (as2) && ipa_equal(ip1, ip2) -#define PEER_FN(as,ip) ipa_hash(ip) - -#define PEER_REHASH bmp_peer_rehash -#define PEER_PARAMS /8, *2, 2, 2, 6, 20 - -HASH_DEFINE_REHASH_FN(PEER, struct bmp_peer_map_key) - -#define PEER_INIT_ORDER 6 - -void -bmp_peer_map_init(struct bmp_peer_map *map, pool *mpool) -{ - map->mpool = mpool; - HASH_INIT(map->peer_hash, map->mpool, PEER_INIT_ORDER); -} - -struct bmp_peer_map_key -bmp_peer_map_key_create(const ip_addr peer_ip, const u32 peer_as) -{ - struct bmp_peer_map_key key; - key.next = NULL; - key.peer_ip = peer_ip; - key.peer_as = peer_as; - - return key; -} - -void -bmp_peer_map_flush(struct bmp_peer_map *map) -{ - struct bmp_peer_map_entry *entry; - HASH_WALK_DELSAFE(map->peer_hash, next, e) - { - entry = (struct bmp_peer_map_entry *) e; - mb_free(entry->data.buf); - HASH_DELETE(map->peer_hash, PEER, PEER_KEY(&entry->key)); - mb_free(entry); - } - HASH_WALK_DELSAFE_END; - - HASH_MAY_RESIZE_DOWN(map->peer_hash, PEER, map->mpool); -} - -void -bmp_peer_map_free(struct bmp_peer_map *map) -{ - bmp_peer_map_flush(map); - HASH_FREE(map->peer_hash); -} - -void -bmp_peer_map_insert(struct bmp_peer_map *map, const struct bmp_peer_map_key key, - const byte *data, const size_t data_size) -{ - struct bmp_peer_map_entry *entry - = (void *) HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key)); - - if (entry) - { - mb_free(entry->data.buf); - entry->data.buf = mb_alloc(map->mpool, data_size); - memcpy(entry->data.buf, data, data_size); - entry->data.buf_size = data_size; - return; - } - - entry = mb_alloc(map->mpool, sizeof (struct bmp_peer_map_entry)); - entry->data.buf = mb_alloc(map->mpool, data_size); - memcpy(entry->data.buf, data, data_size); - entry->data.buf_size = data_size; - entry->key = key; - HASH_INSERT2(map->peer_hash, PEER, map->mpool, &entry->key); -} - -void -bmp_peer_map_remove(struct bmp_peer_map *map, const struct bmp_peer_map_key key) -{ - struct bmp_peer_map_entry *entry - = (void *) HASH_DELETE(map->peer_hash, PEER, PEER_KEY(&key)); - - if (!entry) - return; - - mb_free(entry->data.buf); - mb_free(entry); -} - -const struct bmp_peer_map_entry * -bmp_peer_map_get(struct bmp_peer_map *map, const struct bmp_peer_map_key key) -{ - return (struct bmp_peer_map_entry *) HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key)); -} - -void -bmp_peer_map_walk(const struct bmp_peer_map *map, bmp_peer_map_walk_action action, void *arg) -{ - struct bmp_peer_map_entry *entry; - HASH_WALK_FILTER(map->peer_hash, next, e, _) - { - entry = (struct bmp_peer_map_entry *) e; - action(entry->key, entry->data.buf, entry->data.buf_size, arg); - } - HASH_WALK_FILTER_END; -} diff --git a/proto/bmp/map.h b/proto/bmp/map.h deleted file mode 100644 index 8e7ea695..00000000 --- a/proto/bmp/map.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * BIRD -- The BGP Monitoring Protocol (BMP) - * - * (c) 2020 Akamai Technologies, Inc. (Pawel Maslanka, pmaslank@akamai.com) - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -/** - * This map implementation binds peer IP address as container key with custom data. - */ -#ifndef _BIRD_BMP_MAP_H_ -#define _BIRD_BMP_MAP_H_ - -#include "nest/bird.h" -#include "lib/hash.h" -#include "lib/resource.h" - -struct bmp_peer_map_key { - struct bmp_peer_map_key *next; - ip_addr peer_ip; - u32 peer_as; -}; - -struct bmp_peer_map_data { - void *buf; - size_t buf_size; -}; - -struct bmp_peer_map_entry { - struct bmp_peer_map_key key; - struct bmp_peer_map_data data; -}; - -struct bmp_peer_map { - pool *mpool; // Memory pool for peer entries in peer_hash - HASH(struct bmp_peer_map_key) peer_hash; // Hash for peers to find the index -}; - -void -bmp_peer_map_init(struct bmp_peer_map *map, pool *mpool); - -struct bmp_peer_map_key -bmp_peer_map_key_create(const ip_addr peer_ip, const u32 peer_as); - -void -bmp_peer_map_free(struct bmp_peer_map *map); - -void -bmp_peer_map_flush(struct bmp_peer_map *map); - -void -bmp_peer_map_insert(struct bmp_peer_map *map, const struct bmp_peer_map_key key, - const byte *data, const size_t data_size); - -void -bmp_peer_map_remove(struct bmp_peer_map *map, const struct bmp_peer_map_key key); - -const struct bmp_peer_map_entry * -bmp_peer_map_get(struct bmp_peer_map *map, const struct bmp_peer_map_key key); - -typedef void (*bmp_peer_map_walk_action)(const struct bmp_peer_map_key key, - const byte *data, const size_t data_size, void *arg); - -void -bmp_peer_map_walk(const struct bmp_peer_map *map, bmp_peer_map_walk_action action, void *arg); - -#endif /* _BIRD_BMP_MAP_H_ */