diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2023-08-22 15:28:05 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2023-08-22 15:28:05 +0200 |
commit | 5121101136cb80151a9361c63dc4822afeb44eef (patch) | |
tree | 2bcf923fe58bf38386ee4693882d5a09e9a40648 | |
parent | d2dbe854631813eae9fbf3e264ced4460ea4c432 (diff) | |
parent | 4558adabfbbe3696156d20767168010d6238f434 (diff) |
Merge branch 'bmp'
-rw-r--r-- | nest/proto.c | 6 | ||||
-rw-r--r-- | nest/protocol.h | 7 | ||||
-rw-r--r-- | nest/rt-table.c | 71 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 40 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 11 | ||||
-rw-r--r-- | proto/bgp/packets.c | 84 | ||||
-rw-r--r-- | proto/bmp/README.txt | 4 | ||||
-rw-r--r-- | proto/bmp/bmp.c | 929 | ||||
-rw-r--r-- | proto/bmp/bmp.h | 110 | ||||
-rw-r--r-- | proto/bmp/buffer.c | 25 | ||||
-rw-r--r-- | proto/bmp/config.Y | 11 |
11 files changed, 757 insertions, 541 deletions
diff --git a/nest/proto.c b/nest/proto.c index 885a0b75..a5325705 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -179,6 +179,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf) c->merge_limit = cf->merge_limit; c->in_keep_filtered = cf->in_keep_filtered; c->rpki_reload = cf->rpki_reload; + c->bmp_hack = cf->bmp_hack; c->channel_state = CS_DOWN; c->export_state = ES_DOWN; @@ -523,7 +524,7 @@ channel_setup_in_table(struct channel *c) cf->addr_type = c->net_type; cf->internal = 1; - c->in_table = rt_setup(c->proto->pool, cf); + c->in_table = cf->table = rt_setup(c->proto->pool, cf); c->reload_event = ev_new_init(c->proto->pool, channel_reload_loop, c); } @@ -574,7 +575,8 @@ channel_do_up(struct channel *c) static void channel_do_flush(struct channel *c) { - rt_schedule_prune(c->table); + if (!c->bmp_hack) + rt_schedule_prune(c->table); c->gr_wait = 0; if (c->gr_lock) diff --git a/nest/protocol.h b/nest/protocol.h index da6d434e..dad0b781 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -214,7 +214,6 @@ struct proto { void (*if_notify)(struct proto *, unsigned flags, struct iface *i); void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a); void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old); - void (*rte_update_in_notify)(struct channel *, const net_addr *, const struct rte *, const struct rte_src *); void (*neigh_notify)(struct neighbor *neigh); int (*preexport)(struct channel *, struct rte *rt); void (*reload_routes)(struct channel *); @@ -477,7 +476,8 @@ struct channel_class { #endif }; -extern struct channel_class channel_bgp; +extern const struct channel_class channel_basic; +extern const struct channel_class channel_bgp; struct channel_config { node n; @@ -500,6 +500,7 @@ struct channel_config { u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */ u8 in_keep_filtered; /* Routes rejected in import filter are kept */ u8 rpki_reload; /* RPKI changes trigger channel reload */ + u8 bmp_hack; /* No flush */ }; struct channel { @@ -552,6 +553,7 @@ struct channel { u8 reload_pending; /* Reloading and another reload is scheduled */ u8 refeed_pending; /* Refeeding and another refeed is scheduled */ u8 rpki_reload; /* RPKI changes trigger channel reload */ + u8 bmp_hack; /* No flush */ struct rtable *out_table; /* Internal table for exported routes */ @@ -620,6 +622,7 @@ static inline struct channel_config *proto_cf_main_channel(struct proto_config * struct channel *proto_find_channel_by_table(struct proto *p, struct rtable *t); struct channel *proto_find_channel_by_name(struct proto *p, const char *n); struct channel *proto_add_channel(struct proto *p, struct channel_config *cf); +void proto_remove_channel(struct proto *p, struct channel *c); int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf); void channel_set_state(struct channel *c, uint state); diff --git a/nest/rt-table.c b/nest/rt-table.c index 2b065032..23c4bbb2 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2148,11 +2148,11 @@ rt_setup(pool *pp, struct rtable_config *cf) init_list(&t->flowspec_links); init_list(&t->subscribers); + hmap_init(&t->id_map, p, 1024); + hmap_set(&t->id_map, 0); + if (!(t->internal = cf->internal)) { - hmap_init(&t->id_map, p, 1024); - hmap_set(&t->id_map, 0); - t->rt_event = ev_new_init(p, rt_event, t); t->prune_timer = tm_new_init(p, rt_prune_timer, t, 0, 0); t->last_rt_change = t->gc_time = current_time(); @@ -3096,9 +3096,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr { old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY); - if (c->proto->rte_update_in_notify) - c->proto->rte_update_in_notify(c, n, old, src); - return 1; } @@ -3111,28 +3108,15 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr /* Remove the old rte */ *pos = old->next; - rte_free_quick(old); tab->rt_count--; - break; } - if (!new) - { - if (!old) - goto drop_withdraw; - - if (!net->routes) - fib_delete(&tab->fib, net); - - if (c->proto->rte_update_in_notify) - c->proto->rte_update_in_notify(c, n, NULL, src); - - return 1; - } + if (!old && !new) + goto drop_withdraw; struct channel_limit *l = &c->rx_limit; - if (l->action && !old) + if (l->action && !old && new) { if (tab->rt_count >= l->limit) channel_notify_limit(c, l, PLD_RX, tab->rt_count); @@ -3147,18 +3131,39 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr } } - /* Insert the new rte */ - rte *e = rte_do_cow(new); - e->flags |= REF_COW; - e->net = net; - e->sender = c; - e->lastmod = current_time(); - e->next = *pos; - *pos = e; - tab->rt_count++; + if (new) + { + /* Insert the new rte */ + rte *e = rte_do_cow(new); + e->flags |= REF_COW; + e->net = net; + e->sender = c; + e->lastmod = current_time(); + e->next = *pos; + *pos = new = e; + tab->rt_count++; - if (c->proto->rte_update_in_notify) - c->proto->rte_update_in_notify(c, n, e, src); + if (!old) + { + new->id = hmap_first_zero(&tab->id_map); + hmap_set(&tab->id_map, new->id); + } + else + new->id = old->id; + } + + rte_announce(tab, RA_ANY, net, new, old, NULL, NULL); + + if (old) + { + if (!new) + hmap_clear(&tab->id_map, old->id); + + rte_free_quick(old); + } + + if (!net->routes) + fib_delete(&tab->fib, net); return 1; diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 1ae56397..0a2e8f5a 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -380,10 +380,20 @@ bgp_close_conn(struct bgp_conn *conn) rfree(conn->sk); conn->sk = NULL; + mb_free(conn->local_open_msg); + conn->local_open_msg = NULL; + mb_free(conn->remote_open_msg); + conn->remote_open_msg = NULL; + conn->local_open_length = 0; + conn->remote_open_length = 0; + mb_free(conn->local_caps); conn->local_caps = NULL; mb_free(conn->remote_caps); conn->remote_caps = NULL; + + conn->notify_data = NULL; + conn->notify_size = 0; } @@ -682,10 +692,12 @@ bgp_conn_enter_established_state(struct bgp_conn *conn) bgp_conn_set_state(conn, BS_ESTABLISHED); proto_notify_state(&p->p, PS_UP); + bmp_peer_up(p, conn->local_open_msg, conn->local_open_length, + conn->remote_open_msg, conn->remote_open_length); } static void -bgp_conn_leave_established_state(struct bgp_proto *p) +bgp_conn_leave_established_state(struct bgp_conn *conn, struct bgp_proto *p) { BGP_TRACE(D_EVENTS, "BGP session closed"); p->last_established = current_time(); @@ -693,6 +705,10 @@ bgp_conn_leave_established_state(struct bgp_proto *p) if (p->p.proto_state == PS_UP) bgp_stop(p, 0, NULL, 0); + + bmp_peer_down(p, p->last_error_class, + conn->notify_code, conn->notify_subcode, + conn->notify_data, conn->notify_size); } void @@ -709,7 +725,7 @@ bgp_conn_enter_close_state(struct bgp_conn *conn) bgp_start_timer(conn->hold_timer, 10); if (os == BS_ESTABLISHED) - bgp_conn_leave_established_state(p); + bgp_conn_leave_established_state(conn, p); } void @@ -723,7 +739,7 @@ bgp_conn_enter_idle_state(struct bgp_conn *conn) ev_schedule(p->event); if (os == BS_ESTABLISHED) - bgp_conn_leave_established_state(p); + bgp_conn_leave_established_state(conn, p); } /** @@ -867,10 +883,7 @@ bgp_graceful_restart_timeout(timer *t) } } else - { bgp_stop(p, 0, NULL, 0); - bmp_peer_down(p, BE_NONE, NULL, 0); - } } static void @@ -994,10 +1007,7 @@ bgp_sock_err(sock *sk, int err) if (err) BGP_TRACE(D_EVENTS, "Connection lost (%M)", err); else - { BGP_TRACE(D_EVENTS, "Connection closed"); - bmp_peer_down(p, BE_SOCKET, NULL, 0); - } if ((conn->state == BS_ESTABLISHED) && p->gr_ready) bgp_handle_graceful_restart(p); @@ -1322,7 +1332,6 @@ bgp_neigh_notify(neighbor *n) bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST); /* Perhaps also run bgp_update_startup_delay(p)? */ bgp_stop(p, 0, NULL, 0); - bmp_peer_down(p, BE_MISC, NULL, 0); } } else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP)) @@ -1334,7 +1343,6 @@ bgp_neigh_notify(neighbor *n) if (ps == PS_UP) bgp_update_startup_delay(p); bgp_stop(p, 0, NULL, 0); - bmp_peer_down(p, BE_MISC, NULL, 0); } } else @@ -1376,7 +1384,6 @@ bgp_bfd_notify(struct bfd_request *req) if (ps == PS_UP) bgp_update_startup_delay(p); bgp_stop(p, 0, NULL, 0); - bmp_peer_down(p, BE_MISC, NULL, 0); } } } @@ -1705,10 +1712,6 @@ bgp_init(struct proto_config *CF) P->rte_modify = bgp_rte_modify_stale; P->rte_igp_metric = bgp_rte_igp_metric; -#ifdef CONFIG_BMP - P->rte_update_in_notify = bgp_rte_update_in_notify; -#endif - p->cf = cf; p->is_internal = (cf->local_as == cf->remote_as); p->is_interior = p->is_internal || cf->confederation_member; @@ -2261,12 +2264,13 @@ bgp_error(struct bgp_conn *c, uint code, uint subcode, byte *data, int len) bgp_log_error(p, BE_BGP_TX, "Error", code, subcode, data, ABS(len)); bgp_store_error(p, c, BE_BGP_TX, (code << 16) | subcode); - bgp_conn_enter_close_state(c); c->notify_code = code; c->notify_subcode = subcode; c->notify_data = data; c->notify_size = (len > 0) ? len : 0; + + bgp_conn_enter_close_state(c); bgp_schedule_packet(c, NULL, PKT_NOTIFICATION); if (code != 6) @@ -2634,7 +2638,7 @@ bgp_show_proto_info(struct proto *P) } } -struct channel_class channel_bgp = { +const struct channel_class channel_bgp = { .channel_size = sizeof(struct bgp_channel), .config_size = sizeof(struct bgp_channel_config), .init = bgp_channel_init, diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 0fb375d5..c11433ec 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -287,6 +287,11 @@ struct bgp_conn { u8 ext_messages; /* Session uses extended message length */ u32 received_as; /* ASN received in OPEN message */ + byte *local_open_msg; /* Saved OPEN messages (no header) */ + byte *remote_open_msg; + uint local_open_length; + uint remote_open_length; + struct bgp_caps *local_caps; struct bgp_caps *remote_caps; timer *connect_timer; @@ -487,6 +492,7 @@ struct bgp_parse_state { #define BGP_PORT 179 #define BGP_VERSION 4 #define BGP_HEADER_LENGTH 19 +#define BGP_HDR_MARKER_LENGTH 16 #define BGP_MAX_MESSAGE_LENGTH 4096 #define BGP_MAX_EXT_MSG_LENGTH 65535 #define BGP_RX_BUFFER_SIZE 4096 @@ -625,11 +631,12 @@ struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool); u32 bgp_rte_igp_metric(struct rte *); void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old); int bgp_preexport(struct channel *, struct rte *); -void bgp_rte_update_in_notify(struct channel *C, const net_addr *n, const struct rte *new, const struct rte_src *src); int bgp_get_attr(const struct eattr *e, byte *buf, int buflen); void bgp_get_route_info(struct rte *, byte *buf); int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad); +byte * bgp_bmp_encode_rte(struct bgp_channel *c, byte *buf, const net_addr *n, const struct rte *new, const struct rte_src *src); + #define BGP_AIGP_METRIC 1 #define BGP_AIGP_MAX U64(0xffffffffffffffff) @@ -658,8 +665,8 @@ const char * bgp_error_dsc(unsigned code, unsigned subcode); void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len); void bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to); +byte *bgp_create_end_mark_(struct bgp_channel *c, byte *buf); -byte * bgp_create_end_mark(struct bgp_channel *c, byte *buf); /* Packet types */ diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 66f243bd..ee98115d 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -167,7 +167,6 @@ bgp_create_notification(struct bgp_conn *conn, byte *buf) buf[0] = conn->notify_code; buf[1] = conn->notify_subcode; memcpy(buf+2, conn->notify_data, conn->notify_size); - bmp_peer_down(p, BE_NONE, buf, conn->notify_size + 2); return buf + 2 + conn->notify_size; } @@ -777,6 +776,14 @@ err: } static byte * +bgp_copy_open(struct bgp_proto *p, const byte *pkt, uint len) +{ + char *buf = mb_alloc(p->p.pool, len - BGP_HEADER_LENGTH); + memcpy(buf, pkt + BGP_HEADER_LENGTH, len - BGP_HEADER_LENGTH); + return buf; +} + +static byte * bgp_create_open(struct bgp_conn *conn, byte *buf) { struct bgp_proto *p = conn->bgp; @@ -850,6 +857,9 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len) id = get_u32(pkt+24); BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%R)", asn, hold, id); + conn->remote_open_msg = bgp_copy_open(p, pkt, len); + conn->remote_open_length = len - BGP_HEADER_LENGTH; + if (bgp_read_options(conn, pkt+29, pkt[28], len-29) < 0) return; @@ -981,7 +991,6 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len) bgp_schedule_packet(conn, NULL, PKT_KEEPALIVE); bgp_start_timer(conn->hold_timer, conn->hold_time); bgp_conn_enter_openconfirm_state(conn); - bmp_put_recv_bgp_open_msg(p, pkt, len); } @@ -2419,15 +2428,20 @@ bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck, { struct bgp_proto *p = (void *) c->c.proto; byte *end = buf + (BGP_MAX_EXT_MSG_LENGTH - BGP_HEADER_LENGTH); + byte *res = NULL; /* FIXME: must be a bit shorter */ + struct lp_state tmpp; + lp_save(tmp_linpool, &tmpp); + struct bgp_caps *peer = p->conn->remote_caps; const struct bgp_af_caps *rem = bgp_find_af_caps(peer, c->afi); + struct bgp_write_state s = { .proto = p, .channel = c, .pool = tmp_linpool, - .mp_reach = (c->afi != BGP_AF_IPV4) || rem->ext_next_hop, + .mp_reach = (c->afi != BGP_AF_IPV4) || (rem && rem->ext_next_hop), .as4_session = 1, .add_path = c->add_path_rx, .mpls = c->desc->mpls, @@ -2436,16 +2450,20 @@ bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck, if (!update) { - return !s.mp_reach ? + res = !s.mp_reach ? bgp_create_ip_unreach(&s, buck, buf, end): bgp_create_mp_unreach(&s, buck, buf, end); } else { - return !s.mp_reach ? + res = !s.mp_reach ? bgp_create_ip_reach(&s, buck, buf, end): bgp_create_mp_reach(&s, buck, buf, end); } + + lp_restore(tmp_linpool, &tmpp); + + return res; } static byte * @@ -2458,14 +2476,11 @@ bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type) return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE; } -void -bgp_rte_update_in_notify(struct channel *C, const net_addr *n, - const struct rte *new, const struct rte_src *src) +byte * +bgp_bmp_encode_rte(struct bgp_channel *c, byte *buf, const net_addr *n, + const struct rte *new, const struct rte_src *src) { -// struct bgp_proto *p = (void *) C->proto; - struct bgp_channel *c = (void *) C; - - byte buf[BGP_MAX_EXT_MSG_LENGTH]; +// struct bgp_proto *p = (void *) c->c.proto; byte *pkt = buf + BGP_HEADER_LENGTH; ea_list *attrs = new ? new->attrs->eattrs : NULL; @@ -2489,11 +2504,11 @@ bgp_rte_update_in_notify(struct channel *C, const net_addr *n, add_tail(&b->prefixes, &px->buck_node); byte *end = bgp_create_update_bmp(c, pkt, b, !!new); - if (!end) - return; - bgp_bmp_prepare_bgp_hdr(buf, end - buf, PKT_UPDATE); - bmp_route_monitor_put_update_in_pre_msg(buf, end - buf); + if (end) + bgp_bmp_prepare_bgp_hdr(buf, end - buf, PKT_UPDATE); + + return end; } #endif /* CONFIG_BMP */ @@ -2600,6 +2615,14 @@ bgp_create_mp_end_mark(struct bgp_channel *c, byte *buf) } byte * +bgp_create_end_mark_(struct bgp_channel *c, byte *buf) +{ + return (c->afi == BGP_AF_IPV4) ? + bgp_create_ip_end_mark(c, buf): + bgp_create_mp_end_mark(c, buf); +} + +static byte * bgp_create_end_mark(struct bgp_channel *c, byte *buf) { struct bgp_proto *p = (void *) c->c.proto; @@ -2607,9 +2630,7 @@ bgp_create_end_mark(struct bgp_channel *c, byte *buf) BGP_TRACE(D_PACKETS, "Sending END-OF-RIB"); p->stats.tx_updates++; - return (c->afi == BGP_AF_IPV4) ? - bgp_create_ip_end_mark(c, buf): - bgp_create_mp_end_mark(c, buf); + return bgp_create_end_mark_(c, buf); } static inline void @@ -2750,8 +2771,6 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) s.ip_reach_len = len - pos; s.ip_reach_nlri = pkt + pos; - bmp_route_monitor_update_in_pre_begin(); - if (s.attr_len) ea = bgp_decode_attrs(&s, s.attrs, s.attr_len); else @@ -2782,9 +2801,6 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) bgp_decode_nlri(&s, s.mp_reach_af, s.mp_reach_nlri, s.mp_reach_len, ea, s.mp_next_hop_data, s.mp_next_hop_len); - bmp_route_monitor_update_in_pre_commit(p); - bmp_route_monitor_update_in_pre_end(); - done: rta_free(s.cached_rta); lp_restore(tmp_linpool, &tmpp); @@ -2988,7 +3004,7 @@ bgp_send(struct bgp_conn *conn, uint type, uint len) conn->bgp->stats.tx_messages++; conn->bgp->stats.tx_bytes += len; - memset(buf, 0xff, 16); /* Marker */ + memset(buf, 0xff, BGP_HDR_MARKER_LENGTH); put_u16(buf+16, len); buf[18] = type; @@ -3036,12 +3052,11 @@ bgp_fire_tx(struct bgp_conn *conn) { conn->packets_to_send &= ~(1 << PKT_OPEN); end = bgp_create_open(conn, pkt); - int rv = bgp_send(conn, PKT_OPEN, end - buf); - if (rv >= 0) - { - bmp_put_sent_bgp_open_msg(p, pkt, end - buf); - } - return rv; + + conn->local_open_msg = bgp_copy_open(p, buf, end - buf); + conn->local_open_length = end - buf - BGP_HEADER_LENGTH; + + return bgp_send(conn, PKT_OPEN, end - buf); } else if (s & (1 << PKT_KEEPALIVE)) { @@ -3322,6 +3337,11 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len) bgp_log_error(p, BE_BGP_RX, "Received", code, subcode, pkt+21, len-21); bgp_store_error(p, conn, BE_BGP_RX, (code << 16) | subcode); + conn->notify_code = code; + conn->notify_subcode = subcode; + conn->notify_data = pkt+21; + conn->notify_size = len-21; + bgp_conn_enter_close_state(conn); bgp_schedule_packet(conn, NULL, PKT_SCHEDULE_CLOSE); @@ -3340,8 +3360,6 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len) p->p.disabled = 1; } } - - bmp_peer_down(p, BE_NONE, pkt, len); } static void diff --git a/proto/bmp/README.txt b/proto/bmp/README.txt index 386f4029..ed51529f 100644 --- a/proto/bmp/README.txt +++ b/proto/bmp/README.txt @@ -1,6 +1,6 @@ ABOUT This package |proto/bmp/*| provide implementation of BGP Monitoring Protocol (BMP). It has been started by Akamai Technologies, Inc. as a pilot program for support BMP in BIRD. -It provides only basic features of BMP specification which are needed by Akamai evaluation of +It provides only basic features of BMP specification which are needed by Akamai evaluation of feasible BMP protocol. -Content of this package has been provided as a patch for BIRD release v2.0.7.
\ No newline at end of file +Content of this package has been provided as a patch for BIRD release v2.0.7. diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index f04b59b8..261e9fdd 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -23,7 +23,7 @@ * * The BMP session is managed by a simple state machine with three states: Idle * (!started, !sk), Connect (!started, sk active), and Established (started). It - * has three events: connect successfull (Connect -> Established), socket error + * has three events: connect successful (Connect -> Established), socket error * (any -> Idle), and connect timeout (Idle/Connect -> Connect, resetting the * TCP socket). */ @@ -56,8 +56,25 @@ #include "nest/iface.h" #include "nest/route.h" -// We allow for single instance of BMP protocol -static struct bmp_proto *g_bmp; +// List of BMP instances +static list STATIC_LIST_INIT(bmp_proto_list); + +#define HASH_PEER_KEY(n) n->bgp +#define HASH_PEER_NEXT(n) n->next +#define HASH_PEER_EQ(b1,b2) b1 == b2 +#define HASH_PEER_FN(b) ptr_hash(b) + +#define BMP_STREAM_KEY_POLICY 0x100 + +#define HASH_STREAM_KEY(n) n->bgp, n->key +#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_TABLE_KEY(n) n->table +#define HASH_TABLE_NEXT(n) n->next +#define HASH_TABLE_EQ(t1,t2) t1 == t2 +#define HASH_TABLE_FN(t) ptr_hash(t) /* BMP Common Header [RFC 7854 - Section 4.1] */ enum bmp_version { @@ -203,18 +220,24 @@ static void bmp_close_socket(struct bmp_proto *p); static void bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, - const byte* tx_data, const size_t tx_data_size, - const byte* rx_data, const size_t rx_data_size); + const byte *tx_data, const size_t tx_data_size, + const byte *rx_data, const size_t rx_data_size); + +static void bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_stream *bs); // Stores necessary any data in list struct bmp_data_node { node n; byte *data; size_t data_size; -}; -static void -bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C); + u32 remote_as; + u32 remote_id; + ip_addr remote_ip; + btime timestamp; + bool global_peer; + bool policy; +}; static void bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size) @@ -229,7 +252,7 @@ bmp_info_tlv_hdr_serialize(buffer *stream, const enum bmp_info_tlv_type type, const char *str) { size_t str_len = strlen(str); - str_len = MIN(str_len, 65535); + str_len = MIN(str_len, MIB_II_STR_LEN); bmp_put_u16(stream, type); bmp_put_u16(stream, str_len); @@ -273,7 +296,10 @@ static void bmp_fire_tx(void *p_) { struct bmp_proto *p = p_; - byte *buf = p->sk->tbuf; + + if (!p->started) + return; + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( EMPTY_LIST(p->tx_queue), "Called BMP TX event handler when there is not any data to send" @@ -290,7 +316,7 @@ bmp_fire_tx(void *p_) } size_t data_size = tx_data->data_size; - memcpy(buf, tx_data->data, tx_data->data_size); + memcpy(p->sk->tbuf, tx_data->data, data_size); mb_free(tx_data->data); rem_node((node *) tx_data); mb_free(tx_data); @@ -336,19 +362,21 @@ bmp_put_ipa(buffer *stream, const ip_addr addr) } static void -bmp_set_initial_bgp_hdr(buffer *stream, const u16 msg_size, const u8 msg_type) +bmp_put_bgp_hdr(buffer *stream, const u8 msg_type, const u16 msg_length) { - byte marker[BGP_MSG_HDR_MARKER_SIZE]; - memset(marker, 0xff, BGP_MSG_HDR_MARKER_SIZE); - bmp_put_data(stream, marker, BGP_MSG_HDR_MARKER_SIZE); - bmp_put_u16(stream, msg_size); + bmp_buffer_need(stream, BGP_HEADER_LENGTH); + + memset(stream->pos, 0xff, BGP_HDR_MARKER_LENGTH); + stream->pos += BGP_HDR_MARKER_LENGTH; + + bmp_put_u16(stream, msg_length); bmp_put_u8(stream, msg_type); } /** * bmp_per_peer_hdr_serialize - serializes Per-Peer Header * - * @is_pre_policy: indicate the message reflects the pre-policy Adj-RIB-In + * @is_post_policy: indicate the message reflects the post-policy Adj-RIB-In * @peer_addr: the remote IP address associated with the TCP session * @peer_as: the Autonomous System number of the peer * @peer_bgp_id: the BGP Identifier of the peer @@ -357,7 +385,7 @@ bmp_set_initial_bgp_hdr(buffer *stream, const u16 msg_size, const u8 msg_type) */ static void bmp_per_peer_hdr_serialize(buffer *stream, const bool is_global_instance_peer, - const bool is_pre_policy, const bool is_as_path_4bytes, + const bool is_post_policy, const bool is_as_path_4bytes, const ip_addr peer_addr, const u32 peer_as, const u32 peer_bgp_id, const u32 ts_sec, const u32 ts_usec) { @@ -368,9 +396,9 @@ bmp_per_peer_hdr_serialize(buffer *stream, const bool is_global_instance_peer, const u8 peer_flag_v = ipa_is_ip4(peer_addr) ? BMP_PEER_HDR_FLAG_V_IP4 : BMP_PEER_HDR_FLAG_V_IP6; - const u8 peer_flag_l = is_pre_policy - ? BMP_PEER_HDR_FLAG_L_PRE_POLICY_ADJ_RIB_IN - : BMP_PEER_HDR_FLAG_L_POST_POLICY_ADJ_RIB_IN; + const u8 peer_flag_l = is_post_policy + ? BMP_PEER_HDR_FLAG_L_POST_POLICY_ADJ_RIB_IN + : BMP_PEER_HDR_FLAG_L_PRE_POLICY_ADJ_RIB_IN; const u8 peer_flag_a = is_as_path_4bytes ? BMP_PEER_HDR_FLAG_A_AS_PATH_4B : BMP_PEER_HDR_FLAG_A_AS_PATH_2B; @@ -394,14 +422,17 @@ bmp_per_peer_hdr_serialize(buffer *stream, const bool is_global_instance_peer, /* [4.6] Route Monitoring */ static void bmp_route_monitor_msg_serialize(buffer *stream, const bool is_peer_global, - const bool table_in_pre_policy, const u32 peer_as, const u32 peer_bgp_id, + const bool table_in_post_policy, const u32 peer_as, const u32 peer_bgp_id, const bool as4_support, const ip_addr remote_addr, const byte *update_msg, - const size_t update_msg_size, u32 ts_sec, u32 ts_usec) + const size_t update_msg_size, btime timestamp) { const size_t data_size = BMP_PER_PEER_HDR_SIZE + update_msg_size; + u32 ts_sec = timestamp TO_S; + u32 ts_usec = timestamp - (ts_sec S); + bmp_buffer_need(stream, BMP_COMMON_HDR_SIZE + data_size); bmp_common_hdr_serialize(stream, BMP_ROUTE_MONITOR, data_size); - bmp_per_peer_hdr_serialize(stream, is_peer_global, table_in_pre_policy, + bmp_per_peer_hdr_serialize(stream, is_peer_global, table_in_post_policy, as4_support, remote_addr, peer_as, peer_bgp_id, ts_sec, ts_usec); bmp_put_data(stream, update_msg, update_msg_size); } @@ -410,25 +441,25 @@ static void bmp_peer_up_notif_msg_serialize(buffer *stream, const bool is_peer_global, const u32 peer_as, const u32 peer_bgp_id, const bool as4_support, const ip_addr local_addr, const ip_addr remote_addr, const u16 local_port, - const u16 remote_port, const byte *sent_msg, const size_t sent_msg_size, - const byte *recv_msg, const size_t recv_msg_size) + const u16 remote_port, const byte *sent_msg, const size_t sent_msg_length, + const byte *recv_msg, const size_t recv_msg_length) { - const size_t data_size = BMP_PER_PEER_HDR_SIZE + BMP_PEER_UP_NOTIF_MSG_FIX_SIZE - + sent_msg_size + recv_msg_size; + const size_t data_size = + BMP_PER_PEER_HDR_SIZE + BMP_PEER_UP_NOTIF_MSG_FIX_SIZE + + BGP_HEADER_LENGTH + sent_msg_length + BGP_HEADER_LENGTH + recv_msg_length; + bmp_buffer_need(stream, BMP_COMMON_HDR_SIZE + data_size); bmp_common_hdr_serialize(stream, BMP_PEER_UP_NOTIF, data_size); bmp_per_peer_hdr_serialize(stream, is_peer_global, - true /* TODO: Hardcoded pre-policy Adj-RIB-In */, as4_support, remote_addr, + false /* TODO: Hardcoded pre-policy Adj-RIB-In */, as4_support, remote_addr, peer_as, peer_bgp_id, 0, 0); // 0, 0 - No timestamp provided bmp_put_ipa(stream, local_addr); bmp_put_u16(stream, local_port); bmp_put_u16(stream, remote_port); - bmp_set_initial_bgp_hdr(stream, sent_msg_size, PKT_OPEN); - const size_t missing_bgp_hdr_size = BGP_MSG_HDR_MARKER_SIZE - + BGP_MSG_HDR_LENGTH_SIZE - + BGP_MSG_HDR_TYPE_SIZE; - bmp_put_data(stream, sent_msg, sent_msg_size - missing_bgp_hdr_size); - bmp_put_data(stream, recv_msg, recv_msg_size); + bmp_put_bgp_hdr(stream, PKT_OPEN, BGP_HEADER_LENGTH + sent_msg_length); + bmp_put_data(stream, sent_msg, sent_msg_length); + bmp_put_bgp_hdr(stream, PKT_OPEN, BGP_HEADER_LENGTH + recv_msg_length); + bmp_put_data(stream, recv_msg, recv_msg_length); } static void @@ -440,57 +471,232 @@ bmp_peer_down_notif_msg_serialize(buffer *stream, const bool is_peer_global, bmp_buffer_need(stream, BMP_COMMON_HDR_SIZE + payload_size); bmp_common_hdr_serialize(stream, BMP_PEER_DOWN_NOTIF, payload_size); bmp_per_peer_hdr_serialize(stream, is_peer_global, - true /* TODO: Hardcoded pre-policy adj RIB IN */, as4_support, remote_addr, + false /* TODO: Hardcoded pre-policy adj RIB IN */, as4_support, remote_addr, peer_as, peer_bgp_id, 0, 0); // 0, 0 - No timestamp provided bmp_put_data(stream, data, data_size); } + +/* + * BMP tables + */ + +static struct bmp_table * +bmp_find_table(struct bmp_proto *p, struct rtable *tab) +{ + return HASH_FIND(p->table_map, HASH_TABLE, tab); +} + +static struct bmp_table * +bmp_add_table(struct bmp_proto *p, struct rtable *tab) +{ + struct bmp_table *bt = mb_allocz(p->p.pool, sizeof(struct bmp_table)); + bt->table = tab; + rt_lock_table(bt->table); + + HASH_INSERT(p->table_map, HASH_TABLE, bt); + + struct channel_config cc = { + .name = "monitor", + .channel = &channel_basic, + .table = tab->config, + .in_filter = FILTER_REJECT, + .net_type = tab->addr_type, + .ra_mode = RA_ANY, + .bmp_hack = 1, + }; + + bt->channel = proto_add_channel(&p->p, &cc); + channel_set_state(bt->channel, CS_UP); + + return bt; +} + static void -bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif( - const struct bmp_peer_map_key key, const byte *tx_msg, - const size_t tx_msg_size, void *bmp_) +bmp_remove_table(struct bmp_proto *p, struct bmp_table *bt) { - struct bmp_proto *p = bmp_; - ASSERT(p->started); + channel_set_state(bt->channel, CS_FLUSHING); + channel_set_state(bt->channel, CS_DOWN); + proto_remove_channel(&p->p, bt->channel); - const struct bmp_peer_map_entry *map_rx_msg = bmp_peer_map_get(&p->peer_open_msg.rx_msg, key); - IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - map_rx_msg, - "Processing TX BGP OPEN MSG but there is not corresponding received MSG" - ); + HASH_REMOVE(p->table_map, HASH_TABLE, bt); - const struct bmp_peer_map_entry *map_bgp_proto = bmp_peer_map_get(&p->bgp_peers, key); - IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - map_bgp_proto, - "There is not BGP proto related with stored TX/RX OPEN MSG" - ); + rt_unlock_table(bt->table); + bt->table = NULL; + + mb_free(bt); +} + +static inline struct bmp_table *bmp_get_table(struct bmp_proto *p, struct rtable *tab) +{ return bmp_find_table(p, tab) ?: bmp_add_table(p, tab); } + +static inline void bmp_lock_table(struct bmp_proto *p UNUSED, struct bmp_table *bt) +{ bt->uc++; } + +static inline void bmp_unlock_table(struct bmp_proto *p, struct bmp_table *bt) +{ bt->uc--; if (!bt->uc) bmp_remove_table(p, bt); } + + +/* + * BMP streams + */ + +static inline u32 bmp_stream_key(u32 afi, bool policy) +{ return afi ^ (policy ? BMP_STREAM_KEY_POLICY : 0); } + +static inline u32 bmp_stream_afi(struct bmp_stream *bs) +{ return bs->key & ~BMP_STREAM_KEY_POLICY; } - const struct bgp_proto *bgp; - memcpy(&bgp, map_bgp_proto->data.buf, sizeof (bgp)); - if (bgp->p.proto_state == PS_UP) +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) +{ + return HASH_FIND(p->stream_map, HASH_STREAM, bgp, bmp_stream_key(afi, policy)); +} + +static struct bmp_stream * +bmp_add_stream(struct bmp_proto *p, struct bmp_peer *bp, u32 afi, bool policy, struct rtable *tab, struct bgp_channel *sender) +{ + struct bmp_stream *bs = mb_allocz(p->p.pool, sizeof(struct bmp_stream)); + bs->bgp = bp->bgp; + bs->key = bmp_stream_key(afi, policy); + + add_tail(&bp->streams, &bs->n); + HASH_INSERT(p->stream_map, HASH_STREAM, bs); + + bs->table = bmp_get_table(p, tab); + bmp_lock_table(p, bs->table); + + bs->sender = sender; + bs->sync = false; + + return bs; +} + +static void +bmp_remove_stream(struct bmp_proto *p, struct bmp_stream *bs) +{ + rem_node(&bs->n); + HASH_REMOVE(p->stream_map, HASH_STREAM, bs); + + bmp_unlock_table(p, bs->table); + bs->table = NULL; + + mb_free(bs); +} + + +/* + * BMP peers + */ + +static struct bmp_peer * +bmp_find_peer(struct bmp_proto *p, const struct bgp_proto *bgp) +{ + return HASH_FIND(p->peer_map, HASH_PEER, bgp); +} + +static struct bmp_peer * +bmp_add_peer(struct bmp_proto *p, struct bgp_proto *bgp) +{ + struct bmp_peer *bp = mb_allocz(p->p.pool, sizeof(struct bmp_peer)); + bp->bgp = bgp; + + init_list(&bp->streams); + + HASH_INSERT(p->peer_map, HASH_PEER, bp); + + struct bgp_channel *c; + BGP_WALK_CHANNELS(bgp, c) { - bmp_send_peer_up_notif_msg(p, bgp, tx_msg, tx_msg_size, - map_rx_msg->data.buf, map_rx_msg->data.buf_size); + if (p->monitoring_rib.in_pre_policy && c->c.in_table) + bmp_add_stream(p, bp, c->afi, false, c->c.in_table, c); + + if (p->monitoring_rib.in_post_policy && c->c.table) + bmp_add_stream(p, bp, c->afi, true, c->c.table, c); } + + return bp; } static void -bmp_peer_up(const struct bgp_proto *bgp) +bmp_remove_peer(struct bmp_proto *p, struct bmp_peer *bp) { - struct bgp_channel *c; - WALK_LIST(c, bgp->p.channels) + struct bmp_stream *bs, *bs_next; + WALK_LIST_DELSAFE(bs, bs_next, bp->streams) + bmp_remove_stream(p, bs); + + HASH_REMOVE(p->peer_map, HASH_PEER, bp); + + mb_free(bp); +} + +static void +bmp_peer_up_(struct bmp_proto *p, struct bgp_proto *bgp, bool sync, + const byte *tx_open_msg, uint tx_open_length, + const byte *rx_open_msg, uint rx_open_length) +{ + if (!p->started) + return; + + struct bmp_peer *bp = bmp_find_peer(p, bgp); + if (bp) + return; + + TRACE(D_STATES, "Peer up for %s", bgp->p.name); + + bp = bmp_add_peer(p, bgp); + + bmp_send_peer_up_notif_msg(p, bgp, tx_open_msg, tx_open_length, rx_open_msg, rx_open_length); + + /* + * We asssume peer_up() notifications are received before any route + * notifications from that peer. Therefore, peers established after BMP + * session coould be considered synced with empty RIB. + */ + if (sync) { - bmp_route_monitor_pre_policy_table_in_snapshot((struct channel *) c); + struct bmp_stream *bs; + WALK_LIST(bs, bp->streams) + { + bmp_route_monitor_end_of_rib(p, bs); + bs->sync = true; + } } } +void +bmp_peer_up(struct bgp_proto *bgp, + const byte *tx_open_msg, uint tx_open_length, + const byte *rx_open_msg, uint rx_open_length) +{ + struct bmp_proto *p; node *n; + WALK_LIST2(p, n, bmp_proto_list, bmp_node) + bmp_peer_up_(p, bgp, true, tx_open_msg, tx_open_length, rx_open_msg, rx_open_length); +} + +static void +bmp_peer_init(struct bmp_proto *p, struct bgp_proto *bgp) +{ + struct bgp_conn *conn = bgp->conn; + + if (!conn || (conn->state != BS_ESTABLISHED) || + !conn->local_open_msg || !conn->remote_open_msg) + return; + + bmp_peer_up_(p, bgp, false, conn->local_open_msg, conn->local_open_length, + conn->remote_open_msg, conn->remote_open_length); +} + + + static const struct birdsock * bmp_get_birdsock(const struct bgp_proto *bgp) { if (bgp->conn && bgp->conn->sk) - { return bgp->conn->sk; - } return NULL; } @@ -499,11 +705,8 @@ static const struct birdsock * bmp_get_birdsock_ext(const struct bgp_proto *bgp) { const struct birdsock *sk = bmp_get_birdsock(bgp); - if (sk != NULL) - { return sk; - } if (bgp->incoming_conn.sk) { @@ -521,9 +724,7 @@ static const struct bgp_caps * bmp_get_bgp_remote_caps(const struct bgp_proto *bgp) { if (bgp->conn && bgp->conn->remote_caps) - { return bgp->conn->remote_caps; - } return NULL; } @@ -533,9 +734,7 @@ bmp_get_bgp_remote_caps_ext(const struct bgp_proto *bgp) { const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps(bgp); if (remote_caps != NULL) - { return remote_caps; - } if (bgp->incoming_conn.remote_caps) { @@ -560,8 +759,8 @@ bmp_is_peer_global_instance(const struct bgp_proto *bgp) static void bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, - const byte* tx_data, const size_t tx_data_size, - const byte* rx_data, const size_t rx_data_size) + const byte *tx_data, const size_t tx_data_size, + const byte *rx_data, const size_t rx_data_size) { ASSERT(p->started); @@ -579,264 +778,98 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, rx_data, rx_data_size); bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_free(&payload); - - bmp_peer_up(bgp); } -void -bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, - const size_t pkt_size) -{ - struct bmp_proto *p = g_bmp; - - if (!p) - { - return; - } - - struct bmp_peer_map_key key - = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - const struct bmp_peer_map_entry *rx_msg - = bmp_peer_map_get(&p->peer_open_msg.rx_msg, key); - - bmp_peer_map_insert(&p->peer_open_msg.tx_msg, key, pkt, pkt_size); - - if (!rx_msg) - bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); - - if (rx_msg && p->started) - bmp_send_peer_up_notif_msg(p, bgp, pkt, pkt_size, rx_msg->data.buf, - rx_msg->data.buf_size); -} - -void -bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, - const size_t pkt_size) -{ - struct bmp_proto *p = g_bmp; - - if (!p) - { - return; - } - - struct bmp_peer_map_key key - = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - const struct bmp_peer_map_entry *tx_msg - = bmp_peer_map_get(&p->peer_open_msg.tx_msg, key); - - bmp_peer_map_insert(&p->peer_open_msg.rx_msg, key, pkt, pkt_size); - - if (!tx_msg) - bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); - - if (tx_msg && p->started) - bmp_send_peer_up_notif_msg(p, bgp, tx_msg->data.buf, tx_msg->data.buf_size, - pkt, pkt_size); -} - -void -bmp_route_monitor_update_in_pre_begin() +static void +bmp_route_monitor_put_update(struct bmp_proto *p, struct bmp_stream *bs, const byte *data, size_t length, btime timestamp) { - struct bmp_proto *p = g_bmp; - - if (!p || !p->started) - { - return; - } - - if (p->monitoring_rib.in_pre_policy == false) - { - return; - } - - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue), - "Previous BMP route monitoring update not finished yet" - ); - - gettimeofday(&p->rt_table_in_pre_policy.update_begin_time,NULL); - init_list(&p->rt_table_in_pre_policy.update_msg_queue); - p->rt_table_in_pre_policy.update_msg_size = 0; - p->rt_table_in_pre_policy.update_in_progress = true; + struct bmp_data_node *upd_msg = mb_alloc(p->update_msg_mem_pool, + sizeof (struct bmp_data_node)); + upd_msg->data = mb_alloc(p->update_msg_mem_pool, length); + memcpy(upd_msg->data, data, length); + upd_msg->data_size = length; + add_tail(&p->update_msg_queue, &upd_msg->n); + + /* Save some metadata */ + struct bgp_proto *bgp = bs->bgp; + upd_msg->remote_as = bgp->remote_as; + upd_msg->remote_id = bgp->remote_id; + upd_msg->remote_ip = bgp->remote_ip; + upd_msg->timestamp = timestamp; + upd_msg->global_peer = bmp_is_peer_global_instance(bgp); + upd_msg->policy = bmp_stream_policy(bs); + + /* Kick the commit */ + if (!ev_active(p->update_ev)) + ev_schedule(p->update_ev); } -void -bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size) +static void +bmp_route_monitor_notify(struct bmp_proto *p, struct bmp_stream *bs, + const net_addr *n, const struct rte *new, const struct rte_src *src) { - struct bmp_proto *p = g_bmp; - - if (!p || !p->started) - { - return; - } - - if (p->monitoring_rib.in_pre_policy == false) - { - return; - } + byte buf[BGP_MAX_EXT_MSG_LENGTH]; + byte *end = bgp_bmp_encode_rte(bs->sender, buf, n, new, src); - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !p->rt_table_in_pre_policy.update_in_progress, - "BMP route monitoring update not started yet" - ); + btime delta_t = new ? current_time() - new->lastmod : 0; + btime timestamp = current_real_time() - delta_t; - struct bmp_data_node *upd_msg = mb_alloc(p->update_msg_mem_pool, - sizeof (struct bmp_data_node)); - upd_msg->data = mb_alloc(p->update_msg_mem_pool, data_size); - memcpy(upd_msg->data, data, data_size); - upd_msg->data_size = data_size; - p->rt_table_in_pre_policy.update_msg_size += data_size; - add_tail(&p->rt_table_in_pre_policy.update_msg_queue, &upd_msg->n); + if (end) + bmp_route_monitor_put_update(p, bs, buf, end - buf, timestamp); + else + log(L_WARN "%s: Cannot encode update for %N", p->p.name, n); } -void -bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) +static void +bmp_route_monitor_commit(void *p_) { - struct bmp_proto *p = g_bmp; - - if (!p || !p->started) - { - return; - } + struct bmp_proto *p = p_; - if (p->monitoring_rib.in_pre_policy == false) - { + if (!p->started) return; - } - const struct birdsock *sk = bmp_get_birdsock(bgp); - IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - sk, - "Failed to get bird socket from BGP proto" - ); - - const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps(bgp); - IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - remote_caps, - "Failed to get remote capabilities from BGP proto" - ); - - bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); buffer payload - = bmp_buffer_alloc(p->buffer_mpool, - p->rt_table_in_pre_policy.update_msg_size + DEFAULT_MEM_BLOCK_SIZE); - - buffer update_msgs - = bmp_buffer_alloc(p->buffer_mpool, - p->rt_table_in_pre_policy.update_msg_size); + = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); - struct bmp_data_node *data; - WALK_LIST(data, p->rt_table_in_pre_policy.update_msg_queue) + struct bmp_data_node *data, *data_next; + WALK_LIST_DELSAFE(data, data_next, p->update_msg_queue) { - bmp_put_data(&update_msgs, data->data, data->data_size); bmp_route_monitor_msg_serialize(&payload, - is_global_instance_peer, true /* TODO: Hardcoded pre-policy Adj-Rib-In */, - bgp->conn->received_as, bgp->remote_id, remote_caps->as4_support, - sk->daddr, bmp_buffer_data(&update_msgs), bmp_buffer_pos(&update_msgs), - p->rt_table_in_pre_policy.update_begin_time.tv_sec, - p->rt_table_in_pre_policy.update_begin_time.tv_usec); + data->global_peer, data->policy, + data->remote_as, data->remote_id, true, + data->remote_ip, data->data, data->data_size, + data->timestamp); bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_flush(&payload); - bmp_buffer_flush(&update_msgs); - } - - bmp_buffer_free(&payload); - bmp_buffer_free(&update_msgs); -} -void -bmp_route_monitor_update_in_pre_end() -{ - struct bmp_proto *p = g_bmp; - - if (!p || !p->started) - { - return; + mb_free(data->data); + rem_node(&data->n); + mb_free(data); } - if (p->monitoring_rib.in_pre_policy == false) - { - return; - } - - struct bmp_data_node *upd_msg; - struct bmp_data_node *upd_msg_next; - WALK_LIST_DELSAFE(upd_msg, upd_msg_next, p->rt_table_in_pre_policy.update_msg_queue) - { - mb_free(upd_msg->data); - rem_node((node *) upd_msg); - mb_free(upd_msg); - } - - p->rt_table_in_pre_policy.update_in_progress = false; + bmp_buffer_free(&payload); } static void -bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C) +bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_stream *bs) { - struct bmp_proto *p = g_bmp; - - if (p->monitoring_rib.in_pre_policy == false) - { - return; - } + TRACE(D_PACKETS, "Sending END-OF-RIB for %s.%s", bs->bgp->p.name, bs->sender->c.name); - struct rtable *tab = C->in_table; - if (!tab) - { - return; - } + byte rx_end_payload[DEFAULT_MEM_BLOCK_SIZE]; + byte *pos = bgp_create_end_mark_(bs->sender, rx_end_payload + BGP_HEADER_LENGTH); + memset(rx_end_payload + BGP_MSG_HDR_MARKER_POS, 0xff, + BGP_MSG_HDR_MARKER_SIZE); // BGP UPDATE MSG marker + put_u16(rx_end_payload + BGP_MSG_HDR_LENGTH_POS, pos - rx_end_payload); + put_u8(rx_end_payload + BGP_MSG_HDR_TYPE_POS, PKT_UPDATE); - size_t cnt = 0; - struct proto *P; - struct fib_iterator fit; - memset(&fit, 0x00, sizeof (fit)); - FIB_ITERATE_INIT(&fit, &tab->fib); - FIB_ITERATE_START(&tab->fib, &fit, net, n) - { - P = n->routes->sender->proto; - if (P->proto->class != PROTOCOL_BGP) - { - continue; - } - - bmp_route_monitor_update_in_pre_begin(); - - rte *e; - for (e = n->routes; e; e = e->next) - { - bgp_rte_update_in_notify(C, n->n.addr, e, e->src); - } - - bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) P); - bmp_route_monitor_update_in_pre_end(); - ++cnt; - } - FIB_ITERATE_END; - - if (cnt > 0) - { - bmp_route_monitor_update_in_pre_begin(); - byte rx_end_payload[DEFAULT_MEM_BLOCK_SIZE]; - byte *pos - = bgp_create_end_mark((struct bgp_channel *) C, rx_end_payload - + BGP_HEADER_LENGTH); - memset(rx_end_payload + BGP_MSG_HDR_MARKER_POS, 0xff, - BGP_MSG_HDR_MARKER_SIZE); // BGP UPDATE MSG marker - put_u16(rx_end_payload + BGP_MSG_HDR_LENGTH_POS, pos - rx_end_payload); - put_u8(rx_end_payload + BGP_MSG_HDR_TYPE_POS, PKT_UPDATE); - bmp_route_monitor_put_update_in_pre_msg(rx_end_payload, pos - rx_end_payload); - bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) C->proto); - bmp_route_monitor_update_in_pre_end(); - } + bmp_route_monitor_put_update(p, bs, rx_end_payload, pos - rx_end_payload, current_real_time()); } static void bmp_send_peer_down_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, - const byte* data, const size_t data_size) + const byte *data, const size_t data_size) { ASSERT(p->started); @@ -853,69 +886,72 @@ bmp_send_peer_down_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, bmp_buffer_free(&payload); } -void -bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, - size_t pkt_size) +static void +bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp, + int err_class, int err_code, int err_subcode, const byte *data, int length) { - struct bmp_proto *p = g_bmp; - - if (!p) - { + if (!p->started) return; - } - struct bmp_peer_map_key key - = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); + struct bmp_peer *bp = bmp_find_peer(p, bgp); + if (!bp) + return; - bmp_peer_map_remove(&p->peer_open_msg.tx_msg, key); - bmp_peer_map_remove(&p->peer_open_msg.rx_msg, key); - bmp_peer_map_remove(&p->bgp_peers, key); - const size_t missing_bgp_hdr_size = BGP_MSG_HDR_MARKER_SIZE - + BGP_MSG_HDR_LENGTH_SIZE - + BGP_MSG_HDR_TYPE_SIZE; + TRACE(D_STATES, "Peer down for %s", bgp->p.name); - if (!p->started) - return; + uint bmp_code = 0; + uint fsm_code = 0; - buffer payload - = bmp_buffer_alloc(p->buffer_mpool, pkt_size + missing_bgp_hdr_size + 1); - if (pkt != NULL && pkt_size > 0) + switch (err_class) { - byte marker[BGP_MSG_HDR_MARKER_SIZE]; - memset(marker, 0xff, BGP_MSG_HDR_MARKER_SIZE); // NOTIF MSG marker - if (!memcmp(pkt, marker, BGP_MSG_HDR_MARKER_SIZE)) - { - // So it is received BGP PDU - bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION); - bmp_put_data(&payload, pkt, pkt_size); - } - else - { - bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION); - bmp_put_data(&payload, marker, BGP_MSG_HDR_MARKER_SIZE); - bmp_put_u16(&payload, pkt_size); - bmp_put_u8(&payload, PKT_NOTIFICATION); - bmp_put_data(&payload, pkt, pkt_size); - } + case BE_BGP_RX: + bmp_code = BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION; + break; + + case BE_BGP_TX: + case BE_AUTO_DOWN: + case BE_MAN_DOWN: + bmp_code = BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION; + break; + + default: + bmp_code = BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION; + length = 0; + break; } - else + + buffer payload = bmp_buffer_alloc(p->buffer_mpool, 1 + BGP_HEADER_LENGTH + 2 + length); + bmp_put_u8(&payload, bmp_code); + + switch (bmp_code) { - // TODO: Handle De-configured Peer Down Reason Code - if (err_class == BE_SOCKET || err_class == BE_MISC) - { - bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION); - } - else - { - bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION); - // TODO: Fill in with appropriate FSM event code - bmp_put_u16(&payload, 0x00); // no relevant Event code is defined - } + case BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION: + case BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION: + bmp_put_bgp_hdr(&payload, BGP_HEADER_LENGTH + 2 + length, PKT_NOTIFICATION); + bmp_put_u8(&payload, err_code); + bmp_put_u8(&payload, err_subcode); + bmp_put_data(&payload, data, length); + break; + + case BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION: + bmp_put_u16(&payload, fsm_code); + break; } bmp_send_peer_down_notif_msg(p, bgp, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_free(&payload); + + bmp_remove_peer(p, bp); +} + +void +bmp_peer_down(const struct bgp_proto *bgp, + int err_class, int code, int subcode, const byte *data, int length) +{ + struct bmp_proto *p; node *n; + WALK_LIST2(p, n, bmp_proto_list, bmp_node) + bmp_peer_down_(p, bgp, err_class, code, subcode, data, length); } static void @@ -940,6 +976,73 @@ bmp_send_termination_msg(struct bmp_proto *p, bmp_buffer_free(&stream); } +int +bmp_preexport(struct channel *C UNUSED, rte *e) +{ + /* Reject non-direct routes */ + if (e->src->proto != e->sender->proto) + return -1; + + /* Reject non-BGP routes */ + if (e->sender->channel != &channel_bgp) + return -1; + + return 1; +} + +static void +bmp_rt_notify(struct proto *P, struct channel *c, struct network *net, + struct rte *new, struct rte *old) +{ + struct bmp_proto *p = (void *) P; + + struct bgp_channel *src = (void *) (new ?: old)->sender; + struct bgp_proto *bgp = (void *) src->c.proto; + bool policy = (c->table == src->c.table); + + /* + * We assume that we receive peer_up before the first route and peer_down + * synchronously with BGP session close. So if bmp_stream exists, the related + * BGP session is up and could be accessed. That may not be true in + * multithreaded setup. + */ + + struct bmp_stream *bs = bmp_find_stream(p, bgp, src->afi, policy); + if (!bs) + return; + + bmp_route_monitor_notify(p, bs, net->n.addr, new, (new ?: old)->src); +} + +static void +bmp_feed_end(struct channel *c) +{ + struct bmp_proto *p = (void *) c->proto; + + struct bmp_table *bt = bmp_find_table(p, c->table); + if (!bt) + return; + + /* + * 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) + { + if ((bs->table == bt) && !bs->sync) + { + bmp_route_monitor_end_of_rib(p, bs); + bs->sync = true; + } + } + HASH_WALK_END; +} + + /** * bmp_startup - enter established state * @p: BMP instance @@ -952,9 +1055,12 @@ bmp_startup(struct bmp_proto *p) { ASSERT(!p->started); p->started = true; + p->sock_err = 0; TRACE(D_EVENTS, "BMP session established"); + proto_notify_state(&p->p, PS_UP); + /* Send initiation message */ buffer payload = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); bmp_init_msg_serialize(&payload, p->sys_descr, p->sys_name); @@ -962,17 +1068,18 @@ bmp_startup(struct bmp_proto *p) bmp_buffer_free(&payload); /* Send Peer Up messages */ - bmp_peer_map_walk(&p->peer_open_msg.tx_msg, - bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif, p); - - proto_notify_state(&p->p, PS_UP); + struct proto *peer; + WALK_LIST(peer, proto_list) + if ((peer->proto->class == PROTOCOL_BGP) && (peer->proto_state == PS_UP)) + bmp_peer_init(p, (struct bgp_proto *) peer); } /** * bmp_down - leave established state * @p: BMP instance * - * The bgp_down() function is called when the BMP session fails. + * The bgp_down() function is called when the BMP session fails. The caller is + * responsible for changing protocol state. */ static void bmp_down(struct bmp_proto *p) @@ -982,7 +1089,15 @@ bmp_down(struct bmp_proto *p) TRACE(D_EVENTS, "BMP session closed"); - proto_notify_state(&p->p, PS_START); + /* Unregister existing peer structures */ + HASH_WALK_DELSAFE(p->peer_map, next, bp) + { + bmp_remove_peer(p, bp); + } + HASH_WALK_END; + + /* Removing peers should also remove all streams and tables */ + ASSERT(!p->peer_map.count && !p->stream_map.count && !p->table_map.count); } /** @@ -999,6 +1114,7 @@ bmp_connect(struct bmp_proto *p) sock *sk = sk_new(p->p.pool); sk->type = SK_TCP_ACTIVE; + sk->saddr = p->local_addr; sk->daddr = p->station_ip; sk->dport = p->station_port; sk->ttl = IP4_MAX_TTL; @@ -1010,6 +1126,8 @@ bmp_connect(struct bmp_proto *p) p->sk = sk; sk->data = p; + TRACE(D_EVENTS, "Connecting to %I port %u", sk->daddr, sk->dport); + int rc = sk_open(sk); if (rc < 0) @@ -1018,12 +1136,14 @@ bmp_connect(struct bmp_proto *p) tm_start(p->connect_retry_timer, CONNECT_RETRY_TIME); } -/* BMP connect successfull event - switch from Connect to Established state */ +/* BMP connect successful event - switch from Connect to Established state */ static void bmp_connected(struct birdsock *sk) { struct bmp_proto *p = (void *) sk->data; + TRACE(D_EVENTS, "Connected"); + sk->rx_hook = bmp_rx; sk->tx_hook = bmp_tx; tm_stop(p->connect_retry_timer); @@ -1037,6 +1157,8 @@ bmp_sock_err(sock *sk, int err) { struct bmp_proto *p = sk->data; + p->sock_err = err; + if (err) TRACE(D_EVENTS, "Connection lost (%M)", err); else @@ -1047,6 +1169,8 @@ bmp_sock_err(sock *sk, int err) bmp_close_socket(p); tm_start(p->connect_retry_timer, CONNECT_RETRY_TIME); + + proto_notify_state(&p->p, PS_START); } /* BMP connect timeout event - switch from Idle/Connect state to Connect state */ @@ -1070,6 +1194,22 @@ bmp_close_socket(struct bmp_proto *p) } +static void +bmp_postconfig(struct proto_config *CF) +{ + struct bmp_config *cf = (void *) CF; + + /* Do not check templates at all */ + if (cf->c.class == SYM_TEMPLATE) + return; + + if (ipa_zero(cf->station_ip)) + cf_error("Station IP address not specified"); + + if (!cf->station_port) + cf_error("Station port number not specified"); +} + /** Configuration handle section **/ static struct proto * bmp_init(struct proto_config *CF) @@ -1078,45 +1218,52 @@ bmp_init(struct proto_config *CF) struct bmp_proto *p = (void *) P; struct bmp_config *cf = (void *) CF; + P->rt_notify = bmp_rt_notify; + P->preexport = bmp_preexport; + P->feed_end = bmp_feed_end; + p->cf = cf; + p->local_addr = cf->local_addr; p->station_ip = cf->station_ip; p->station_port = cf->station_port; strcpy(p->sys_descr, cf->sys_descr); strcpy(p->sys_name, cf->sys_name); p->monitoring_rib.in_pre_policy = cf->monitoring_rib_in_pre_policy; p->monitoring_rib.in_post_policy = cf->monitoring_rib_in_post_policy; - p->monitoring_rib.local = cf->monitoring_rib_local; return P; } +/** + * bmp_start - initialize internal resources of BMP implementation. + * NOTE: It does not connect to BMP collector yet. + */ static int bmp_start(struct proto *P) { struct bmp_proto *p = (void *) P; - log(L_DEBUG "Init BMP"); - p->buffer_mpool = rp_new(P->pool, "BMP Buffer"); p->map_mem_pool = rp_new(P->pool, "BMP Map"); p->tx_mem_pool = rp_new(P->pool, "BMP Tx"); p->update_msg_mem_pool = rp_new(P->pool, "BMP Update"); - p->tx_ev = ev_new_init(p->tx_mem_pool, bmp_fire_tx, p); + p->tx_ev = ev_new_init(p->p.pool, bmp_fire_tx, p); + p->update_ev = ev_new_init(p->p.pool, bmp_route_monitor_commit, p); p->connect_retry_timer = tm_new_init(p->p.pool, bmp_connection_retry, p, 0, 0); p->sk = NULL; - bmp_peer_map_init(&p->peer_open_msg.tx_msg, p->map_mem_pool); - bmp_peer_map_init(&p->peer_open_msg.rx_msg, p->map_mem_pool); - bmp_peer_map_init(&p->bgp_peers, p->map_mem_pool); + HASH_INIT(p->peer_map, P->pool, 4); + HASH_INIT(p->stream_map, P->pool, 4); + HASH_INIT(p->table_map, P->pool, 4); init_list(&p->tx_queue); - init_list(&p->rt_table_in_pre_policy.update_msg_queue); + init_list(&p->update_msg_queue); p->started = false; + p->sock_err = 0; + add_tail(&bmp_proto_list, &p->bmp_node); tm_start(p->connect_retry_timer, CONNECT_INIT_TIME); - g_bmp = p; - return PS_START; } @@ -1128,10 +1275,11 @@ bmp_shutdown(struct proto *P) if (p->started) { bmp_send_termination_msg(p, BMP_TERM_REASON_ADM); - p->started = false; + bmp_down(p); } - g_bmp = NULL; + p->sock_err = 0; + rem_node(&p->bmp_node); return PS_DOWN; } @@ -1140,25 +1288,76 @@ static int bmp_reconfigure(struct proto *P, struct proto_config *CF) { struct bmp_proto *p = (void *) P; - const struct bmp_config *cf = (void *) CF; + const struct bmp_config *new = (void *) CF; + const struct bmp_config *old = p->cf; - log(L_WARN "Reconfiguring BMP is not supported"); + int needs_restart = bstrcmp(new->sys_descr, old->sys_descr) + || bstrcmp(new->sys_name, old->sys_name) + || !ipa_equal(new->local_addr, old->local_addr) + || !ipa_equal(new->station_ip, old->station_ip) + || (new->station_port != old->station_port) + || (new->monitoring_rib_in_pre_policy != old->monitoring_rib_in_pre_policy) + || (new->monitoring_rib_in_post_policy != old->monitoring_rib_in_post_policy); - p->cf = cf; + /* If there is any change, restart the protocol */ + if (needs_restart) + return 0; + + /* We must update our copy of configuration ptr */ + p->cf = new; return 1; } +static void +bmp_get_status(struct proto *P, byte *buf) +{ + struct bmp_proto *p = (void *) P; + + if (P->proto_state == PS_DOWN) + bsprintf(buf, "Down"); + else + { + const char *state = !p->started ? (!p->sk ? "Idle" : "Connect") : "Established"; + + if (!p->sock_err) + bsprintf(buf, "%s", state); + else + bsprintf(buf, "%-14s%s %M", state, "Error:", p->sock_err); + } +} + +static void +bmp_show_proto_info(struct proto *P) +{ + struct bmp_proto *p = (void *) P; + + if (P->proto_state != PS_DOWN) + { + cli_msg(-1006, " %-19s %I", "Station address:", p->station_ip); + cli_msg(-1006, " %-19s %u", "Station port:", p->station_port); + + if (!ipa_zero(p->local_addr)) + cli_msg(-1006, " %-19s %I", "Local address:", p->local_addr); + + if (p->sock_err) + cli_msg(-1006, " %-19s %M", "Last error:", p->sock_err); + } +} + struct protocol proto_bmp = { .name = "BMP", .template = "bmp%d", .class = PROTOCOL_BMP, .proto_size = sizeof(struct bmp_proto), .config_size = sizeof(struct bmp_config), + .postconfig = bmp_postconfig, .init = bmp_init, .start = bmp_start, .shutdown = bmp_shutdown, .reconfigure = bmp_reconfigure, + .get_status = bmp_get_status, + .show_proto_info = bmp_show_proto_info, }; void diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 19623e33..2d700c25 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -35,118 +35,94 @@ struct bmp_config { struct proto_config c; const char *sys_descr; // sysDescr MIB-II [RFC1213] object const char *sys_name; // sysName MIB-II [RFC1213] object + ip_addr local_addr; // Local IP address ip_addr station_ip; // Monitoring station address u16 station_port; // Monitoring station TCP port bool monitoring_rib_in_pre_policy; // Route monitoring pre-policy Adj-Rib-In - bool monitoring_rib_in_post_policy; // Route monitoring post-policy Adj-Rib-In - bool monitoring_rib_local; // Route monitoring Local Rib + bool monitoring_rib_in_post_policy; // Route monitoring post-policy Adj-Rib-In }; /* Forward declarations */ struct bgp_proto; struct bmp_proto; -// Stores sent and received BGP OPEN MSGs -struct bmp_peer_open_msg { - struct bmp_peer_map tx_msg; - struct bmp_peer_map rx_msg; -}; - -// Keeps necessary information during composing BGP UPDATE MSG which is going -// to be sent to the BMP collector -struct rt_table_info { - list update_msg_queue; // Stores all composed BGP UPDATE MSGs - size_t update_msg_size; // Size of all BGP UPDATE MSGs - struct timeval update_begin_time; // Keeps timestamp of starting BGP UPDATE MSGs composing - bool update_in_progress; // Holds information whether composing process is still in progress -}; - struct bmp_proto { struct proto p; // Parent proto const struct bmp_config *cf; // Shortcut to BMP configuration + node bmp_node; // Node in bmp_proto_list + + HASH(struct bmp_peer) peer_map; + HASH(struct bmp_stream) stream_map; + HASH(struct bmp_table) table_map; + sock *sk; // TCP connection - event *tx_ev; // TX event + event *tx_ev; // TX event + event *update_ev; // Update event char sys_descr[MIB_II_STR_LEN]; // sysDescr MIB-II [RFC1213] object char sys_name[MIB_II_STR_LEN]; // sysName MIB-II [RFC1213] object + ip_addr local_addr; // Source local IP address ip_addr station_ip; // Monitoring station IP address 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_peer_open_msg peer_open_msg; // Stores sent and received BGP OPEN MSG per BGP peer + // struct bmp_peer_map bgp_peers; // Stores 'bgp_proto' structure per BGP peer pool *buffer_mpool; // Memory pool used for BMP buffer allocations pool *map_mem_pool; // Memory pool used for BMP map allocations pool *tx_mem_pool; // Memory pool used for packet allocations designated to BMP collector pool *update_msg_mem_pool; // Memory pool used for BPG UPDATE MSG allocations list tx_queue; // Stores queued packets going to be sent timer *connect_retry_timer; // Timer for retrying connection to the BMP collector - struct rt_table_info rt_table_in_pre_policy; // Pre-policy route import table + list update_msg_queue; // Stores all composed BGP UPDATE MSGs bool started; // Flag that stores running status of BMP instance + int sock_err; // Last socket error code }; +struct bmp_peer { + struct bgp_proto *bgp; + struct bmp_peer *next; + list streams; +}; -#ifdef CONFIG_BMP +struct bmp_stream { + node n; + struct bgp_proto *bgp; + u32 key; + bool sync; + struct bmp_stream *next; + struct bmp_table *table; + struct bgp_channel *sender; +}; -/** - * bmp_put_sent_bgp_open_msg - save sent BGP OPEN msg packet in BMP implementation. - * NOTE: If there has been passed sent and received BGP OPEN MSGs to the BMP - * implementation, then there is going to be send BMP Peer Up Notification - * message to the BMP collector. - */ -void -bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, - const size_t pkt_size); +struct bmp_table { + struct rtable *table; + struct bmp_table *next; + struct channel *channel; + u32 uc; +}; -/** - * bmp_put_recv_bgp_open_msg - save received BGP OPEN msg packet in BMP implementation. - * NOTE: If there has been passed sent and received BGP OPEN MSGs to the BMP - * implementation, then there is going to be send BMP Peer Up Notification - * message to the BMP collector. - */ -void -bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, - const size_t pkt_size); + +#ifdef CONFIG_BMP /** - * The following 4 functions create BMP Route Monitoring message based on - * pre-policy Adj-RIB-In. Composing Route Monitoring message consist of few - * stages. First of all call bmp_route_monitor_update_in_pre_begin() in order - * to start composing message. As a second step, call - * bmp_route_monitor_put_update_in_pre_msg() in order to save BGP UPDATE msg. - * As a third step call bmp_route_monitor_update_in_pre_commit() in order to - * send BMP Route Monitoring message to the BMP collector. As a last step, - * call bmp_route_monitor_update_in_pre_end() in order to release resources. + * bmp_peer_up - send notification that BGP peer connection is established */ void -bmp_route_monitor_update_in_pre_begin(void); - -void -bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size); - -void -bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp); - -void -bmp_route_monitor_update_in_pre_end(void); +bmp_peer_up(struct bgp_proto *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, const int err_class, const byte *pkt, - size_t pkt_size); +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_put_sent_bgp_open_msg(const struct bgp_proto *bgp UNUSED, const byte* pkt UNUSED, const size_t pkt_size UNUSED) { } -static inline void bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp UNUSED, const byte* pkt UNUSED, const size_t pkt_size UNUSED) { } -static inline void bmp_route_monitor_update_in_pre_begin(void) { } -static inline void bmp_route_monitor_put_update_in_pre_msg(const byte *data UNUSED, const size_t data_size UNUSED) { } -static inline void bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp UNUSED) { } -static inline void bmp_route_monitor_update_in_pre_end(void) { } -static inline void bmp_peer_down(const struct bgp_proto *bgp UNUSED, const int err_class UNUSED, const byte *pkt UNUSED, size_t pkt_size UNUSED) { } +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 */ diff --git a/proto/bmp/buffer.c b/proto/bmp/buffer.c index f471e08a..be9dd698 100644 --- a/proto/bmp/buffer.c +++ b/proto/bmp/buffer.c @@ -15,7 +15,6 @@ bmp_buffer_alloc(pool *ppool, const size_t n) buf.start = mb_alloc(ppool, n); buf.pos = buf.start; buf.end = buf.start + n; - return buf; } @@ -26,33 +25,41 @@ bmp_buffer_free(buffer *buf) buf->start = buf->pos = buf->end = NULL; } +/** + * @brief bmp_buffer_grow + * @param buf - buffer to grow + * @param n - required amount of available space + * Resize buffer in a way that there is at least @n bytes of available space. + */ static void bmp_buffer_grow(buffer *buf, const size_t n) { - const size_t pos = bmp_buffer_pos(buf); - buf->start = mb_realloc(buf->start, n); + size_t pos = bmp_buffer_pos(buf); + size_t size = bmp_buffer_size(buf); + size_t req = pos + n; + + while (size < req) + size = size * 3 / 2; + + buf->start = mb_realloc(buf->start, size); buf->pos = buf->start + pos; - buf->end = buf->start + n; + buf->end = buf->start + size; } void bmp_buffer_need(buffer *buf, const size_t n) { if (bmp_buffer_avail(buf) < n) - { bmp_buffer_grow(buf, n); - } } void bmp_put_data(buffer *buf, const void *src, const size_t n) { if (!n) - { return; - } bmp_buffer_need(buf, n); memcpy(buf->pos, src, n); buf->pos += n; -}
\ No newline at end of file +} diff --git a/proto/bmp/config.Y b/proto/bmp/config.Y index 776d7ecc..acb0c4d9 100644 --- a/proto/bmp/config.Y +++ b/proto/bmp/config.Y @@ -25,13 +25,8 @@ proto: bmp_proto '}' ; bmp_proto_start: proto_start BMP { this_proto = proto_config_new(&proto_bmp, $1); - BMP_CFG->station_ip = IPA_NONE4; - BMP_CFG->station_port = 0; BMP_CFG->sys_descr = "Not defined"; BMP_CFG->sys_name = "Not defined"; - BMP_CFG->monitoring_rib_in_pre_policy = false; - BMP_CFG->monitoring_rib_in_post_policy = false; - BMP_CFG->monitoring_rib_local = false; } ; @@ -52,6 +47,9 @@ bmp_station_address: bmp_proto: bmp_proto_start proto_name '{' | bmp_proto proto_item ';' + | bmp_proto LOCAL ADDRESS ipa ';' { + BMP_CFG->local_addr = $4; + } | bmp_proto STATION ADDRESS bmp_station_address ';' | bmp_proto SYSTEM DESCRIPTION text ';' { if (!$4 || (strlen($4) == 0)) @@ -73,9 +71,6 @@ bmp_proto: | bmp_proto MONITORING RIB IN POST_POLICY bool ';' { BMP_CFG->monitoring_rib_in_post_policy = $6; } - | bmp_proto MONITORING RIB LOCAL bool ';' { - BMP_CFG->monitoring_rib_local = $5; - } ; CF_CODE |