From a848dad40aa618e5e24417e4ef46b62c860de679 Mon Sep 17 00:00:00 2001 From: Pawel Maslanka Date: Mon, 29 Mar 2021 22:45:21 +0200 Subject: [PATCH 01/14] BMP protocol support Initial implementation of a basic subset of the BMP (BGP Monitoring Protocol, RFC 7854) from Akamai team. Submitted for further review and improvement. --- configure.ac | 3 +- nest/protocol.h | 5 +- nest/rt-table.c | 11 + proto/Doc | 1 + proto/bgp/attrs.c | 7 + proto/bgp/bgp.c | 11 + proto/bgp/bgp.h | 14 + proto/bgp/packets.c | 352 +++++++++++- proto/bmp/Doc | 1 + proto/bmp/LICENSE | 2 + proto/bmp/Makefile | 6 + proto/bmp/README.txt | 6 + proto/bmp/bmp.c | 1279 ++++++++++++++++++++++++++++++++++++++++++ proto/bmp/bmp.h | 152 +++++ proto/bmp/buffer.c | 58 ++ proto/bmp/buffer.h | 78 +++ proto/bmp/config.Y | 90 +++ proto/bmp/map.c | 155 +++++ proto/bmp/map.h | 70 +++ proto/bmp/utils.h | 94 ++++ 20 files changed, 2391 insertions(+), 4 deletions(-) create mode 100644 proto/bmp/Doc create mode 100644 proto/bmp/LICENSE create mode 100644 proto/bmp/Makefile create mode 100644 proto/bmp/README.txt create mode 100644 proto/bmp/bmp.c create mode 100644 proto/bmp/bmp.h create mode 100644 proto/bmp/buffer.c create mode 100644 proto/bmp/buffer.h create mode 100644 proto/bmp/config.Y create mode 100644 proto/bmp/map.c create mode 100644 proto/bmp/map.h create mode 100644 proto/bmp/utils.h diff --git a/configure.ac b/configure.ac index d73eec28..f2091219 100644 --- a/configure.ac +++ b/configure.ac @@ -312,7 +312,7 @@ if test "$enable_mpls_kernel" != no ; then fi fi -all_protocols="$proto_bfd babel bgp mrt ospf perf pipe radv rip rpki static" +all_protocols="$proto_bfd babel bgp bmp mrt ospf perf pipe radv rip rpki static" all_protocols=`echo $all_protocols | sed 's/ /,/g'` @@ -323,6 +323,7 @@ fi AH_TEMPLATE([CONFIG_BABEL], [Babel protocol]) AH_TEMPLATE([CONFIG_BFD], [BFD protocol]) AH_TEMPLATE([CONFIG_BGP], [BGP protocol]) +AH_TEMPLATE([CONFIG_BMP], [BMP protocol]) AH_TEMPLATE([CONFIG_MRT], [MRT protocol]) AH_TEMPLATE([CONFIG_OSPF], [OSPF protocol]) AH_TEMPLATE([CONFIG_PIPE], [Pipe protocol]) diff --git a/nest/protocol.h b/nest/protocol.h index fcbf0539..03b8a8ec 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -42,6 +42,7 @@ enum protocol_class { PROTOCOL_BABEL, PROTOCOL_BFD, PROTOCOL_BGP, + PROTOCOL_BMP, PROTOCOL_DEVICE, PROTOCOL_DIRECT, PROTOCOL_KERNEL, @@ -103,7 +104,7 @@ void protos_dump_all(void); extern struct protocol proto_device, proto_radv, proto_rip, proto_static, proto_mrt, proto_ospf, proto_perf, - proto_pipe, proto_bgp, proto_bfd, proto_babel, proto_rpki; + proto_pipe, proto_bgp, proto_bmp, proto_bfd, proto_babel, proto_rpki; /* * Routing Protocol Instance @@ -213,6 +214,8 @@ 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)(const struct proto *, const struct channel *, + const net *net, const struct rte *new, const struct rte *old, const struct rte_src *src); void (*neigh_notify)(struct neighbor *neigh); int (*preexport)(struct channel *, struct rte *rt); void (*reload_routes)(struct channel *); diff --git a/nest/rt-table.c b/nest/rt-table.c index e4b27814..553e8223 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -3095,6 +3095,10 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr if (old->flags & (REF_STALE | REF_DISCARD | REF_MODIFY)) { old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY); + + if (c->proto->rte_update_in_notify) + c->proto->rte_update_in_notify(c->proto, c, net, new, old, src); + return 1; } @@ -3118,6 +3122,9 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr if (!old) goto drop_withdraw; + if (c->proto->rte_update_in_notify) + c->proto->rte_update_in_notify(c->proto, c, net, new, old, src); + if (!net->routes) fib_delete(&tab->fib, net); @@ -3149,6 +3156,10 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr e->next = *pos; *pos = e; tab->rt_count++; + + if (c->proto->rte_update_in_notify) + c->proto->rte_update_in_notify(c->proto, c, net, new, old, src); + return 1; drop_update: diff --git a/proto/Doc b/proto/Doc index ef573d2a..9de9eeec 100644 --- a/proto/Doc +++ b/proto/Doc @@ -2,6 +2,7 @@ H Protocols C babel C bfd C bgp +C bmp C ospf C pipe C radv diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 204151c3..de45cae0 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1151,6 +1151,13 @@ bgp_attr_known(uint code) return (code < ARRAY_SIZE(bgp_attr_table)) && bgp_attr_table[code].name; } +void bgp_fix_attr_flags(ea_list *attrs) +{ + for (u8 i = 0; i < attrs->count; i++) + { + attrs->attrs[i].flags = bgp_attr_table[EA_ID(attrs->attrs[i].id)].flags; + } +} /* * Attribute export diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 9408715e..709625ea 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -125,6 +125,7 @@ #include "lib/string.h" #include "bgp.h" +#include "proto/bmp/bmp.h" static list STATIC_LIST_INIT(bgp_sockets); /* Global list of listening sockets */ @@ -866,7 +867,10 @@ bgp_graceful_restart_timeout(timer *t) } } else + { bgp_stop(p, 0, NULL, 0); + bmp_peer_down(p, BE_NONE, NULL, BMP_PEER_DOWN_NULL_PKT_SIZE); + } } static void @@ -990,7 +994,10 @@ 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, BMP_PEER_DOWN_NULL_PKT_SIZE); + } if ((conn->state == BS_ESTABLISHED) && p->gr_ready) bgp_handle_graceful_restart(p); @@ -1315,6 +1322,7 @@ 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, BMP_PEER_DOWN_NULL_PKT_SIZE); } } else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP)) @@ -1326,6 +1334,7 @@ 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, BMP_PEER_DOWN_NULL_PKT_SIZE); } } else @@ -1367,6 +1376,7 @@ 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, BMP_PEER_DOWN_NULL_PKT_SIZE); } } } @@ -1684,6 +1694,7 @@ bgp_init(struct proto_config *CF) struct bgp_config *cf = (struct bgp_config *) CF; P->rt_notify = bgp_rt_notify; + P->rte_update_in_notify = bgp_rte_update_in_notify; P->preexport = bgp_preexport; P->neigh_notify = bgp_neigh_notify; P->reload_routes = bgp_reload_routes; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 302f58e7..c4f4f3be 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -496,6 +496,13 @@ struct bgp_parse_state { #define BGP_CF_WALK_CHANNELS(P,C) WALK_LIST(C, P->c.channels) if (C->c.channel == &channel_bgp) #define BGP_WALK_CHANNELS(P,C) WALK_LIST(C, P->p.channels) if (C->c.channel == &channel_bgp) +#define BGP_MSG_HDR_MARKER_SIZE 16 +#define BGP_MSG_HDR_MARKER_POS 0 +#define BGP_MSG_HDR_LENGTH_SIZE 2 +#define BGP_MSG_HDR_LENGTH_POS BGP_MSG_HDR_MARKER_SIZE +#define BGP_MSG_HDR_TYPE_SIZE 1 +#define BGP_MSG_HDR_TYPE_POS (BGP_MSG_HDR_MARKER_SIZE + BGP_MSG_HDR_LENGTH_SIZE) + static inline int bgp_channel_is_ipv4(struct bgp_channel *c) { return BGP_AFI(c->afi) == BGP_AFI_IPV4; } @@ -542,6 +549,8 @@ void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code void bgp_stop(struct bgp_proto *p, int subcode, byte *data, uint len); const char *bgp_format_role_name(u8 role); +void bgp_fix_attr_flags(ea_list *attrs); + static inline int rte_resolvable(rte *rt) { @@ -615,6 +624,9 @@ 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(const struct proto *P, const struct channel *C, + const net *net, const struct rte *new, const struct rte *old, + 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); @@ -648,6 +660,7 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi 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); /* Packet types */ @@ -658,6 +671,7 @@ void bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to); #define PKT_ROUTE_REFRESH 0x05 /* [RFC2918] */ #define PKT_BEGIN_REFRESH 0x1e /* Dummy type for BoRR packet [RFC7313] */ #define PKT_SCHEDULE_CLOSE 0x1f /* Used internally to schedule socket close */ +#define PKT_BMP_MSG 0x20 /* BGP Monitoring Protocol message [RFC7854] */ /* Attributes */ diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 5c17c370..bec8cd91 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -26,6 +26,7 @@ #include "nest/cli.h" #include "bgp.h" +#include "proto/bmp/bmp.h" #define BGP_RR_REQUEST 0 @@ -166,6 +167,7 @@ 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; } @@ -975,6 +977,7 @@ 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); } @@ -2239,6 +2242,224 @@ bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to) #define MAX_ATTRS_LENGTH (end-buf+BGP_HEADER_LENGTH - 1024) +/** + * Following functions starting with prefix bgp_bmp_* compose BGP UPDATE messages. + * Their implementation has been adopted from relevant function without 'bmp_' part in + * their names. + */ + +// Buffer @buf should be big enough. It means that there should be available at least 19 bytes +static byte * +bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type) +{ + if (!buf) + { + return NULL; + } + + memset(buf + BGP_MSG_HDR_MARKER_POS, 0xff, BGP_MSG_HDR_MARKER_SIZE); + put_u16(buf + BGP_MSG_HDR_LENGTH_POS, msg_size); + put_u8(buf + BGP_MSG_HDR_TYPE_POS, msg_type); + + return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE; +} + +static uint +bgp_bmp_encode_nlri_ip4(struct bgp_write_state *s, const net *n, + const u32 path_id, byte *buf, uint size) +{ + const struct net_addr_ip4 *naddr = (net_addr_ip4 *)n->n.addr; + + byte *pos = buf; + /* Encode path ID */ + if (s->add_path) + { + put_u32(pos, path_id); + ADVANCE(pos, size, 4); + } + + /* Encode prefix length */ + *pos = naddr->pxlen; + ADVANCE(pos, size, 1); + + /* Encode MPLS labels */ + if (s->mpls) + { + bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1); + } + + /* Encode prefix body */ + ip4_addr a = ip4_hton(naddr->prefix); + uint b = (naddr->pxlen + 7) / 8; + memcpy(pos, &a, b); + ADVANCE(pos, size, b); + + return pos - buf; +} + +static uint +bgp_bmp_encode_nlri_ip6(struct bgp_write_state *s, const net *n, + const u32 path_id, byte *buf, uint size) +{ + if (size < BGP_NLRI_MAX) + { + return 0; + } + + const struct net_addr_ip6 *naddr = (net_addr_ip6 *)n->n.addr; + byte *pos = buf; + /* Encode path ID */ + if (s->add_path) + { + put_u32(pos, path_id); + ADVANCE(pos, size, 4); + } + + /* Encode prefix length */ + *pos = naddr->pxlen; + ADVANCE(pos, size, 1); + + /* Encode MPLS labels */ + if (s->mpls) + { + bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1); + } + + /* Encode prefix body */ + ip6_addr a = ip6_hton(naddr->prefix); + uint b = (naddr->pxlen + 7) / 8; + memcpy(pos, &a, b); + ADVANCE(pos, size, b); + + return pos - buf; +} + +static byte * +bgp_bmp_create_ip_reach(struct bgp_write_state *s, const net *n, + const struct rte *new, const struct rte *old, const u32 path_id, + byte *buf, uint size) +{ + /* + * 2 B Withdrawn Routes Length (zero) + * --- IPv4 Withdrawn Routes NLRI (unused) + * 2 B Total Path Attribute Length + * var Path Attributes + * var IPv4 Network Layer Reachability Information + */ + + int lr, la; // Route length, attribute length + ea_list *attrs = new ? new->attrs->eattrs : old->attrs->eattrs; + bgp_fix_attr_flags(attrs); + + la = bgp_encode_attrs(s, attrs, buf + 2, buf + size - 2); + if (la < 0) + { + /* Attribute list too long */ + log(L_ERR "Failed to encode UPDATE msg attributes"); + return NULL; + } + + put_u16(buf, la); + lr = bgp_bmp_encode_nlri_ip4(s, n, path_id, buf + 2 + la, size - (2 + la)); + + return buf + 2 + la + lr; +} + +static byte * +bgp_bmp_create_mp_reach(struct bgp_write_state *s, const net *n, + const struct rte *new, const struct rte *old, const u32 path_id, + byte *buf, uint size) +{ + /* + * 2 B IPv4 Withdrawn Routes Length (zero) + * --- IPv4 Withdrawn Routes NLRI (unused) + * 2 B Total Path Attribute Length + * 1 B MP_REACH_NLRI hdr - Attribute Flags + * 1 B MP_REACH_NLRI hdr - Attribute Type Code + * 2 B MP_REACH_NLRI hdr - Length of Attribute Data + * 2 B MP_REACH_NLRI data - Address Family Identifier + * 1 B MP_REACH_NLRI data - Subsequent Address Family Identifier + * 1 B MP_REACH_NLRI data - Length of Next Hop Network Address + * var MP_REACH_NLRI data - Network Address of Next Hop + * 1 B MP_REACH_NLRI data - Reserved (zero) + * var MP_REACH_NLRI data - Network Layer Reachability Information + * var Rest of Path Attributes + * --- IPv4 Network Layer Reachability Information (unused) + */ + + int lh, lr, la; /* Lengths of next hop, NLRI and attributes */ + + /* Begin of MP_REACH_NLRI atribute */ + buf[4] = BAF_OPTIONAL | BAF_EXT_LEN; + buf[5] = BA_MP_REACH_NLRI; + put_u16(buf+6, 0); /* Will be fixed later */ + put_af3(buf+8, s->channel->afi); + byte *pos = buf+11; + byte *end = buf + size; + /* Encode attributes to temporary buffer */ + byte *abuf = alloca(MAX_ATTRS_LENGTH); + + ea_list *attrs = new ? new->attrs->eattrs : old->attrs->eattrs; + bgp_fix_attr_flags(attrs); + + la = bgp_encode_attrs(s, attrs, abuf, abuf + MAX_ATTRS_LENGTH); + if (la < 0) + { + /* Attribute list too long */ + log(L_ERR "Failed to encode UPDATE msg attributes"); + return NULL; + } + + /* Encode the next hop */ + lh = bgp_encode_next_hop(s, s->mp_next_hop, pos+1); + *pos = lh; + pos += 1+lh; + + /* Reserved field */ + *pos++ = 0; + + /* Encode the NLRI */ + lr = bgp_bmp_encode_nlri_ip6(s, n, path_id, pos, end - (buf + la)); + pos += lr; + + /* End of MP_REACH_NLRI atribute, update data length */ + put_u16(buf+6, pos-buf-8); + + /* Copy remaining attributes */ + memcpy(pos, abuf, la); + pos += la; + + /* Initial UPDATE fields */ + put_u16(buf+0, 0); + put_u16(buf+2, pos-buf-4); + + return pos; +} + +static byte * +bgp_bmp_create_ip_unreach(struct bgp_write_state *s, const net *n, + const struct rte *new, const struct rte *old, const u32 path_id, + byte *buf, uint size) +{ + /* + * 2 B Withdrawn Routes Length + * var IPv4 Withdrawn Routes NLRI + * 2 B Total Path Attribute Length (zero) + * --- Path Attributes (unused) + * --- IPv4 Network Layer Reachability Information (unused) + */ + + uint len = 0; + bool is_withdrawn = !new && old; + if (is_withdrawn) + { + len = bgp_bmp_encode_nlri_ip4(s, n, path_id, buf + 2, size - 2); + } + + put_u16(buf, len); + return buf + 2 + len; +} + static byte * bgp_create_ip_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, byte *end) { @@ -2384,6 +2605,122 @@ bgp_create_mp_unreach(struct bgp_write_state *s, struct bgp_bucket *buck, byte * return buf+11+len; } +static byte * +bgp_bmp_create_mp_unreach(struct bgp_write_state *s, const net *n, + const struct rte *new, const struct rte *old, const u32 path_id, + byte *buf, uint size) +{ + /* + * 2 B Withdrawn Routes Length (zero) + * --- IPv4 Withdrawn Routes NLRI (unused) + * 2 B Total Path Attribute Length + * 1 B MP_UNREACH_NLRI hdr - Attribute Flags + * 1 B MP_UNREACH_NLRI hdr - Attribute Type Code + * 2 B MP_UNREACH_NLRI hdr - Length of Attribute Data + * 2 B MP_UNREACH_NLRI data - Address Family Identifier + * 1 B MP_UNREACH_NLRI data - Subsequent Address Family Identifier + * var MP_UNREACH_NLRI data - Network Layer Reachability Information + * --- IPv4 Network Layer Reachability Information (unused) + */ + + uint len = 0; + bool is_withdrawn = !new && old; + if (is_withdrawn) + { + len = bgp_bmp_encode_nlri_ip6(s, n, path_id, buf + 11, size); + } + + put_u16(buf+0, 0); + put_u16(buf+2, 7+len); + + /* Begin of MP_UNREACH_NLRI atribute */ + buf[4] = BAF_OPTIONAL | BAF_EXT_LEN; + buf[5] = BA_MP_UNREACH_NLRI; + + put_u16(buf+6, 3+len); + put_af3(buf+8, s->channel->afi); + + return buf+11+len; +} + +void +bgp_rte_update_in_notify(const struct proto *P, const struct channel *C, + const net *n, const struct rte *new, const struct rte *old, + const struct rte_src *src) +{ + struct bgp_proto *p = (struct bgp_proto *)P; + struct bgp_channel *c = (struct bgp_channel *)C; + byte buf[BGP_MAX_EXT_MSG_LENGTH] = { 0x00 }; + byte *pkt = buf + BGP_HEADER_LENGTH; + byte *end = pkt + (bgp_max_packet_length(p->conn) - BGP_HEADER_LENGTH); + + 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 = (bgp_channel_is_ipv6(c) || rem->ext_next_hop), + .as4_session = peer->as4_support, + .add_path = c->add_path_rx, + .mpls = c->desc->mpls, + }; + + const u32 path_id = c->add_path_rx ? src->private_id : 0; + byte *pos = pkt; + if (!s.mp_reach) + { + pos = bgp_bmp_create_ip_unreach(&s, n, new, old, path_id, pkt, end - pkt); + if (!pos) + { + log(L_ERR "Failed to create unreachable field in UPDATE message"); + return; + } + + pos = bgp_bmp_create_ip_reach(&s, n, new, old, path_id, pos, end - pos); + if (!pos) + { + log(L_ERR "Failed to create reachable field in UPDATE message"); + return; + } + + bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE); + bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf); + } + else if (new) // && s.mp_reach + { + pos = s.mp_reach + ? bgp_bmp_create_mp_reach(&s, n, new, old, path_id, pos, end - pos) + : bgp_bmp_create_ip_reach(&s, n, new, old, path_id, pos, end - pos); + if (!pos) + { + log(L_ERR "Failed to create reachable field in UPDATE message"); + return; + } + + bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE); + bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf); + } + + if (!new && old) + { + bmp_route_monitor_update_in_pre_commit(p); + bmp_route_monitor_update_in_pre_end(); + bmp_route_monitor_update_in_pre_begin(); + pkt = buf + BGP_HEADER_LENGTH; + end = pkt + (bgp_max_packet_length(p->conn) - BGP_HEADER_LENGTH); + pos = bgp_bmp_create_mp_unreach(&s, n, new, old, path_id, pkt, end - pkt); + if (!pos) + { + log(L_ERR "Failed to create unreachable field in UPDATE message"); + return; + } + + bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE); + bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf); + } +} + static byte * bgp_create_update(struct bgp_channel *c, byte *buf) { @@ -2484,7 +2821,7 @@ bgp_create_mp_end_mark(struct bgp_channel *c, byte *buf) return buf+10; } -static byte * +byte * bgp_create_end_mark(struct bgp_channel *c, byte *buf) { struct bgp_proto *p = (void *) c->c.proto; @@ -2635,6 +2972,7 @@ 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); @@ -2666,6 +3004,9 @@ 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); @@ -2917,7 +3258,12 @@ bgp_fire_tx(struct bgp_conn *conn) { conn->packets_to_send &= ~(1 << PKT_OPEN); end = bgp_create_open(conn, pkt); - return bgp_send(conn, PKT_OPEN, end - buf); + int rv = bgp_send(conn, PKT_OPEN, end - buf); + if (rv >= 0) + { + bmp_put_sent_bgp_open_msg(p, pkt, end - buf); + } + return rv; } else if (s & (1 << PKT_KEEPALIVE)) { @@ -3216,6 +3562,8 @@ 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/Doc b/proto/bmp/Doc new file mode 100644 index 00000000..69b6e807 --- /dev/null +++ b/proto/bmp/Doc @@ -0,0 +1 @@ +S bmp.c diff --git a/proto/bmp/LICENSE b/proto/bmp/LICENSE new file mode 100644 index 00000000..1772f08d --- /dev/null +++ b/proto/bmp/LICENSE @@ -0,0 +1,2 @@ +The patch is provided under the terms of the GNU General Public License, either +version 2, or any later version. \ No newline at end of file diff --git a/proto/bmp/Makefile b/proto/bmp/Makefile new file mode 100644 index 00000000..d6fca1aa --- /dev/null +++ b/proto/bmp/Makefile @@ -0,0 +1,6 @@ +src := bmp.c buffer.c map.c +obj := $(src-o-files) +$(all-daemon) +$(cf-local) + +tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file diff --git a/proto/bmp/README.txt b/proto/bmp/README.txt new file mode 100644 index 00000000..386f4029 --- /dev/null +++ b/proto/bmp/README.txt @@ -0,0 +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 +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 diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c new file mode 100644 index 00000000..5d4e1ac3 --- /dev/null +++ b/proto/bmp/bmp.c @@ -0,0 +1,1279 @@ +/* + * 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. + */ + +/** + * DOC: BGP Monitoring Protocol (BMP) + * + * Supported standards: + * o RFC 7854 - BMP standard + * + * TODO: + * - Support Peer Distinguisher ID in Per-Peer Header + * - Support peer type as RD Instance in Peer Type field of Per-Peer Header. + * Currently, there are supported Global and Local Instance Peer types + * - Support corresponding FSM event code during send PEER DOWN NOTIFICATION + * - Support DE_CONFIGURED PEER DOWN REASON code in PEER DOWN NOTIFICATION message + * - If connection with BMP collector will lost then we don't establish connection again + * - Set Peer Type by its a global and local-scope IP address + */ + +#include "proto/bmp/bmp.h" +#include "proto/bmp/buffer.h" +#include "proto/bmp/map.h" +#include "proto/bmp/utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nest/cli.h" +#include "filter/filter.h" +#include "proto/bgp/bgp.h" +#include "sysdep/unix/unix.h" +#include "lib/event.h" +#include "lib/ip.h" +#include "lib/lists.h" +#include "lib/resource.h" +#include "lib/unaligned.h" +#include "nest/iface.h" +#include "nest/route.h" + +// We allow for single instance of BMP protocol +static struct bmp_proto *g_bmp; + +/* BMP Common Header [RFC 7854 - Section 4.1] */ +enum bmp_version { + BMP_VER_UNUSED = 0, // Version 0 is reserved and MUST NOT be sent + BMP_VERSION_1 = 1, // Version 1 was used by draft version of RFC 7854 + BMP_VERSION_2 = 2, // Version 2 was used by draft version of RFC 7854 + BMP_VERSION_3 = 3 // Version 3 is used by all messages defined in RFC 7854 +}; + +enum bmp_message_type { + BMP_ROUTE_MONITOR = 0, // Route Monitoring + BMP_STATS_REPORT = 1, // Statistics Report + BMP_PEER_DOWN_NOTIF = 2, // Peer Down Notification + BMP_PEER_UP_NOTIF = 3, // Peer Up Notification + BMP_INIT_MSG = 4, // Initiation Message + BMP_TERM_MSG = 5, // Termination Message + BMP_ROUTE_MIRROR_MSG = 6 // Route Mirroring Message +}; + +// Total size of Common Header +#define BMP_COMMON_HDR_SIZE 6 +// Defines size of padding when IPv4 address is going to be put into field +// which can accept also IPv6 address +#define BMP_PADDING_IP4_ADDR_SIZE 12 + +/* BMP Per-Peer Header [RFC 7854 - Section 4.2] */ +// Total size of Per-Peer Header +#define BMP_PER_PEER_HDR_SIZE 42 + +enum bmp_peer_type { + BMP_PEER_TYPE_GLOBAL_INSTANCE = 0, + BMP_PEER_TYPE_RD_INSTANCE = 1, + BMP_PEER_TYPE_LOCAL_INSTANCE = 2 +}; + +#define BMP_PEER_HDR_FLAG_V_SHIFT 7 +enum bmp_peer_flag_v_t { + // The Peer address is an IPv4 address + BMP_PEER_HDR_FLAG_V_IP4 = (0 << BMP_PEER_HDR_FLAG_V_SHIFT), + // The Peer address is an IPv6 address + BMP_PEER_HDR_FLAG_V_IP6 = (1 << BMP_PEER_HDR_FLAG_V_SHIFT) +}; + +#define BMP_PEER_HDR_FLAG_L_SHIFT 6 +enum bmp_peer_flag_l { + BMP_PEER_HDR_FLAG_L_PRE_POLICY_ADJ_RIB_IN = (0 << BMP_PEER_HDR_FLAG_L_SHIFT), + BMP_PEER_HDR_FLAG_L_POST_POLICY_ADJ_RIB_IN = (1 << BMP_PEER_HDR_FLAG_L_SHIFT) +}; + +#define BMP_PEER_HDR_FLAG_A_SHIFT 5 +enum bmp_peer_flag_a { + // The 4-byte AS_PATH format + BMP_PEER_HDR_FLAG_A_AS_PATH_4B = (0 << BMP_PEER_HDR_FLAG_A_SHIFT), + // The legacy 2-byte AS_PATH format + BMP_PEER_HDR_FLAG_A_AS_PATH_2B = (1 << BMP_PEER_HDR_FLAG_A_SHIFT) +}; + +#define BMP_PEER_HDR_FLAGS_INIT(flags) \ + (flags) = 0 +#define BMP_PEER_HDR_FLAGS_SET(flags, bit_mask) \ + (flags) |= (bit_mask) + +/* BMP Information TLV header [RFC 7854 - Section 4.4] */ +// Total size of Type and Length fields of Information TLV Header without +// variable part +#define BMP_INFO_TLV_FIX_SIZE 4 + +enum bmp_info_tlv_type { + BMP_INFO_TLV_TYPE_STRING = 0, // String + BMP_INFO_TLV_TYPE_SYS_DESCR = 1, // SysDescr + BMP_INFO_TLV_TYPE_SYS_NAME = 2 // SysName +}; + +/* BMP Peer Up Notification message header [RFC 7854 - Section 4.10] */ +// Total size of all fields of Peer Up Notification message except variable part +#define BMP_PEER_UP_NOTIF_MSG_FIX_SIZE 20 + +enum bmp_peer_down_notif_reason { + // The local system closed the session + BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION = 1, + // The local system closed the session + BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION = 2, + // The remote system closed the session with a notification message + BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION = 3, + // The remote system closed the session without a notification message + BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION = 4, + // Information for this peer will no longer be sent to the monitoring station + // for configuration reasons + BMP_PEER_DOWN_REASON_PEER_DE_CONFIGURED = 5 +}; + +/* BMP Termination Message [RFC 7854 - Section 4.5] */ +#define BMP_TERM_INFO_TYPE_SIZE 2 +enum bmp_term_info_type { + BMP_TERM_INFO_STRING = 0, // The Information field contains string + BMP_TERM_INFO_REASON = 1, // The Information field contains 2-byte reason code +}; + +// 2-byte code in the Information field +#define BMP_TERM_REASON_CODE_SIZE 2 +enum bmp_term_reason { + BMP_TERM_REASON_ADM = 0, // Session administratively closed + BMP_TERM_REASON_UNK = 1, // Unspecified reason + BMP_TERM_REASON_OOR = 2, // Out of resources + BMP_TERM_REASON_DUP = 3, // Redundant connection + BMP_TERM_REASON_PERM = 4, // Session permanently administratively closed +}; + +// Size of Information Length field in Termination Message header +#define BMP_TERM_INFO_LEN_FIELD_SIZE 2 + +// Default chunk size request when memory allocation +#define DEFAULT_MEM_BLOCK_SIZE 4096 + +// Timeout for connection to the BMP collector retry +#define CONNECT_RETRY_SEC (10 S) + +#define IP4_MAX_TTL 255 + +// Handle BIRD socket error event +static void +bmp_sock_err(sock *sk, int err); + +static enum bmp_result +bmp_send_peer_up_notif_msg(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); + +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); + +// 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(const struct channel *C); + +static void +bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size) +{ + bmp_put_u8(stream, BMP_VERSION_3); + bmp_put_u32(stream, BMP_COMMON_HDR_SIZE + data_size); + bmp_put_u8(stream, type); +} + +static enum bmp_result +bmp_info_tlv_hdr_serialize(buffer *stream, const enum bmp_info_tlv_type type, + const char *ascii) +{ + const size_t ascii_len = strlen(ascii); + if (ascii_len > MIB_II_STR_LEN) + { + return BMP_E_INVALID_ARG; + } + + bmp_put_u16(stream, type); + // It doesn't contain null terminating character '\0' + bmp_put_u16(stream, ascii_len); + bmp_put_data(stream, ascii, ascii_len); + + return BMP_E_NONE; +} + +// Serializes BMP Initiation message header [RFC 7854 - Section 4.3] +static enum bmp_result +bmp_init_msg_serialize(buffer *stream, const char *sys_descr, const char *sys_name) +{ + const size_t sys_descr_len = strlen(sys_descr); + const size_t sys_name_len = strlen(sys_name); + // We include MIB-II sysDescr and sysName in BMP INIT MSG so that's why + // allocated 2x BMP_INFO_TLV_FIX_SIZE memory pool size + const size_t data_size = (2 * BMP_INFO_TLV_FIX_SIZE) + sys_descr_len + sys_name_len; + bmp_buffer_need(stream, BMP_COMMON_HDR_SIZE + data_size); + bmp_common_hdr_serialize(stream, BMP_INIT_MSG, data_size); + IF_BMP_FAILED_RETURN_RC( + bmp_info_tlv_hdr_serialize(stream, BMP_INFO_TLV_TYPE_SYS_DESCR, sys_descr) + ); + + IF_BMP_FAILED_RETURN_RC( + bmp_info_tlv_hdr_serialize(stream, BMP_INFO_TLV_TYPE_SYS_NAME, sys_name) + ); + + return BMP_E_NONE; +} + +static enum bmp_result +bmp_schedule_tx_packet(const byte *payload, const size_t size) +{ + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + !g_bmp->station_connected, + "Not BMP station connected yet", + BMP_E_CONNECT_TO_SRV + ); + + struct bmp_data_node *tx_data = mb_alloc(g_bmp->tx_mem_pool, sizeof (struct bmp_data_node)); + tx_data->data = mb_alloc(g_bmp->tx_mem_pool, size); + memcpy(tx_data->data, payload, size); + tx_data->data_size = size; + add_tail(&g_bmp->tx_queue, &tx_data->n); + if (sk_tx_buffer_empty(g_bmp->conn->sk) + && !ev_active(g_bmp->conn->tx_ev)) + { + ev_schedule(g_bmp->conn->tx_ev); + } + + return BMP_E_NONE; +} + +/** + * bmp_startup - connect to the BMP collector. + * NOTE: Send Initiation Message to the BMP collector. + */ +static enum bmp_result +bmp_startup(void) +{ + if (g_bmp->started || !g_bmp->station_connected) + { + return BMP_E_NONE; + } + + enum bmp_result rc = BMP_E_NONE; + buffer payload + = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); + IF_BMP_FAILED_GOTO_LABEL( + bmp_init_msg_serialize(&payload, g_bmp->sys_descr, g_bmp->sys_name), + err + ); + + IF_BMP_FAILED_GOTO_LABEL( + bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)), + err + ); + + g_bmp->started = true; + +err: + bmp_buffer_free(&payload); + return rc; +} + +void +bmp_fire_tx(void *vconn) +{ + struct bmp_conn *conn = (struct bmp_conn *) vconn; + IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + conn->sk, + "Socket is null" + ); + + byte *buf = conn->sk->tbuf; + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + EMPTY_LIST(g_bmp->tx_queue), + "Called BMP TX event handler when there is not any data to send" + ); + + size_t cnt = 0; // Counts max packets which we want to send per TX slot + struct bmp_data_node *tx_data; + struct bmp_data_node *tx_data_next; + size_t data_size = 0; + WALK_LIST_DELSAFE(tx_data, tx_data_next, g_bmp->tx_queue) + { + if (tx_data->data_size > conn->sk->tbsize) + { + sk_set_tbsize(conn->sk, tx_data->data_size); + } + + data_size = tx_data->data_size; + memcpy(buf, tx_data->data, tx_data->data_size); + mb_free(tx_data->data); + rem_node((node *) tx_data); + mb_free(tx_data); + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + (sk_send(conn->sk, data_size) == 0), + "Failed to send BMP packet", + ); + + // BMP packets should be treat with lowest priority when scheduling sending + // packets to target. That's why we want to send max. 32 packets per event + // call + if (++cnt > 32) + { + if (!ev_active(conn->tx_ev)) + { + ev_schedule(conn->tx_ev); + } + + return; + } + } +} + +static void +bmp_tx(struct birdsock *sk) +{ + IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + bmp_startup(), + "Failed to send Initation message to BMP collector" + ); + + bmp_fire_tx(sk->data); +} + +static inline enum bmp_result +bmp_open_socket(struct bmp_proto *bmp) +{ + bmp->conn->sk->daddr = bmp->station_ip; + bmp->conn->sk->dport = bmp->station_port; + bmp->conn->sk->err_hook = bmp_sock_err; + + if (sk_open(bmp->conn->sk) < 0) + { + return BMP_E_OPEN_SOCKET; + } + + return BMP_E_NONE; +} + +static void +bmp_connection_retry(timer *t) +{ + struct bmp_proto *bmp = (struct bmp_proto *) t->data; + IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + bmp_open_socket(bmp), + "Failed to connect to BMP station" + ); + + log(L_DEBUG "Connected to BMP station after connection retry"); + tm_stop(t); +} + +void +bmp_sock_err(sock *sk, int err) +{ + struct bmp_conn *conn = (struct bmp_conn *)sk->data; + log(L_WARN "[BMP:%s] Socket error: %M", conn->bmp->p.name, err); +} + +static void +bmp_put_ip4_addr_with_padding(buffer *stream, const ip4_addr addr) +{ + byte padding[BMP_PADDING_IP4_ADDR_SIZE] = { 0x00 }; + bmp_put_data(stream, padding, BMP_PADDING_IP4_ADDR_SIZE); + bmp_put_ip4(stream, addr); +} + +static void +bmp_set_initial_bgp_hdr(buffer *stream, const u16 msg_size, const u8 msg_type) +{ + 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_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 + * @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 + * @ts_sec: the time in seconds when the encapsulated routes were received + * @ts_usec: the time in microseconds when the encapsulated routes were received + */ +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 ip_addr peer_addr, const u32 peer_as, const u32 peer_bgp_id, + const u32 ts_sec, const u32 ts_usec) +{ + // TODO: ATM we don't support BMP_PEER_TYPE_RD_INSTANCE + const enum bmp_peer_type peer_type = is_global_instance_peer + ? BMP_PEER_TYPE_GLOBAL_INSTANCE + : BMP_PEER_TYPE_LOCAL_INSTANCE; + 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_a = is_as_path_4bytes + ? BMP_PEER_HDR_FLAG_A_AS_PATH_4B + : BMP_PEER_HDR_FLAG_A_AS_PATH_2B; + u8 peer_flags; + BMP_PEER_HDR_FLAGS_INIT(peer_flags); + BMP_PEER_HDR_FLAGS_SET(peer_flags, peer_flag_v); + BMP_PEER_HDR_FLAGS_SET(peer_flags, peer_flag_l); + BMP_PEER_HDR_FLAGS_SET(peer_flags, peer_flag_a); + + bmp_put_u8(stream, peer_type); + bmp_put_u8(stream, peer_flags); + // TODO: Provide appropriate peer Route Distinguisher if applicable + bmp_put_u64(stream, 0x00); // 0x00 - Not supported peer distinguisher + if (ipa_is_ip4(peer_addr)) + { + bmp_put_ip4_addr_with_padding(stream, ipa_to_ip4(peer_addr)); + } + else + { + bmp_put_ip6(stream, ipa_to_ip6(peer_addr)); + } + + bmp_put_u32(stream, peer_as); + bmp_put_u32(stream, peer_bgp_id); + bmp_put_u32(stream, ts_sec); + bmp_put_u32(stream, ts_usec); +} + +/* [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 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 data_size = BMP_PER_PEER_HDR_SIZE + update_msg_size; + 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, + as4_support, remote_addr, peer_as, peer_bgp_id, ts_sec, ts_usec); + bmp_put_data(stream, update_msg, update_msg_size); +} + +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 size_t data_size = BMP_PER_PEER_HDR_SIZE + BMP_PEER_UP_NOTIF_MSG_FIX_SIZE + + sent_msg_size + recv_msg_size; + 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, + peer_as, peer_bgp_id, 0, 0); // 0, 0 - No timestamp provided + if (ipa_is_ip4(local_addr)) + { + bmp_put_ip4_addr_with_padding(stream, ipa_to_ip4(local_addr)); + } + else + { + bmp_put_ip6(stream, ipa_to_ip6(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); +} + +static void +bmp_peer_down_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 remote_addr, const byte *data, const size_t data_size) +{ + const size_t payload_size = BMP_PER_PEER_HDR_SIZE + data_size; + 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, + peer_as, peer_bgp_id, 0, 0); // 0, 0 - No timestamp provided + bmp_put_data(stream, data, data_size); +} + +/** + * bmp_open - initialize internal resources of BMP implementation. + * NOTE: It does not connect to BMP collector yet. + */ +enum bmp_result +bmp_open(const struct proto *P) +{ + struct bmp_proto *bmp = (struct bmp_proto *) P; + g_bmp = bmp; + enum bmp_result rc = BMP_E_NONE; + + log(L_DEBUG "Init BMP"); + if (!P) + { + return BMP_E_NULL_REF; + } + + g_bmp->buffer_mpool = rp_new(P->pool, "BMP Buffer"); + g_bmp->map_mem_pool = rp_new(P->pool, "BMP Map"); + g_bmp->tx_mem_pool = rp_new(P->pool, "BMP Tx"); + g_bmp->update_msg_mem_pool = rp_new(P->pool, "BMP Update"); + bmp->conn->tx_ev = ev_new_init(g_bmp->tx_mem_pool, bmp_fire_tx, bmp->conn); + if (!bmp->conn->tx_ev) + { + return BMP_E_NEW_TX_EVENT; + } + + IF_BMP_FAILED_RETURN_RC( + bmp_peer_map_init(&g_bmp->peer_open_msg.tx_msg, g_bmp->map_mem_pool) + ); + + IF_BMP_FAILED_GOTO_LABEL( + bmp_peer_map_init(&g_bmp->peer_open_msg.rx_msg, g_bmp->map_mem_pool), + err_free_ip_map_tx_msg + ); + + IF_BMP_FAILED_GOTO_LABEL( + bmp_peer_map_init(&g_bmp->bgp_peers, g_bmp->map_mem_pool), + err_free_ip_map_rx_msg + ); + + init_list(&g_bmp->tx_queue); + init_list(&g_bmp->rt_table_in_pre_policy.update_msg_queue); + g_bmp->station_connected = false; + g_bmp->started = false; + g_bmp->connect_retry_timer = NULL; + if (BMP_FAILED(bmp_open_socket(bmp))) + { + log(L_DEBUG "Failed to connect to BMP station"); + g_bmp->connect_retry_timer = tm_new_init(P->pool, bmp_connection_retry, bmp, + CONNECT_RETRY_SEC, 0 /* not randomized */); + tm_start(g_bmp->connect_retry_timer, CONNECT_RETRY_SEC); + g_bmp->station_connected = false; + } + else + { + log(L_DEBUG "Connected to BMP station"); + } + + strncpy(g_bmp->sys_name, bmp->sys_name, sizeof (g_bmp->sys_name) - 1); + strncpy(g_bmp->sys_descr, bmp->sys_descr, sizeof (g_bmp->sys_descr) - 1); + return BMP_E_NONE; + +err_free_ip_map_rx_msg: + bmp_peer_map_free(&g_bmp->peer_open_msg.rx_msg); + +err_free_ip_map_tx_msg: + bmp_peer_map_free(&g_bmp->peer_open_msg.tx_msg); + return rc; +} + +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) +{ + const struct bmp_peer_map_entry *map_rx_msg = bmp_peer_map_get(&g_bmp->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" + ); + + const struct bmp_peer_map_entry *map_bgp_proto = bmp_peer_map_get(&g_bmp->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" + ); + + const struct bgp_proto *bgp; + memcpy(&bgp, map_bgp_proto->data.buf, sizeof (bgp)); + if (bgp->p.proto_state == PS_UP) + { + IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + bmp_send_peer_up_notif_msg(bgp, tx_msg, tx_msg_size, map_rx_msg->data.buf, + map_rx_msg->data.buf_size), + "Failed to send BMP Peer Up Notification MSG" + ); + } +} + +static void +bmp_peer_up(const struct bgp_proto *bgp) +{ + struct bgp_channel *c; + WALK_LIST(c, bgp->p.channels) + { + bmp_route_monitor_pre_policy_table_in_snapshot((struct channel *) c); + } +} + +static const struct birdsock * +bmp_get_birdsock(const struct bgp_proto *bgp) +{ + if (bgp->conn && bgp->conn->sk) + { + return bgp->conn->sk; + } + + return NULL; +} + +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) + { + sk = bgp->incoming_conn.sk; + } + else if (bgp->outgoing_conn.sk) + { + sk = bgp->outgoing_conn.sk; + } + + return sk; +} + +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; +} + +static const struct bgp_caps * +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) + { + remote_caps = bgp->incoming_conn.remote_caps; + } + else if (bgp->outgoing_conn.remote_caps) + { + remote_caps = bgp->outgoing_conn.remote_caps; + } + + return remote_caps; +} + +static bool +bmp_is_peer_global_instance(const struct bgp_proto *bgp) +{ + return (bgp->cf->peer_type != BGP_PT_EXTERNAL && + bgp->cf->peer_type != BGP_PT_INTERNAL) + ? (bgp->local_as != bgp->remote_as) + : (bgp->cf->peer_type == BGP_PT_EXTERNAL); +} + +enum bmp_result +bmp_send_peer_up_notif_msg(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 struct birdsock *sk = bmp_get_birdsock_ext(bgp); + if (IS_NULL(sk)) + { + return BMP_E_BIRDSOCK_NULL_REF; + } + + const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps_ext(bgp); + if (IS_NULL(remote_caps)) + { + return BMP_E_REMOTE_CAPS_NULL_REF; + } + + enum bmp_result rc = BMP_E_NONE; + const bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); + buffer payload = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); + bmp_peer_up_notif_msg_serialize(&payload, is_global_instance_peer, + bgp->remote_as, bgp->remote_id, remote_caps->as4_support, + sk->saddr, sk->daddr, sk->sport, sk->dport, tx_data, tx_data_size, + rx_data, rx_data_size); + IF_BMP_FAILED_GOTO_LABEL( + bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)), + err + ); + + bmp_peer_up(bgp); + +err: + bmp_buffer_free(&payload); + return rc; +} + +void +bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, + const size_t pkt_size) +{ + if (IS_NULL(g_bmp)) + { + return; + } + + struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, + bgp->remote_as); + const struct bmp_peer_map_entry *map_entry + = bmp_peer_map_get(&g_bmp->peer_open_msg.rx_msg, key); + if (!map_entry || !g_bmp->started) + { + IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + bmp_peer_map_insert(&g_bmp->peer_open_msg.tx_msg, key, pkt, pkt_size), + "Failed to put data into map" + ); + + if (!map_entry) + { + IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + bmp_peer_map_insert(&g_bmp->bgp_peers, key, (const byte *) &bgp, + sizeof (bgp)), + "Failed to put data into map" + ); + } + + return; + } + + IF_BMP_FAILED_PRINT_ERR_MSG( + bmp_send_peer_up_notif_msg(bgp, pkt, pkt_size, map_entry->data.buf, + map_entry->data.buf_size), + "Failed to send PEER UP notification" + ); +} + +void +bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, + const size_t pkt_size) +{ + if (IS_NULL(g_bmp)) + { + return; + } + + struct bmp_peer_map_key key + = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); + const struct bmp_peer_map_entry *map_data + = bmp_peer_map_get(&g_bmp->peer_open_msg.tx_msg, key); + if (!map_data || !g_bmp->started) + { + IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + bmp_peer_map_insert(&g_bmp->peer_open_msg.rx_msg, key, pkt, pkt_size), + "Failed to insert item into peer map" + ); + + if (!map_data) + { + IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + bmp_peer_map_insert(&g_bmp->bgp_peers, key, (const byte *) &bgp, + sizeof (bgp)), + "Failed to insert item into peer map" + ); + } + + return; + } + + IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + bmp_send_peer_up_notif_msg(bgp, map_data->data.buf, map_data->data.buf_size, + pkt, pkt_size), + "Failed to send peer up notification" + ); +} + +void +bmp_route_monitor_update_in_pre_begin() +{ + if (IS_NULL(g_bmp)) + { + return; + } + + if (g_bmp->monitoring_rib.in_pre_policy == false) + { + return; + } + + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + !g_bmp->started, + "BMP instance not started yet" + ); + + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + !EMPTY_LIST(g_bmp->rt_table_in_pre_policy.update_msg_queue), + "Previous BMP route monitoring update not finished yet" + ); + + gettimeofday(&g_bmp->rt_table_in_pre_policy.update_begin_time,NULL); + init_list(&g_bmp->rt_table_in_pre_policy.update_msg_queue); + g_bmp->rt_table_in_pre_policy.update_msg_size = 0; + g_bmp->rt_table_in_pre_policy.update_in_progress = true; +} + +void +bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size) +{ + if (IS_NULL(g_bmp)) + { + return; + } + + if (g_bmp->monitoring_rib.in_pre_policy == false) + { + return; + } + + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + !g_bmp->started, + "BMP instance not started yet" + ); + + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + !g_bmp->rt_table_in_pre_policy.update_in_progress, + "BMP route monitoring update not started yet" + ); + + struct bmp_data_node *upd_msg = mb_alloc(g_bmp->update_msg_mem_pool, + sizeof (struct bmp_data_node)); + upd_msg->data = mb_alloc(g_bmp->update_msg_mem_pool, data_size); + memcpy(upd_msg->data, data, data_size); + upd_msg->data_size = data_size; + g_bmp->rt_table_in_pre_policy.update_msg_size += data_size; + add_tail(&g_bmp->rt_table_in_pre_policy.update_msg_queue, &upd_msg->n); +} + +void +bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) +{ + if (IS_NULL(g_bmp)) + { + return; + } + + if (g_bmp->monitoring_rib.in_pre_policy == false) + { + return; + } + + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + (!g_bmp->started || EMPTY_LIST(g_bmp->rt_table_in_pre_policy.update_msg_queue)), + "BMP route monitoring update not started yet" + ); + + 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(g_bmp->buffer_mpool, + g_bmp->rt_table_in_pre_policy.update_msg_size + DEFAULT_MEM_BLOCK_SIZE); + + buffer update_msgs + = bmp_buffer_alloc(g_bmp->buffer_mpool, + g_bmp->rt_table_in_pre_policy.update_msg_size); + + struct bmp_data_node *data; + WALK_LIST(data, g_bmp->rt_table_in_pre_policy.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), + g_bmp->rt_table_in_pre_policy.update_begin_time.tv_sec, + g_bmp->rt_table_in_pre_policy.update_begin_time.tv_usec); + + IF_BMP_FAILED_PRINT_ERR_MSG_AND_GOTO_LABEL( + bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)), + "Failed to schedule packet for sent", + err + ); + + bmp_buffer_flush(&payload); + bmp_buffer_flush(&update_msgs); + } + +err: + bmp_buffer_free(&update_msgs); + bmp_buffer_free(&payload); +} + +void +bmp_route_monitor_update_in_pre_end() +{ + if (IS_NULL(g_bmp)) + { + return; + } + + if (g_bmp->monitoring_rib.in_pre_policy == false) + { + return; + } + + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + (!g_bmp->started || EMPTY_LIST(g_bmp->rt_table_in_pre_policy.update_msg_queue)), + "BMP route monitoring update not started yet" + ); + + struct bmp_data_node *upd_msg; + struct bmp_data_node *upd_msg_next; + WALK_LIST_DELSAFE(upd_msg, upd_msg_next, g_bmp->rt_table_in_pre_policy.update_msg_queue) + { + mb_free(upd_msg->data); + rem_node((node *) upd_msg); + mb_free(upd_msg); + } +} + +void +bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C) +{ + if (g_bmp->monitoring_rib.in_pre_policy == false) + { + return; + } + + struct rtable *tab = C->in_table; + if (IS_NULL(tab)) + { + return; + } + + 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(P, C, n, e, NULL, 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(); + } +} + +static enum bmp_result +bmp_send_peer_down_notif_msg(const struct bgp_proto *bgp, + const byte* data, const size_t data_size) +{ + const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps_ext(bgp); + bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); + enum bmp_result rc = BMP_E_NONE; + buffer payload + = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); + bmp_peer_down_notif_msg_serialize(&payload, is_global_instance_peer, + bgp->remote_as, bgp->remote_id, + remote_caps ? remote_caps->as4_support : bgp->as4_session, + bgp->remote_ip, data, data_size); + IF_BMP_FAILED_PRINT_ERR_MSG( + bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)), + "Failed to schedule packet for transmit" + ); + + bmp_buffer_free(&payload); + return rc; +} + +void +bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, + size_t pkt_size) +{ + if (IS_NULL(g_bmp) || (!g_bmp->started)) + { + return; + } + + struct bmp_peer_map_key key + = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); + if (!bmp_peer_map_get(&g_bmp->bgp_peers, key)) + { + return; + } + + bmp_peer_map_remove(&g_bmp->peer_open_msg.tx_msg, key); + bmp_peer_map_remove(&g_bmp->peer_open_msg.rx_msg, key); + bmp_peer_map_remove(&g_bmp->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; + buffer payload + = bmp_buffer_alloc(g_bmp->buffer_mpool, pkt_size + missing_bgp_hdr_size + 1); + if (pkt != NULL && pkt_size > 0) + { + 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); + } + } + else + { + // 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 + } + } + + IF_BMP_FAILED_PRINT_ERR_MSG( + bmp_send_peer_down_notif_msg(bgp, bmp_buffer_data(&payload), + bmp_buffer_pos(&payload)), + "Failed to send PEER DOWN notification" + ); + + bmp_buffer_free(&payload); +} + +static enum bmp_result +bmp_send_termination_msg(struct bmp_proto *bmp, + const enum bmp_term_reason reason) +{ + enum bmp_result rc = BMP_E_NONE; + const size_t term_msg_hdr_size = BMP_TERM_INFO_TYPE_SIZE + + BMP_TERM_INFO_LEN_FIELD_SIZE + + BMP_TERM_REASON_CODE_SIZE; + const size_t term_msg_size = BMP_COMMON_HDR_SIZE + term_msg_hdr_size; + buffer stream + = bmp_buffer_alloc(g_bmp->buffer_mpool, term_msg_size); + bmp_common_hdr_serialize(&stream, BMP_TERM_MSG, term_msg_hdr_size); + bmp_put_u16(&stream, BMP_TERM_INFO_REASON); + bmp_put_u16(&stream, BMP_TERM_REASON_CODE_SIZE); // 2-byte code indication the reason + bmp_put_u16(&stream, reason); + memcpy(bmp->conn->sk->tbuf, bmp_buffer_data(&stream), bmp_buffer_pos(&stream)); + if (sk_send(bmp->conn->sk, bmp_buffer_pos(&stream)) < 0) + { + rc = BMP_E_SEND_DATA; + } + + bmp_buffer_free(&stream); + return rc; +} + +static void +bmp_station_connected(struct birdsock *sk) +{ + struct bmp_conn *conn = (struct bmp_conn *)sk->data; + conn->sk->tx_hook = bmp_tx; + conn->bmp->station_connected = true; + IF_BMP_FAILED_PRINT_ERR_MSG( + bmp_startup(), + "Failed to start BMP protocol" + ); + + bmp_peer_map_walk(&conn->bmp->peer_open_msg.tx_msg, + bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif); + bmp_peer_map_flush(&conn->bmp->peer_open_msg.tx_msg); + bmp_peer_map_flush(&conn->bmp->peer_open_msg.rx_msg); +} + +static inline void +bmp_setup_socket(struct bmp_conn *conn) +{ + sock *sk = sk_new(proto_pool); + sk->type = SK_TCP_ACTIVE; + sk->ttl = IP4_MAX_TTL; + sk->tos = IP_PREC_INTERNET_CONTROL; + sk->tbsize = BGP_TX_BUFFER_EXT_SIZE; + sk->tx_hook = bmp_station_connected; + + conn->sk = sk; + sk->data = conn; +} + +/** Configuration handle section **/ +static struct proto * +bmp_init(struct proto_config *CF) +{ + struct proto *P = proto_new(CF); + struct bmp_proto *bmp = (struct bmp_proto *) P; + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + (g_bmp != NULL), + "Single BMP protocol instance has been already run", + PS_DOWN + ); + + struct bmp_config *cf = (struct bmp_config *) CF; + bmp->cf = cf; + bmp->station_ip = cf->station_ip; + bmp->station_port = cf->station_port; + strcpy(bmp->sys_descr, cf->sys_descr); + strcpy(bmp->sys_name, cf->sys_name); + bmp->disabled = cf->disabled; + bmp->monitoring_rib.in_pre_policy = cf->monitoring_rib_in_pre_policy; + bmp->monitoring_rib.in_post_policy = cf->monitoring_rib_in_post_policy; + bmp->monitoring_rib.local = cf->monitoring_rib_local; + + g_bmp = bmp; + return P; +} + +static int +bmp_start(struct proto *P) +{ + struct bmp_proto *bmp = (struct bmp_proto *) P; + if (bmp->disabled) + { + g_bmp = NULL; + return PS_DOWN; + } + + if (bmp->disabled) + { + return PS_DOWN; + } + + bmp->conn = mb_allocz(P->pool, sizeof (struct bmp_conn)); + bmp->conn->bmp = bmp; + bmp_setup_socket(bmp->conn); + IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + bmp_open(P), + "Failed to connect to BMP collector", + PS_DOWN + ); + + return PS_UP; +} + +static int +bmp_shutdown(struct proto *P) +{ + struct bmp_proto *bmp = (struct bmp_proto *) P; + IF_BMP_FAILED_PRINT_ERR_MSG( + bmp_send_termination_msg(bmp, BMP_TERM_REASON_ADM), + "Failed to send BMP termination message" + ); + + g_bmp->station_connected = false; + g_bmp->started = false; + g_bmp = NULL; + + return PS_DOWN; +} + +static int +bmp_reconfigure(struct proto *P UNUSED, struct proto_config *CF UNUSED) +{ + log(L_WARN "Reconfiguring BMP is not supported"); + return PS_UP; +} + +struct protocol proto_bmp = { + .name = "BMP", + .class = PROTOCOL_BMP, + .proto_size = sizeof(struct bmp_proto), + .config_size = sizeof(struct bmp_config), + .init = bmp_init, + .start = bmp_start, + .shutdown = bmp_shutdown, + .reconfigure = bmp_reconfigure, +}; + +void +bmp_build(void) +{ + proto_build(&proto_bmp); +} diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h new file mode 100644 index 00000000..03c5f529 --- /dev/null +++ b/proto/bmp/bmp.h @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#ifndef _BIRD_BMP_H_ +#define _BIRD_BMP_H_ + +#include "nest/bird.h" +#include "nest/protocol.h" +#include "lib/lists.h" +#include "nest/route.h" +#include "lib/event.h" +#include "lib/hash.h" +#include "lib/socket.h" +#include "proto/bmp/map.h" + +#include + +// Max length of MIB-II description object +#define MIB_II_STR_LEN 255 + +enum bmp_peer_down { + // Value of packet size of 'pkt_size' argument of bmp_peer_down() function + // used for pointing out that there was not any packet to pass + BMP_PEER_DOWN_NULL_PKT_SIZE = 0 +}; + +// The following fields of this structure controls whether there will be put +// specific routes into Route Monitoring message and send to BMP collector +struct monitoring_rib { + bool in_pre_policy; // Monitoring pre-policy Adj-Rib-In + bool in_post_policy; // Monitoring post-policy Adj-Rib-In + bool local; // Monitoring Local Rib +}; + +struct bmp_config { + struct proto_config c; + char *sys_descr; // sysDescr MIB-II [RFC1213] object + char *sys_name; // sysName MIB-II [RFC1213] object + ip_addr station_ip; // Monitoring station address + u16 station_port; // Monitoring station TCP port + bool disabled; // Manually disabled + 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 +}; + +/* Forward declarations */ +struct bgp_proto; +struct bmp_proto; + +struct bmp_conn { + struct bmp_proto *bmp; + struct birdsock *sk; + event *tx_ev; +}; + +// 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 + struct bmp_conn *conn; // Connection we have established + 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 station_ip; // Monitoring station IP address + u16 station_port; // Monitoring station TCP port + bool disabled; // Manually disabled + struct monitoring_rib monitoring_rib; + // Below fields are for internal use + int station_socket; // Socket associated with the BMP collector + 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 + 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 + bool station_connected; // Flag that stores connection status with BMP station + bool started; // Flag that stores running status of BMP instance +}; + +/** + * 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); + +/** + * 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); + +/** + * 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. + */ +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_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); + +#endif /* _BIRD_BMP_H_ */ diff --git a/proto/bmp/buffer.c b/proto/bmp/buffer.c new file mode 100644 index 00000000..f471e08a --- /dev/null +++ b/proto/bmp/buffer.c @@ -0,0 +1,58 @@ +/* + * 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/buffer.h" + +buffer +bmp_buffer_alloc(pool *ppool, const size_t n) +{ + buffer buf; + buf.start = mb_alloc(ppool, n); + buf.pos = buf.start; + buf.end = buf.start + n; + + return buf; +} + +void +bmp_buffer_free(buffer *buf) +{ + mb_free(buf->start); + buf->start = buf->pos = buf->end = NULL; +} + +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); + buf->pos = buf->start + pos; + buf->end = buf->start + n; +} + +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/buffer.h b/proto/bmp/buffer.h new file mode 100644 index 00000000..07eb4e9c --- /dev/null +++ b/proto/bmp/buffer.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +#ifndef _BIRD_BMP_BUFFER_H_ +#define _BIRD_BMP_BUFFER_H_ + +#include "proto/bmp/bmp.h" +#include "proto/bmp/utils.h" + +#include + +#include "lib/resource.h" + +buffer +bmp_buffer_alloc(pool *ppool, const size_t n); + +void +bmp_buffer_free(buffer *buf); + +static inline void +bmp_buffer_flush(buffer *buf) +{ + buf->pos = buf->start; +} + +static inline size_t +bmp_buffer_size(const buffer *buf) +{ + return buf->end - buf->start; +} + +static inline size_t +bmp_buffer_avail(const buffer *buf) +{ + return buf->end - buf->pos; +} + +static inline size_t +bmp_buffer_pos(const buffer *buf) +{ + return buf->pos - buf->start; +} + +static inline byte * +bmp_buffer_data(const buffer *buf) +{ + return buf->start; +} + +void +bmp_buffer_need(buffer *buf, const size_t n); + +// Idea for following macros has been taken from |proto/mrt/mrt.c| +#define BMP_DEFINE_PUT_FUNC(S, T) \ + static inline void \ + bmp_put_##S(buffer *b, const T x) \ + { \ + bmp_buffer_need(b, sizeof(T)); \ + put_##S(b->pos, x); \ + b->pos += sizeof(T); \ + } + +BMP_DEFINE_PUT_FUNC(u8, u8) +BMP_DEFINE_PUT_FUNC(u16, u16) +BMP_DEFINE_PUT_FUNC(u32, u32) +BMP_DEFINE_PUT_FUNC(u64, u64) +BMP_DEFINE_PUT_FUNC(ip4, ip4_addr) +BMP_DEFINE_PUT_FUNC(ip6, ip6_addr) + +void +bmp_put_data(buffer *buf, const void *src, const size_t n); + +#endif /* _BIRD_BMP_BUFFER_H_ */ \ No newline at end of file diff --git a/proto/bmp/config.Y b/proto/bmp/config.Y new file mode 100644 index 00000000..df7822ea --- /dev/null +++ b/proto/bmp/config.Y @@ -0,0 +1,90 @@ +/* + * 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. + */ + +CF_HDR + +#include "proto/bmp/bmp.h" + +CF_DEFINES + +#define BMP_CFG ((struct bmp_config *) this_proto) + +CF_DECLS + +CF_KEYWORDS(BMP, DESCRIPTION, ENABLED, IN, IP, MONITORING, NAME, PORT, + PRE_POLICY, POST_POLICY, RIB, STATION, SYSTEM) + +CF_GRAMMAR + +proto: bmp_proto '}' ; + +bmp_proto_start: proto_start BMP { + this_proto = proto_config_new(&proto_bmp, $1); + BMP_CFG->disabled = false; + 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; + } + ; + +bmp_station_address: + /* empty */ + | bmp_station_address IP ipa { + if (!BMP_CFG->disabled) + if (ipa_zero($3)) + cf_error("Invalid BMP monitoring station IP address"); + BMP_CFG->station_ip = $3; + } + | bmp_station_address PORT expr { + if (($3 < 1) || ($3 > 65535)) + cf_error("Invalid BMP monitoring station port number"); + BMP_CFG->station_port = $3; + } + ; + +bmp_proto: + bmp_proto_start proto_name '{' + | bmp_proto proto_item ';' + | bmp_proto ENABLED bool ';' { + BMP_CFG->disabled = $3; + } + | bmp_proto STATION ADDRESS bmp_station_address ';' + | bmp_proto SYSTEM DESCRIPTION text ';' { + if (!$4 || (strlen($4) == 0)) + cf_error("String is empty"); + else if (strlen($4) > 255) + cf_error("Invalid string length"); + BMP_CFG->sys_descr = $4; + } + | bmp_proto SYSTEM NAME text ';' { + if (!$4 || (strlen($4) == 0)) + cf_error("String is empty"); + else if (strlen($4) > 255) + cf_error("Invalid string length"); + BMP_CFG->sys_name = $4; + } + | bmp_proto MONITORING RIB IN PRE_POLICY bool ';' { + BMP_CFG->monitoring_rib_in_pre_policy = $6; + } + | 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; + } + | bmp_proto DISABLED bool ';' { + BMP_CFG->disabled = $3; } + ; + +CF_CODE + +CF_END diff --git a/proto/bmp/map.c b/proto/bmp/map.c new file mode 100644 index 00000000..e9a37266 --- /dev/null +++ b/proto/bmp/map.c @@ -0,0 +1,155 @@ +/* + * 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" +#include "proto/bmp/utils.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 + +enum bmp_result +bmp_peer_map_init(struct bmp_peer_map *map, pool *mpool) +{ + if (IS_NULL(map) || IS_NULL(mpool)) + { + return BMP_E_NULL_REF; + } + + map->mpool = mpool; + HASH_INIT(map->peer_hash, map->mpool, PEER_INIT_ORDER); + + return BMP_E_NONE; +} + +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; +} + +enum bmp_result +bmp_peer_map_flush(struct bmp_peer_map *map) +{ + if (IS_NULL(map)) + { + return BMP_E_NULL_REF; + } + + 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); + return BMP_E_NONE; +} + +enum bmp_result +bmp_peer_map_free(struct bmp_peer_map *map) +{ + if (IS_NULL(map)) + { + return BMP_E_NULL_REF; + } + + IF_BMP_FAILED_RETURN_RC(bmp_peer_map_flush(map)); + HASH_FREE(map->peer_hash); + + return BMP_E_NONE; +} + +enum bmp_result +bmp_peer_map_insert(struct bmp_peer_map *map, const struct bmp_peer_map_key key, + const byte *data, const size_t data_size) +{ + if (IS_NULL(map)) + { + return BMP_E_NULL_REF; + } + + if (HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key))) + { + return BMP_E_EXISTS; + } + + struct bmp_peer_map_entry *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); + + return BMP_E_NONE; +} + +enum bmp_result +bmp_peer_map_remove(struct bmp_peer_map *map, const struct bmp_peer_map_key key) +{ + if (IS_NULL(map)) + { + return BMP_E_NULL_REF; + } + + struct bmp_peer_map_entry *entry + = (struct bmp_peer_map_entry *) HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key)); + if (IS_NULL(entry)) + { + return BMP_E_NOT_EXISTS; + } + + mb_free(entry->data.buf); + HASH_DELETE(map->peer_hash, PEER, PEER_KEY(&entry->key)); + mb_free(entry); + + return BMP_E_NONE; +} + +const struct bmp_peer_map_entry * +bmp_peer_map_get(struct bmp_peer_map *map, const struct bmp_peer_map_key key) +{ + if (IS_NULL(map)) + { + return NULL; + } + + 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) +{ + 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); + } + HASH_WALK_FILTER_END; +} diff --git a/proto/bmp/map.h b/proto/bmp/map.h new file mode 100644 index 00000000..e9d5798e --- /dev/null +++ b/proto/bmp/map.h @@ -0,0 +1,70 @@ +/* + * 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" + +#include "proto/bmp/utils.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 +}; + +enum bmp_result +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); + +enum bmp_result +bmp_peer_map_free(struct bmp_peer_map *map); + +enum bmp_result +bmp_peer_map_flush(struct bmp_peer_map *map); + +enum bmp_result +bmp_peer_map_insert(struct bmp_peer_map *map, const struct bmp_peer_map_key key, + const byte *data, const size_t data_size); + +enum bmp_result +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 +bmp_peer_map_walk(const struct bmp_peer_map *map, bmp_peer_map_walk_action action); + +#endif /* _BIRD_BMP_MAP_H_ */ diff --git a/proto/bmp/utils.h b/proto/bmp/utils.h new file mode 100644 index 00000000..faca2ba0 --- /dev/null +++ b/proto/bmp/utils.h @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#ifndef _BIRD_BMP_UTILS_H_ +#define _BIRD_BMP_UTILS_H_ + +/** + * TODO: + * - Provide descriptive explanation for the follwing enums + */ +enum bmp_result { + BMP_E_NONE = 0, + BMP_E_INVALID_ARG, + BMP_E_NULL_REF, + BMP_E_EXISTS, + BMP_E_NOT_EXISTS, + BMP_E_OPEN_SOCKET, + BMP_E_CONNECT_TO_SRV, + BMP_E_SEND_DATA, + BMP_E_BIRDSOCK_NULL_REF, + BMP_E_REMOTE_CAPS_NULL_REF, + BMP_E_NEW_TX_EVENT +}; + +#define BMP_FAILED(v) \ + (v != BMP_E_NONE) + +#define IF_BMP_FAILED_RETURN_RC(func) \ + do { \ + enum bmp_result rc = func; \ + if (BMP_FAILED(rc)) \ + { \ + return rc; \ + } \ + } while (0) + +// The following macro requires to define locally enum bmp_result rc; +#define IF_BMP_FAILED_GOTO_LABEL(func, label) \ + do { \ + rc = func; \ + if (BMP_FAILED(rc)) \ + { \ + goto label; \ + } \ + } while (0) + +#define IF_BMP_FAILED_PRINT_ERR_MSG(func, msg) \ + do { \ + enum bmp_result rc = func; \ + if (BMP_FAILED(rc)) \ + { \ + log(L_WARN "[BMP] " msg " (rc = %d)", rc); \ + } \ + } while (0) + +#define IF_BMP_FAILED_PRINT_ERR_MSG_AND_GOTO_LABEL(func, msg, label) \ + do { \ + enum bmp_result rc = func; \ + if (BMP_FAILED(rc)) \ + { \ + log(L_WARN "[BMP] " msg " (rc = %d)", rc); \ + goto label; \ + } \ + } while (0) + +#define IS_NULL(ptr) \ + ((ptr) == NULL) + +#define IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(expr, msg, rv...) \ + do { \ + if ((expr)) \ + { \ + log(L_WARN "[BMP] " msg); \ + return rv; \ + } \ + } while (0) + +#define IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(p, msg, rv...) \ + do { \ + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(IS_NULL(p), msg, rv); \ + } while (0) + +#define IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(func, msg, rv...) \ + do { \ + enum bmp_result rc = func; \ + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(BMP_FAILED(rc), msg, rv); \ + } while (0) + +#endif /* _BIRD_BMP_UTILS_H_ */ \ No newline at end of file From ad16e351773f4b606dd8b4dbbe77c2cb35bf5133 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sun, 28 Mar 2021 04:30:11 +0200 Subject: [PATCH 02/14] BMP: Remove superfluous error handling Most error handling code was was for cases that cannot happen, or they would be code bugs (and should use ASSERT()). Keep error handling for just for I/O errors, like in rest of BIRD. --- proto/bmp/bmp.c | 317 +++++++++++++++------------------------------ proto/bmp/bmp.h | 4 +- proto/bmp/buffer.h | 3 +- proto/bmp/map.c | 76 +++-------- proto/bmp/map.h | 12 +- proto/bmp/utils.h | 94 -------------- 6 files changed, 131 insertions(+), 375 deletions(-) delete mode 100644 proto/bmp/utils.h diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 5d4e1ac3..5153ef36 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -25,7 +25,6 @@ #include "proto/bmp/bmp.h" #include "proto/bmp/buffer.h" #include "proto/bmp/map.h" -#include "proto/bmp/utils.h" #include #include @@ -172,11 +171,28 @@ enum bmp_term_reason { #define IP4_MAX_TTL 255 + +#define IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(expr, msg, rv...) \ + do { \ + if ((expr)) \ + { \ + log(L_WARN "[BMP] " msg); \ + return rv; \ + } \ + } while (0) + + +#define IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(p, msg, rv...) \ + do { \ + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(!(p), msg, rv); \ + } while (0) + + // Handle BIRD socket error event static void bmp_sock_err(sock *sk, int err); -static enum bmp_result +static void bmp_send_peer_up_notif_msg(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); @@ -204,26 +220,20 @@ bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const bmp_put_u8(stream, type); } -static enum bmp_result +static void bmp_info_tlv_hdr_serialize(buffer *stream, const enum bmp_info_tlv_type type, - const char *ascii) + const char *str) { - const size_t ascii_len = strlen(ascii); - if (ascii_len > MIB_II_STR_LEN) - { - return BMP_E_INVALID_ARG; - } + size_t str_len = strlen(str); + str_len = MIN(str_len, 65535); bmp_put_u16(stream, type); - // It doesn't contain null terminating character '\0' - bmp_put_u16(stream, ascii_len); - bmp_put_data(stream, ascii, ascii_len); - - return BMP_E_NONE; + bmp_put_u16(stream, str_len); + bmp_put_data(stream, str, str_len); } // Serializes BMP Initiation message header [RFC 7854 - Section 4.3] -static enum bmp_result +static void bmp_init_msg_serialize(buffer *stream, const char *sys_descr, const char *sys_name) { const size_t sys_descr_len = strlen(sys_descr); @@ -233,70 +243,42 @@ bmp_init_msg_serialize(buffer *stream, const char *sys_descr, const char *sys_na const size_t data_size = (2 * BMP_INFO_TLV_FIX_SIZE) + sys_descr_len + sys_name_len; bmp_buffer_need(stream, BMP_COMMON_HDR_SIZE + data_size); bmp_common_hdr_serialize(stream, BMP_INIT_MSG, data_size); - IF_BMP_FAILED_RETURN_RC( - bmp_info_tlv_hdr_serialize(stream, BMP_INFO_TLV_TYPE_SYS_DESCR, sys_descr) - ); - - IF_BMP_FAILED_RETURN_RC( - bmp_info_tlv_hdr_serialize(stream, BMP_INFO_TLV_TYPE_SYS_NAME, sys_name) - ); - - return BMP_E_NONE; + bmp_info_tlv_hdr_serialize(stream, BMP_INFO_TLV_TYPE_SYS_DESCR, sys_descr); + bmp_info_tlv_hdr_serialize(stream, BMP_INFO_TLV_TYPE_SYS_NAME, sys_name); } -static enum bmp_result +static void bmp_schedule_tx_packet(const byte *payload, const size_t size) { - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !g_bmp->station_connected, - "Not BMP station connected yet", - BMP_E_CONNECT_TO_SRV - ); + ASSERT(g_bmp->station_connected); struct bmp_data_node *tx_data = mb_alloc(g_bmp->tx_mem_pool, sizeof (struct bmp_data_node)); tx_data->data = mb_alloc(g_bmp->tx_mem_pool, size); memcpy(tx_data->data, payload, size); tx_data->data_size = size; add_tail(&g_bmp->tx_queue, &tx_data->n); + if (sk_tx_buffer_empty(g_bmp->conn->sk) - && !ev_active(g_bmp->conn->tx_ev)) + && !ev_active(g_bmp->conn->tx_ev)) { ev_schedule(g_bmp->conn->tx_ev); } - - return BMP_E_NONE; } /** * bmp_startup - connect to the BMP collector. * NOTE: Send Initiation Message to the BMP collector. */ -static enum bmp_result +static void bmp_startup(void) { - if (g_bmp->started || !g_bmp->station_connected) - { - return BMP_E_NONE; - } + ASSERT(g_bmp->station_connected && !g_bmp->started); - enum bmp_result rc = BMP_E_NONE; - buffer payload - = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); - IF_BMP_FAILED_GOTO_LABEL( - bmp_init_msg_serialize(&payload, g_bmp->sys_descr, g_bmp->sys_name), - err - ); - - IF_BMP_FAILED_GOTO_LABEL( - bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)), - err - ); + buffer payload = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); + bmp_init_msg_serialize(&payload, g_bmp->sys_descr, g_bmp->sys_name); + bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); g_bmp->started = true; - -err: - bmp_buffer_free(&payload); - return rc; } void @@ -331,8 +313,8 @@ bmp_fire_tx(void *vconn) rem_node((node *) tx_data); mb_free(tx_data); IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - (sk_send(conn->sk, data_size) == 0), - "Failed to send BMP packet", + (sk_send(conn->sk, data_size) <= 0), + "Failed to send BMP packet" ); // BMP packets should be treat with lowest priority when scheduling sending @@ -353,37 +335,35 @@ bmp_fire_tx(void *vconn) static void bmp_tx(struct birdsock *sk) { - IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - bmp_startup(), - "Failed to send Initation message to BMP collector" - ); - bmp_fire_tx(sk->data); } -static inline enum bmp_result +static inline int bmp_open_socket(struct bmp_proto *bmp) { - bmp->conn->sk->daddr = bmp->station_ip; - bmp->conn->sk->dport = bmp->station_port; - bmp->conn->sk->err_hook = bmp_sock_err; + sock *s = bmp->conn->sk; + s->daddr = bmp->station_ip; + s->dport = bmp->station_port; + s->err_hook = bmp_sock_err; - if (sk_open(bmp->conn->sk) < 0) - { - return BMP_E_OPEN_SOCKET; - } + int rc = sk_open(s); - return BMP_E_NONE; + if (rc < 0) + sk_log_error(s, bmp->p.name); + + return rc; } static void bmp_connection_retry(timer *t) { struct bmp_proto *bmp = (struct bmp_proto *) t->data; - IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - bmp_open_socket(bmp), - "Failed to connect to BMP station" - ); + + if (bmp_open_socket(bmp) < 0) + { + log(L_DEBUG "Failed to connect to BMP station"); + return; + } log(L_DEBUG "Connected to BMP station after connection retry"); tm_stop(t); @@ -534,49 +514,30 @@ bmp_peer_down_notif_msg_serialize(buffer *stream, const bool is_peer_global, * bmp_open - initialize internal resources of BMP implementation. * NOTE: It does not connect to BMP collector yet. */ -enum bmp_result +void bmp_open(const struct proto *P) { struct bmp_proto *bmp = (struct bmp_proto *) P; g_bmp = bmp; - enum bmp_result rc = BMP_E_NONE; log(L_DEBUG "Init BMP"); - if (!P) - { - return BMP_E_NULL_REF; - } g_bmp->buffer_mpool = rp_new(P->pool, "BMP Buffer"); g_bmp->map_mem_pool = rp_new(P->pool, "BMP Map"); g_bmp->tx_mem_pool = rp_new(P->pool, "BMP Tx"); g_bmp->update_msg_mem_pool = rp_new(P->pool, "BMP Update"); bmp->conn->tx_ev = ev_new_init(g_bmp->tx_mem_pool, bmp_fire_tx, bmp->conn); - if (!bmp->conn->tx_ev) - { - return BMP_E_NEW_TX_EVENT; - } - IF_BMP_FAILED_RETURN_RC( - bmp_peer_map_init(&g_bmp->peer_open_msg.tx_msg, g_bmp->map_mem_pool) - ); - - IF_BMP_FAILED_GOTO_LABEL( - bmp_peer_map_init(&g_bmp->peer_open_msg.rx_msg, g_bmp->map_mem_pool), - err_free_ip_map_tx_msg - ); - - IF_BMP_FAILED_GOTO_LABEL( - bmp_peer_map_init(&g_bmp->bgp_peers, g_bmp->map_mem_pool), - err_free_ip_map_rx_msg - ); + bmp_peer_map_init(&g_bmp->peer_open_msg.tx_msg, g_bmp->map_mem_pool); + bmp_peer_map_init(&g_bmp->peer_open_msg.rx_msg, g_bmp->map_mem_pool); + bmp_peer_map_init(&g_bmp->bgp_peers, g_bmp->map_mem_pool); init_list(&g_bmp->tx_queue); init_list(&g_bmp->rt_table_in_pre_policy.update_msg_queue); g_bmp->station_connected = false; g_bmp->started = false; g_bmp->connect_retry_timer = NULL; - if (BMP_FAILED(bmp_open_socket(bmp))) + if (bmp_open_socket(bmp) < 0) { log(L_DEBUG "Failed to connect to BMP station"); g_bmp->connect_retry_timer = tm_new_init(P->pool, bmp_connection_retry, bmp, @@ -591,14 +552,6 @@ bmp_open(const struct proto *P) strncpy(g_bmp->sys_name, bmp->sys_name, sizeof (g_bmp->sys_name) - 1); strncpy(g_bmp->sys_descr, bmp->sys_descr, sizeof (g_bmp->sys_descr) - 1); - return BMP_E_NONE; - -err_free_ip_map_rx_msg: - bmp_peer_map_free(&g_bmp->peer_open_msg.rx_msg); - -err_free_ip_map_tx_msg: - bmp_peer_map_free(&g_bmp->peer_open_msg.tx_msg); - return rc; } void @@ -606,6 +559,7 @@ 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) { + ASSERT(g_bmp->station_connected); const struct bmp_peer_map_entry *map_rx_msg = bmp_peer_map_get(&g_bmp->peer_open_msg.rx_msg, key); IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( map_rx_msg, @@ -622,11 +576,8 @@ bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif( memcpy(&bgp, map_bgp_proto->data.buf, sizeof (bgp)); if (bgp->p.proto_state == PS_UP) { - IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - bmp_send_peer_up_notif_msg(bgp, tx_msg, tx_msg_size, map_rx_msg->data.buf, - map_rx_msg->data.buf_size), - "Failed to send BMP Peer Up Notification MSG" - ); + bmp_send_peer_up_notif_msg(bgp, tx_msg, tx_msg_size, + map_rx_msg->data.buf, map_rx_msg->data.buf_size); } } @@ -655,6 +606,7 @@ 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; @@ -713,47 +665,35 @@ bmp_is_peer_global_instance(const struct bgp_proto *bgp) : (bgp->cf->peer_type == BGP_PT_EXTERNAL); } -enum bmp_result +static void bmp_send_peer_up_notif_msg(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) { + ASSERT(g_bmp->station_connected); + const struct birdsock *sk = bmp_get_birdsock_ext(bgp); - if (IS_NULL(sk)) - { - return BMP_E_BIRDSOCK_NULL_REF; - } + IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + sk, + "[BMP] No BGP socket" + ); - const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps_ext(bgp); - if (IS_NULL(remote_caps)) - { - return BMP_E_REMOTE_CAPS_NULL_REF; - } - - enum bmp_result rc = BMP_E_NONE; const bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); buffer payload = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); bmp_peer_up_notif_msg_serialize(&payload, is_global_instance_peer, - bgp->remote_as, bgp->remote_id, remote_caps->as4_support, + bgp->remote_as, bgp->remote_id, 1, sk->saddr, sk->daddr, sk->sport, sk->dport, tx_data, tx_data_size, rx_data, rx_data_size); - IF_BMP_FAILED_GOTO_LABEL( - bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)), - err - ); + bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_peer_up(bgp); - -err: - bmp_buffer_free(&payload); - return rc; } void bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, const size_t pkt_size) { - if (IS_NULL(g_bmp)) + if (!g_bmp) { return; } @@ -764,35 +704,25 @@ bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, = bmp_peer_map_get(&g_bmp->peer_open_msg.rx_msg, key); if (!map_entry || !g_bmp->started) { - IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - bmp_peer_map_insert(&g_bmp->peer_open_msg.tx_msg, key, pkt, pkt_size), - "Failed to put data into map" - ); + bmp_peer_map_insert(&g_bmp->peer_open_msg.tx_msg, key, pkt, pkt_size); if (!map_entry) { - IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - bmp_peer_map_insert(&g_bmp->bgp_peers, key, (const byte *) &bgp, - sizeof (bgp)), - "Failed to put data into map" - ); + bmp_peer_map_insert(&g_bmp->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); } return; } - IF_BMP_FAILED_PRINT_ERR_MSG( - bmp_send_peer_up_notif_msg(bgp, pkt, pkt_size, map_entry->data.buf, - map_entry->data.buf_size), - "Failed to send PEER UP notification" - ); + bmp_send_peer_up_notif_msg(bgp, pkt, pkt_size, map_entry->data.buf, + map_entry->data.buf_size); } void bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, const size_t pkt_size) { - if (IS_NULL(g_bmp)) + if (!g_bmp) { return; } @@ -803,34 +733,24 @@ bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, = bmp_peer_map_get(&g_bmp->peer_open_msg.tx_msg, key); if (!map_data || !g_bmp->started) { - IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - bmp_peer_map_insert(&g_bmp->peer_open_msg.rx_msg, key, pkt, pkt_size), - "Failed to insert item into peer map" - ); + bmp_peer_map_insert(&g_bmp->peer_open_msg.rx_msg, key, pkt, pkt_size); if (!map_data) { - IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - bmp_peer_map_insert(&g_bmp->bgp_peers, key, (const byte *) &bgp, - sizeof (bgp)), - "Failed to insert item into peer map" - ); + bmp_peer_map_insert(&g_bmp->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); } return; } - IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - bmp_send_peer_up_notif_msg(bgp, map_data->data.buf, map_data->data.buf_size, - pkt, pkt_size), - "Failed to send peer up notification" - ); + bmp_send_peer_up_notif_msg(bgp, map_data->data.buf, map_data->data.buf_size, + pkt, pkt_size); } void bmp_route_monitor_update_in_pre_begin() { - if (IS_NULL(g_bmp)) + if (!g_bmp) { return; } @@ -859,7 +779,7 @@ bmp_route_monitor_update_in_pre_begin() void bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size) { - if (IS_NULL(g_bmp)) + if (!g_bmp) { return; } @@ -891,7 +811,7 @@ 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) { - if (IS_NULL(g_bmp)) + if (!g_bmp) { return; } @@ -938,25 +858,17 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) g_bmp->rt_table_in_pre_policy.update_begin_time.tv_sec, g_bmp->rt_table_in_pre_policy.update_begin_time.tv_usec); - IF_BMP_FAILED_PRINT_ERR_MSG_AND_GOTO_LABEL( - bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)), - "Failed to schedule packet for sent", - err - ); + bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_flush(&payload); bmp_buffer_flush(&update_msgs); } - -err: - bmp_buffer_free(&update_msgs); - bmp_buffer_free(&payload); } void bmp_route_monitor_update_in_pre_end() { - if (IS_NULL(g_bmp)) + if (!g_bmp) { return; } @@ -990,7 +902,7 @@ bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C) } struct rtable *tab = C->in_table; - if (IS_NULL(tab)) + if (!tab) { return; } @@ -1039,33 +951,30 @@ bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C) } } -static enum bmp_result +static void bmp_send_peer_down_notif_msg(const struct bgp_proto *bgp, const byte* data, const size_t data_size) { + ASSERT(g_bmp->station_connected); + const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps_ext(bgp); bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); - enum bmp_result rc = BMP_E_NONE; buffer payload = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); bmp_peer_down_notif_msg_serialize(&payload, is_global_instance_peer, bgp->remote_as, bgp->remote_id, remote_caps ? remote_caps->as4_support : bgp->as4_session, bgp->remote_ip, data, data_size); - IF_BMP_FAILED_PRINT_ERR_MSG( - bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)), - "Failed to schedule packet for transmit" - ); + bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_free(&payload); - return rc; } void bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, size_t pkt_size) { - if (IS_NULL(g_bmp) || (!g_bmp->started)) + if (!g_bmp || !g_bmp->started) { return; } @@ -1119,20 +1028,15 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, } } - IF_BMP_FAILED_PRINT_ERR_MSG( - bmp_send_peer_down_notif_msg(bgp, bmp_buffer_data(&payload), - bmp_buffer_pos(&payload)), - "Failed to send PEER DOWN notification" - ); + bmp_send_peer_down_notif_msg(bgp, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_free(&payload); } -static enum bmp_result +static void bmp_send_termination_msg(struct bmp_proto *bmp, const enum bmp_term_reason reason) { - enum bmp_result rc = BMP_E_NONE; const size_t term_msg_hdr_size = BMP_TERM_INFO_TYPE_SIZE + BMP_TERM_INFO_LEN_FIELD_SIZE + BMP_TERM_REASON_CODE_SIZE; @@ -1144,13 +1048,12 @@ bmp_send_termination_msg(struct bmp_proto *bmp, bmp_put_u16(&stream, BMP_TERM_REASON_CODE_SIZE); // 2-byte code indication the reason bmp_put_u16(&stream, reason); memcpy(bmp->conn->sk->tbuf, bmp_buffer_data(&stream), bmp_buffer_pos(&stream)); - if (sk_send(bmp->conn->sk, bmp_buffer_pos(&stream)) < 0) - { - rc = BMP_E_SEND_DATA; - } + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( + sk_send(bmp->conn->sk, bmp_buffer_pos(&stream)) < 0, + "Failed to send BMP termination message" + ); bmp_buffer_free(&stream); - return rc; } static void @@ -1159,10 +1062,8 @@ bmp_station_connected(struct birdsock *sk) struct bmp_conn *conn = (struct bmp_conn *)sk->data; conn->sk->tx_hook = bmp_tx; conn->bmp->station_connected = true; - IF_BMP_FAILED_PRINT_ERR_MSG( - bmp_startup(), - "Failed to start BMP protocol" - ); + + bmp_startup(); bmp_peer_map_walk(&conn->bmp->peer_open_msg.tx_msg, bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif); @@ -1190,11 +1091,6 @@ bmp_init(struct proto_config *CF) { struct proto *P = proto_new(CF); struct bmp_proto *bmp = (struct bmp_proto *) P; - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - (g_bmp != NULL), - "Single BMP protocol instance has been already run", - PS_DOWN - ); struct bmp_config *cf = (struct bmp_config *) CF; bmp->cf = cf; @@ -1229,11 +1125,7 @@ bmp_start(struct proto *P) bmp->conn = mb_allocz(P->pool, sizeof (struct bmp_conn)); bmp->conn->bmp = bmp; bmp_setup_socket(bmp->conn); - IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - bmp_open(P), - "Failed to connect to BMP collector", - PS_DOWN - ); + bmp_open(P); return PS_UP; } @@ -1242,10 +1134,7 @@ static int bmp_shutdown(struct proto *P) { struct bmp_proto *bmp = (struct bmp_proto *) P; - IF_BMP_FAILED_PRINT_ERR_MSG( - bmp_send_termination_msg(bmp, BMP_TERM_REASON_ADM), - "Failed to send BMP termination message" - ); + bmp_send_termination_msg(bmp, BMP_TERM_REASON_ADM); g_bmp->station_connected = false; g_bmp->started = false; diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 03c5f529..eb800f8e 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -39,8 +39,8 @@ struct monitoring_rib { struct bmp_config { struct proto_config c; - char *sys_descr; // sysDescr MIB-II [RFC1213] object - char *sys_name; // sysName MIB-II [RFC1213] object + const char *sys_descr; // sysDescr MIB-II [RFC1213] object + const char *sys_name; // sysName MIB-II [RFC1213] object ip_addr station_ip; // Monitoring station address u16 station_port; // Monitoring station TCP port bool disabled; // Manually disabled diff --git a/proto/bmp/buffer.h b/proto/bmp/buffer.h index 07eb4e9c..f752cf5d 100644 --- a/proto/bmp/buffer.h +++ b/proto/bmp/buffer.h @@ -10,7 +10,6 @@ #define _BIRD_BMP_BUFFER_H_ #include "proto/bmp/bmp.h" -#include "proto/bmp/utils.h" #include @@ -75,4 +74,4 @@ BMP_DEFINE_PUT_FUNC(ip6, ip6_addr) void bmp_put_data(buffer *buf, const void *src, const size_t n); -#endif /* _BIRD_BMP_BUFFER_H_ */ \ No newline at end of file +#endif /* _BIRD_BMP_BUFFER_H_ */ diff --git a/proto/bmp/map.c b/proto/bmp/map.c index e9a37266..f8219dcc 100644 --- a/proto/bmp/map.c +++ b/proto/bmp/map.c @@ -7,7 +7,6 @@ */ #include "proto/bmp/map.h" -#include "proto/bmp/utils.h" /* Peer Index Table */ #define PEER_KEY(n) (n)->peer_as, (n)->peer_ip @@ -23,18 +22,11 @@ HASH_DEFINE_REHASH_FN(PEER, struct bmp_peer_map_key) #define PEER_INIT_ORDER 6 -enum bmp_result +void bmp_peer_map_init(struct bmp_peer_map *map, pool *mpool) { - if (IS_NULL(map) || IS_NULL(mpool)) - { - return BMP_E_NULL_REF; - } - map->mpool = mpool; HASH_INIT(map->peer_hash, map->mpool, PEER_INIT_ORDER); - - return BMP_E_NONE; } struct bmp_peer_map_key @@ -48,14 +40,9 @@ bmp_peer_map_key_create(const ip_addr peer_ip, const u32 peer_as) return key; } -enum bmp_result +void bmp_peer_map_flush(struct bmp_peer_map *map) { - if (IS_NULL(map)) - { - return BMP_E_NULL_REF; - } - struct bmp_peer_map_entry *entry; HASH_WALK_DELSAFE(map->peer_hash, next, e) { @@ -67,78 +54,55 @@ bmp_peer_map_flush(struct bmp_peer_map *map) HASH_WALK_DELSAFE_END; HASH_MAY_RESIZE_DOWN(map->peer_hash, PEER, map->mpool); - return BMP_E_NONE; } -enum bmp_result +void bmp_peer_map_free(struct bmp_peer_map *map) { - if (IS_NULL(map)) - { - return BMP_E_NULL_REF; - } - - IF_BMP_FAILED_RETURN_RC(bmp_peer_map_flush(map)); + bmp_peer_map_flush(map); HASH_FREE(map->peer_hash); - - return BMP_E_NONE; } -enum bmp_result +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) { - if (IS_NULL(map)) + struct bmp_peer_map_entry *entry + = (void *) HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key)); + + if (entry) { - return BMP_E_NULL_REF; + 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; } - if (HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key))) - { - return BMP_E_EXISTS; - } - - struct bmp_peer_map_entry *entry = mb_alloc(map->mpool, - sizeof (struct bmp_peer_map_entry)); + 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); - - return BMP_E_NONE; } -enum bmp_result +void bmp_peer_map_remove(struct bmp_peer_map *map, const struct bmp_peer_map_key key) { - if (IS_NULL(map)) - { - return BMP_E_NULL_REF; - } - struct bmp_peer_map_entry *entry - = (struct bmp_peer_map_entry *) HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key)); - if (IS_NULL(entry)) - { - return BMP_E_NOT_EXISTS; - } + = (void *) HASH_DELETE(map->peer_hash, PEER, PEER_KEY(&key)); + + if (!entry) + return; mb_free(entry->data.buf); - HASH_DELETE(map->peer_hash, PEER, PEER_KEY(&entry->key)); mb_free(entry); - - return BMP_E_NONE; } const struct bmp_peer_map_entry * bmp_peer_map_get(struct bmp_peer_map *map, const struct bmp_peer_map_key key) { - if (IS_NULL(map)) - { - return NULL; - } - return (struct bmp_peer_map_entry *) HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key)); } diff --git a/proto/bmp/map.h b/proto/bmp/map.h index e9d5798e..0ad5295f 100644 --- a/proto/bmp/map.h +++ b/proto/bmp/map.h @@ -16,8 +16,6 @@ #include "lib/hash.h" #include "lib/resource.h" -#include "proto/bmp/utils.h" - struct bmp_peer_map_key { struct bmp_peer_map_key *next; ip_addr peer_ip; @@ -39,23 +37,23 @@ struct bmp_peer_map { HASH(struct bmp_peer_map_key) peer_hash; // Hash for peers to find the index }; -enum bmp_result +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); -enum bmp_result +void bmp_peer_map_free(struct bmp_peer_map *map); -enum bmp_result +void bmp_peer_map_flush(struct bmp_peer_map *map); -enum bmp_result +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); -enum bmp_result +void bmp_peer_map_remove(struct bmp_peer_map *map, const struct bmp_peer_map_key key); const struct bmp_peer_map_entry * diff --git a/proto/bmp/utils.h b/proto/bmp/utils.h deleted file mode 100644 index faca2ba0..00000000 --- a/proto/bmp/utils.h +++ /dev/null @@ -1,94 +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. - */ - -#ifndef _BIRD_BMP_UTILS_H_ -#define _BIRD_BMP_UTILS_H_ - -/** - * TODO: - * - Provide descriptive explanation for the follwing enums - */ -enum bmp_result { - BMP_E_NONE = 0, - BMP_E_INVALID_ARG, - BMP_E_NULL_REF, - BMP_E_EXISTS, - BMP_E_NOT_EXISTS, - BMP_E_OPEN_SOCKET, - BMP_E_CONNECT_TO_SRV, - BMP_E_SEND_DATA, - BMP_E_BIRDSOCK_NULL_REF, - BMP_E_REMOTE_CAPS_NULL_REF, - BMP_E_NEW_TX_EVENT -}; - -#define BMP_FAILED(v) \ - (v != BMP_E_NONE) - -#define IF_BMP_FAILED_RETURN_RC(func) \ - do { \ - enum bmp_result rc = func; \ - if (BMP_FAILED(rc)) \ - { \ - return rc; \ - } \ - } while (0) - -// The following macro requires to define locally enum bmp_result rc; -#define IF_BMP_FAILED_GOTO_LABEL(func, label) \ - do { \ - rc = func; \ - if (BMP_FAILED(rc)) \ - { \ - goto label; \ - } \ - } while (0) - -#define IF_BMP_FAILED_PRINT_ERR_MSG(func, msg) \ - do { \ - enum bmp_result rc = func; \ - if (BMP_FAILED(rc)) \ - { \ - log(L_WARN "[BMP] " msg " (rc = %d)", rc); \ - } \ - } while (0) - -#define IF_BMP_FAILED_PRINT_ERR_MSG_AND_GOTO_LABEL(func, msg, label) \ - do { \ - enum bmp_result rc = func; \ - if (BMP_FAILED(rc)) \ - { \ - log(L_WARN "[BMP] " msg " (rc = %d)", rc); \ - goto label; \ - } \ - } while (0) - -#define IS_NULL(ptr) \ - ((ptr) == NULL) - -#define IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(expr, msg, rv...) \ - do { \ - if ((expr)) \ - { \ - log(L_WARN "[BMP] " msg); \ - return rv; \ - } \ - } while (0) - -#define IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(p, msg, rv...) \ - do { \ - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(IS_NULL(p), msg, rv); \ - } while (0) - -#define IF_BMP_FAILED_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(func, msg, rv...) \ - do { \ - enum bmp_result rc = func; \ - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(BMP_FAILED(rc), msg, rv); \ - } while (0) - -#endif /* _BIRD_BMP_UTILS_H_ */ \ No newline at end of file From a995ed43860eb139a13456242aa12486179fac86 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sun, 28 Mar 2021 15:13:23 +0200 Subject: [PATCH 03/14] BMP: Do not use global instance ptr internally Use local variable to refence relevant instance instead of using global instance ptr. Also, use 'p' variable instead of 'bmp' so we can use common macros like TRACE(). --- proto/bmp/bmp.c | 320 +++++++++++++++++++++++++----------------------- proto/bmp/map.c | 4 +- proto/bmp/map.h | 4 +- 3 files changed, 174 insertions(+), 154 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 5153ef36..d088226e 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -193,14 +193,14 @@ static void bmp_sock_err(sock *sk, int err); static void -bmp_send_peer_up_notif_msg(const struct bgp_proto *bgp, +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); 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); + const size_t tx_msg_size, void *bmp_); // Stores necessary any data in list struct bmp_data_node { @@ -248,20 +248,20 @@ bmp_init_msg_serialize(buffer *stream, const char *sys_descr, const char *sys_na } static void -bmp_schedule_tx_packet(const byte *payload, const size_t size) +bmp_schedule_tx_packet(struct bmp_proto *p, const byte *payload, const size_t size) { - ASSERT(g_bmp->station_connected); + ASSERT(p->station_connected); - struct bmp_data_node *tx_data = mb_alloc(g_bmp->tx_mem_pool, sizeof (struct bmp_data_node)); - tx_data->data = mb_alloc(g_bmp->tx_mem_pool, size); + struct bmp_data_node *tx_data = mb_alloc(p->tx_mem_pool, sizeof (struct bmp_data_node)); + tx_data->data = mb_alloc(p->tx_mem_pool, size); memcpy(tx_data->data, payload, size); tx_data->data_size = size; - add_tail(&g_bmp->tx_queue, &tx_data->n); + add_tail(&p->tx_queue, &tx_data->n); - if (sk_tx_buffer_empty(g_bmp->conn->sk) - && !ev_active(g_bmp->conn->tx_ev)) + if (sk_tx_buffer_empty(p->conn->sk) + && !ev_active(p->conn->tx_ev)) { - ev_schedule(g_bmp->conn->tx_ev); + ev_schedule(p->conn->tx_ev); } } @@ -270,21 +270,23 @@ bmp_schedule_tx_packet(const byte *payload, const size_t size) * NOTE: Send Initiation Message to the BMP collector. */ static void -bmp_startup(void) +bmp_startup(struct bmp_proto *p) { - ASSERT(g_bmp->station_connected && !g_bmp->started); + ASSERT(p->station_connected && !p->started); - buffer payload = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); - bmp_init_msg_serialize(&payload, g_bmp->sys_descr, g_bmp->sys_name); - bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); + buffer payload = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); + bmp_init_msg_serialize(&payload, p->sys_descr, p->sys_name); + bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); - g_bmp->started = true; + p->started = true; } void bmp_fire_tx(void *vconn) { - struct bmp_conn *conn = (struct bmp_conn *) vconn; + struct bmp_conn *conn = (void *) vconn; + struct bmp_proto *p = conn->bmp; + IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( conn->sk, "Socket is null" @@ -292,22 +294,21 @@ bmp_fire_tx(void *vconn) byte *buf = conn->sk->tbuf; IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - EMPTY_LIST(g_bmp->tx_queue), + EMPTY_LIST(p->tx_queue), "Called BMP TX event handler when there is not any data to send" ); size_t cnt = 0; // Counts max packets which we want to send per TX slot struct bmp_data_node *tx_data; struct bmp_data_node *tx_data_next; - size_t data_size = 0; - WALK_LIST_DELSAFE(tx_data, tx_data_next, g_bmp->tx_queue) + WALK_LIST_DELSAFE(tx_data, tx_data_next, p->tx_queue) { if (tx_data->data_size > conn->sk->tbsize) { sk_set_tbsize(conn->sk, tx_data->data_size); } - data_size = tx_data->data_size; + size_t data_size = tx_data->data_size; memcpy(buf, tx_data->data, tx_data->data_size); mb_free(tx_data->data); rem_node((node *) tx_data); @@ -339,17 +340,17 @@ bmp_tx(struct birdsock *sk) } static inline int -bmp_open_socket(struct bmp_proto *bmp) +bmp_open_socket(struct bmp_proto *p) { - sock *s = bmp->conn->sk; - s->daddr = bmp->station_ip; - s->dport = bmp->station_port; + sock *s = p->conn->sk; + s->daddr = p->station_ip; + s->dport = p->station_port; s->err_hook = bmp_sock_err; int rc = sk_open(s); if (rc < 0) - sk_log_error(s, bmp->p.name); + sk_log_error(s, p->p.name); return rc; } @@ -357,9 +358,9 @@ bmp_open_socket(struct bmp_proto *bmp) static void bmp_connection_retry(timer *t) { - struct bmp_proto *bmp = (struct bmp_proto *) t->data; + struct bmp_proto *p = (void *) t->data; - if (bmp_open_socket(bmp) < 0) + if (bmp_open_socket(p) < 0) { log(L_DEBUG "Failed to connect to BMP station"); return; @@ -372,7 +373,7 @@ bmp_connection_retry(timer *t) void bmp_sock_err(sock *sk, int err) { - struct bmp_conn *conn = (struct bmp_conn *)sk->data; + struct bmp_conn *conn = (void *) sk->data; log(L_WARN "[BMP:%s] Socket error: %M", conn->bmp->p.name, err); } @@ -517,56 +518,54 @@ bmp_peer_down_notif_msg_serialize(buffer *stream, const bool is_peer_global, void bmp_open(const struct proto *P) { - struct bmp_proto *bmp = (struct bmp_proto *) P; - g_bmp = bmp; + struct bmp_proto *p = (void *) P; log(L_DEBUG "Init BMP"); - g_bmp->buffer_mpool = rp_new(P->pool, "BMP Buffer"); - g_bmp->map_mem_pool = rp_new(P->pool, "BMP Map"); - g_bmp->tx_mem_pool = rp_new(P->pool, "BMP Tx"); - g_bmp->update_msg_mem_pool = rp_new(P->pool, "BMP Update"); - bmp->conn->tx_ev = ev_new_init(g_bmp->tx_mem_pool, bmp_fire_tx, bmp->conn); + 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->conn->tx_ev = ev_new_init(p->tx_mem_pool, bmp_fire_tx, p->conn); - bmp_peer_map_init(&g_bmp->peer_open_msg.tx_msg, g_bmp->map_mem_pool); - bmp_peer_map_init(&g_bmp->peer_open_msg.rx_msg, g_bmp->map_mem_pool); - bmp_peer_map_init(&g_bmp->bgp_peers, g_bmp->map_mem_pool); + 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); - init_list(&g_bmp->tx_queue); - init_list(&g_bmp->rt_table_in_pre_policy.update_msg_queue); - g_bmp->station_connected = false; - g_bmp->started = false; - g_bmp->connect_retry_timer = NULL; - if (bmp_open_socket(bmp) < 0) + init_list(&p->tx_queue); + init_list(&p->rt_table_in_pre_policy.update_msg_queue); + p->station_connected = false; + p->started = false; + p->connect_retry_timer = NULL; + if (bmp_open_socket(p) < 0) { log(L_DEBUG "Failed to connect to BMP station"); - g_bmp->connect_retry_timer = tm_new_init(P->pool, bmp_connection_retry, bmp, - CONNECT_RETRY_SEC, 0 /* not randomized */); - tm_start(g_bmp->connect_retry_timer, CONNECT_RETRY_SEC); - g_bmp->station_connected = false; + p->connect_retry_timer = tm_new_init(P->pool, bmp_connection_retry, p, + CONNECT_RETRY_SEC, 0 /* not randomized */); + tm_start(p->connect_retry_timer, CONNECT_RETRY_SEC); + p->station_connected = false; } else { log(L_DEBUG "Connected to BMP station"); } - - strncpy(g_bmp->sys_name, bmp->sys_name, sizeof (g_bmp->sys_name) - 1); - strncpy(g_bmp->sys_descr, bmp->sys_descr, sizeof (g_bmp->sys_descr) - 1); } 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) + const size_t tx_msg_size, void *bmp_) { - ASSERT(g_bmp->station_connected); - const struct bmp_peer_map_entry *map_rx_msg = bmp_peer_map_get(&g_bmp->peer_open_msg.rx_msg, key); + struct bmp_proto *p = bmp_; + ASSERT(p->station_connected); + + 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" ); - const struct bmp_peer_map_entry *map_bgp_proto = bmp_peer_map_get(&g_bmp->bgp_peers, key); + 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" @@ -576,7 +575,7 @@ bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif( memcpy(&bgp, map_bgp_proto->data.buf, sizeof (bgp)); if (bgp->p.proto_state == PS_UP) { - bmp_send_peer_up_notif_msg(bgp, tx_msg, tx_msg_size, + bmp_send_peer_up_notif_msg(p, bgp, tx_msg, tx_msg_size, map_rx_msg->data.buf, map_rx_msg->data.buf_size); } } @@ -666,11 +665,11 @@ bmp_is_peer_global_instance(const struct bgp_proto *bgp) } static void -bmp_send_peer_up_notif_msg(const struct bgp_proto *bgp, +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) { - ASSERT(g_bmp->station_connected); + ASSERT(p->station_connected); const struct birdsock *sk = bmp_get_birdsock_ext(bgp); IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( @@ -679,12 +678,12 @@ bmp_send_peer_up_notif_msg(const struct bgp_proto *bgp, ); const bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); - buffer payload = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); + buffer payload = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); bmp_peer_up_notif_msg_serialize(&payload, is_global_instance_peer, bgp->remote_as, bgp->remote_id, 1, sk->saddr, sk->daddr, sk->sport, sk->dport, tx_data, tx_data_size, rx_data, rx_data_size); - bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); + bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_peer_up(bgp); } @@ -693,7 +692,9 @@ void bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, const size_t pkt_size) { - if (!g_bmp) + struct bmp_proto *p = g_bmp; + + if (!p) { return; } @@ -701,20 +702,20 @@ bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); const struct bmp_peer_map_entry *map_entry - = bmp_peer_map_get(&g_bmp->peer_open_msg.rx_msg, key); - if (!map_entry || !g_bmp->started) + = bmp_peer_map_get(&p->peer_open_msg.rx_msg, key); + if (!map_entry || !p->started) { - bmp_peer_map_insert(&g_bmp->peer_open_msg.tx_msg, key, pkt, pkt_size); + bmp_peer_map_insert(&p->peer_open_msg.tx_msg, key, pkt, pkt_size); if (!map_entry) { - bmp_peer_map_insert(&g_bmp->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); + bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); } return; } - bmp_send_peer_up_notif_msg(bgp, pkt, pkt_size, map_entry->data.buf, + bmp_send_peer_up_notif_msg(p, bgp, pkt, pkt_size, map_entry->data.buf, map_entry->data.buf_size); } @@ -722,7 +723,9 @@ void bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, const size_t pkt_size) { - if (!g_bmp) + struct bmp_proto *p = g_bmp; + + if (!p) { return; } @@ -730,99 +733,105 @@ bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); const struct bmp_peer_map_entry *map_data - = bmp_peer_map_get(&g_bmp->peer_open_msg.tx_msg, key); - if (!map_data || !g_bmp->started) + = bmp_peer_map_get(&p->peer_open_msg.tx_msg, key); + if (!map_data || !p->started) { - bmp_peer_map_insert(&g_bmp->peer_open_msg.rx_msg, key, pkt, pkt_size); + bmp_peer_map_insert(&p->peer_open_msg.rx_msg, key, pkt, pkt_size); if (!map_data) { - bmp_peer_map_insert(&g_bmp->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); + bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); } return; } - bmp_send_peer_up_notif_msg(bgp, map_data->data.buf, map_data->data.buf_size, + bmp_send_peer_up_notif_msg(p, bgp, map_data->data.buf, map_data->data.buf_size, pkt, pkt_size); } void bmp_route_monitor_update_in_pre_begin() { - if (!g_bmp) + struct bmp_proto *p = g_bmp; + + if (!p) { return; } - if (g_bmp->monitoring_rib.in_pre_policy == false) + if (p->monitoring_rib.in_pre_policy == false) { return; } IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !g_bmp->started, + !p->started, "BMP instance not started yet" ); IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !EMPTY_LIST(g_bmp->rt_table_in_pre_policy.update_msg_queue), + !EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue), "Previous BMP route monitoring update not finished yet" ); - gettimeofday(&g_bmp->rt_table_in_pre_policy.update_begin_time,NULL); - init_list(&g_bmp->rt_table_in_pre_policy.update_msg_queue); - g_bmp->rt_table_in_pre_policy.update_msg_size = 0; - g_bmp->rt_table_in_pre_policy.update_in_progress = true; + 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; } void bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size) { - if (!g_bmp) + struct bmp_proto *p = g_bmp; + + if (!p) { return; } - if (g_bmp->monitoring_rib.in_pre_policy == false) + if (p->monitoring_rib.in_pre_policy == false) { return; } IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !g_bmp->started, + !p->started, "BMP instance not started yet" ); IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !g_bmp->rt_table_in_pre_policy.update_in_progress, + !p->rt_table_in_pre_policy.update_in_progress, "BMP route monitoring update not started yet" ); - struct bmp_data_node *upd_msg = mb_alloc(g_bmp->update_msg_mem_pool, + struct bmp_data_node *upd_msg = mb_alloc(p->update_msg_mem_pool, sizeof (struct bmp_data_node)); - upd_msg->data = mb_alloc(g_bmp->update_msg_mem_pool, data_size); + 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; - g_bmp->rt_table_in_pre_policy.update_msg_size += data_size; - add_tail(&g_bmp->rt_table_in_pre_policy.update_msg_queue, &upd_msg->n); + 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); } void bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) { - if (!g_bmp) + struct bmp_proto *p = g_bmp; + + if (!p) { return; } - if (g_bmp->monitoring_rib.in_pre_policy == false) + if (p->monitoring_rib.in_pre_policy == false) { return; } IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - (!g_bmp->started || EMPTY_LIST(g_bmp->rt_table_in_pre_policy.update_msg_queue)), + (!p->started || EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue)), "BMP route monitoring update not started yet" ); @@ -840,25 +849,25 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); buffer payload - = bmp_buffer_alloc(g_bmp->buffer_mpool, - g_bmp->rt_table_in_pre_policy.update_msg_size + DEFAULT_MEM_BLOCK_SIZE); + = 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(g_bmp->buffer_mpool, - g_bmp->rt_table_in_pre_policy.update_msg_size); + = bmp_buffer_alloc(p->buffer_mpool, + p->rt_table_in_pre_policy.update_msg_size); struct bmp_data_node *data; - WALK_LIST(data, g_bmp->rt_table_in_pre_policy.update_msg_queue) + WALK_LIST(data, p->rt_table_in_pre_policy.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), - g_bmp->rt_table_in_pre_policy.update_begin_time.tv_sec, - g_bmp->rt_table_in_pre_policy.update_begin_time.tv_usec); + p->rt_table_in_pre_policy.update_begin_time.tv_sec, + p->rt_table_in_pre_policy.update_begin_time.tv_usec); - bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); + bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_flush(&payload); bmp_buffer_flush(&update_msgs); @@ -868,24 +877,26 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) void bmp_route_monitor_update_in_pre_end() { - if (!g_bmp) + struct bmp_proto *p = g_bmp; + + if (!p) { return; } - if (g_bmp->monitoring_rib.in_pre_policy == false) + if (p->monitoring_rib.in_pre_policy == false) { return; } IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - (!g_bmp->started || EMPTY_LIST(g_bmp->rt_table_in_pre_policy.update_msg_queue)), + (!p->started || EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue)), "BMP route monitoring update not started yet" ); struct bmp_data_node *upd_msg; struct bmp_data_node *upd_msg_next; - WALK_LIST_DELSAFE(upd_msg, upd_msg_next, g_bmp->rt_table_in_pre_policy.update_msg_queue) + 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); @@ -896,7 +907,9 @@ bmp_route_monitor_update_in_pre_end() void bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C) { - if (g_bmp->monitoring_rib.in_pre_policy == false) + struct bmp_proto *p = g_bmp; + + if (p->monitoring_rib.in_pre_policy == false) { return; } @@ -928,7 +941,7 @@ bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C) bgp_rte_update_in_notify(P, C, n, e, NULL, e->src); } - bmp_route_monitor_update_in_pre_commit((struct bgp_proto*) P); + bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) P); bmp_route_monitor_update_in_pre_end(); ++cnt; } @@ -952,20 +965,20 @@ bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C) } static void -bmp_send_peer_down_notif_msg(const struct bgp_proto *bgp, +bmp_send_peer_down_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, const byte* data, const size_t data_size) { - ASSERT(g_bmp->station_connected); + ASSERT(p->station_connected); const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps_ext(bgp); bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); buffer payload - = bmp_buffer_alloc(g_bmp->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); + = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); bmp_peer_down_notif_msg_serialize(&payload, is_global_instance_peer, bgp->remote_as, bgp->remote_id, remote_caps ? remote_caps->as4_support : bgp->as4_session, bgp->remote_ip, data, data_size); - bmp_schedule_tx_packet(bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); + bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_free(&payload); } @@ -974,26 +987,28 @@ void bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, size_t pkt_size) { - if (!g_bmp || !g_bmp->started) + struct bmp_proto *p = g_bmp; + + if (!p || !p->started) { return; } struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - if (!bmp_peer_map_get(&g_bmp->bgp_peers, key)) + if (!bmp_peer_map_get(&p->bgp_peers, key)) { return; } - bmp_peer_map_remove(&g_bmp->peer_open_msg.tx_msg, key); - bmp_peer_map_remove(&g_bmp->peer_open_msg.rx_msg, key); - bmp_peer_map_remove(&g_bmp->bgp_peers, key); + 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; buffer payload - = bmp_buffer_alloc(g_bmp->buffer_mpool, pkt_size + missing_bgp_hdr_size + 1); + = bmp_buffer_alloc(p->buffer_mpool, pkt_size + missing_bgp_hdr_size + 1); if (pkt != NULL && pkt_size > 0) { byte marker[BGP_MSG_HDR_MARKER_SIZE]; @@ -1028,13 +1043,13 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, } } - bmp_send_peer_down_notif_msg(bgp, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); + bmp_send_peer_down_notif_msg(p, bgp, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_free(&payload); } static void -bmp_send_termination_msg(struct bmp_proto *bmp, +bmp_send_termination_msg(struct bmp_proto *p, const enum bmp_term_reason reason) { const size_t term_msg_hdr_size = BMP_TERM_INFO_TYPE_SIZE @@ -1042,14 +1057,14 @@ bmp_send_termination_msg(struct bmp_proto *bmp, + BMP_TERM_REASON_CODE_SIZE; const size_t term_msg_size = BMP_COMMON_HDR_SIZE + term_msg_hdr_size; buffer stream - = bmp_buffer_alloc(g_bmp->buffer_mpool, term_msg_size); + = bmp_buffer_alloc(p->buffer_mpool, term_msg_size); bmp_common_hdr_serialize(&stream, BMP_TERM_MSG, term_msg_hdr_size); bmp_put_u16(&stream, BMP_TERM_INFO_REASON); bmp_put_u16(&stream, BMP_TERM_REASON_CODE_SIZE); // 2-byte code indication the reason bmp_put_u16(&stream, reason); - memcpy(bmp->conn->sk->tbuf, bmp_buffer_data(&stream), bmp_buffer_pos(&stream)); + memcpy(p->conn->sk->tbuf, bmp_buffer_data(&stream), bmp_buffer_pos(&stream)); IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - sk_send(bmp->conn->sk, bmp_buffer_pos(&stream)) < 0, + sk_send(p->conn->sk, bmp_buffer_pos(&stream)) < 0, "Failed to send BMP termination message" ); @@ -1059,16 +1074,18 @@ bmp_send_termination_msg(struct bmp_proto *bmp, static void bmp_station_connected(struct birdsock *sk) { - struct bmp_conn *conn = (struct bmp_conn *)sk->data; + struct bmp_conn *conn = (void *) sk->data; + struct bmp_proto *p = conn->bmp; + conn->sk->tx_hook = bmp_tx; - conn->bmp->station_connected = true; + p->station_connected = true; - bmp_startup(); + bmp_startup(p); - bmp_peer_map_walk(&conn->bmp->peer_open_msg.tx_msg, - bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif); - bmp_peer_map_flush(&conn->bmp->peer_open_msg.tx_msg); - bmp_peer_map_flush(&conn->bmp->peer_open_msg.rx_msg); + bmp_peer_map_walk(&p->peer_open_msg.tx_msg, + bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif, p); + bmp_peer_map_flush(&p->peer_open_msg.tx_msg); + bmp_peer_map_flush(&p->peer_open_msg.rx_msg); } static inline void @@ -1090,54 +1107,57 @@ static struct proto * bmp_init(struct proto_config *CF) { struct proto *P = proto_new(CF); - struct bmp_proto *bmp = (struct bmp_proto *) P; + struct bmp_proto *p = (void *) P; + struct bmp_config *cf = (void *) CF; - struct bmp_config *cf = (struct bmp_config *) CF; - bmp->cf = cf; - bmp->station_ip = cf->station_ip; - bmp->station_port = cf->station_port; - strcpy(bmp->sys_descr, cf->sys_descr); - strcpy(bmp->sys_name, cf->sys_name); - bmp->disabled = cf->disabled; - bmp->monitoring_rib.in_pre_policy = cf->monitoring_rib_in_pre_policy; - bmp->monitoring_rib.in_post_policy = cf->monitoring_rib_in_post_policy; - bmp->monitoring_rib.local = cf->monitoring_rib_local; + p->cf = cf; + 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->disabled = cf->disabled; + 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; - g_bmp = bmp; return P; } static int bmp_start(struct proto *P) { - struct bmp_proto *bmp = (struct bmp_proto *) P; - if (bmp->disabled) + struct bmp_proto *p = (void *) P; + + if (p->disabled) { g_bmp = NULL; return PS_DOWN; } - if (bmp->disabled) + if (p->disabled) { return PS_DOWN; } - bmp->conn = mb_allocz(P->pool, sizeof (struct bmp_conn)); - bmp->conn->bmp = bmp; - bmp_setup_socket(bmp->conn); + p->conn = mb_allocz(P->pool, sizeof (struct bmp_conn)); + p->conn->bmp = p; + bmp_setup_socket(p->conn); bmp_open(P); + g_bmp = p; + return PS_UP; } static int bmp_shutdown(struct proto *P) { - struct bmp_proto *bmp = (struct bmp_proto *) P; - bmp_send_termination_msg(bmp, BMP_TERM_REASON_ADM); + struct bmp_proto *p = (void *) P; + bmp_send_termination_msg(p, BMP_TERM_REASON_ADM); + + p->station_connected = false; + p->started = false; - g_bmp->station_connected = false; - g_bmp->started = false; g_bmp = NULL; return PS_DOWN; diff --git a/proto/bmp/map.c b/proto/bmp/map.c index f8219dcc..16e714fd 100644 --- a/proto/bmp/map.c +++ b/proto/bmp/map.c @@ -107,13 +107,13 @@ bmp_peer_map_get(struct bmp_peer_map *map, const struct bmp_peer_map_key key) } void -bmp_peer_map_walk(const struct bmp_peer_map *map, bmp_peer_map_walk_action action) +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); + 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 index 0ad5295f..8e7ea695 100644 --- a/proto/bmp/map.h +++ b/proto/bmp/map.h @@ -60,9 +60,9 @@ 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); + 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); +bmp_peer_map_walk(const struct bmp_peer_map *map, bmp_peer_map_walk_action action, void *arg); #endif /* _BIRD_BMP_MAP_H_ */ From 4adebdf198d6e2ca1afcd7cb9bfac81725e7b24e Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sun, 28 Mar 2021 15:36:59 +0200 Subject: [PATCH 04/14] BMP: Minor cleanups Remove redundant 'disable' option, simplify IP address serialization, and remove useless macros. --- proto/bgp/bgp.c | 10 +++++----- proto/bgp/bgp.h | 1 - proto/bmp/bmp.c | 42 +++++++----------------------------------- proto/bmp/bmp.h | 9 --------- proto/bmp/config.Y | 11 ++--------- 5 files changed, 14 insertions(+), 59 deletions(-) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 709625ea..a6d30eff 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -869,7 +869,7 @@ bgp_graceful_restart_timeout(timer *t) else { bgp_stop(p, 0, NULL, 0); - bmp_peer_down(p, BE_NONE, NULL, BMP_PEER_DOWN_NULL_PKT_SIZE); + bmp_peer_down(p, BE_NONE, NULL, 0); } } @@ -996,7 +996,7 @@ bgp_sock_err(sock *sk, int err) else { BGP_TRACE(D_EVENTS, "Connection closed"); - bmp_peer_down(p, BE_SOCKET, NULL, BMP_PEER_DOWN_NULL_PKT_SIZE); + bmp_peer_down(p, BE_SOCKET, NULL, 0); } if ((conn->state == BS_ESTABLISHED) && p->gr_ready) @@ -1322,7 +1322,7 @@ 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, BMP_PEER_DOWN_NULL_PKT_SIZE); + bmp_peer_down(p, BE_MISC, NULL, 0); } } else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP)) @@ -1334,7 +1334,7 @@ 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, BMP_PEER_DOWN_NULL_PKT_SIZE); + bmp_peer_down(p, BE_MISC, NULL, 0); } } else @@ -1376,7 +1376,7 @@ 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, BMP_PEER_DOWN_NULL_PKT_SIZE); + bmp_peer_down(p, BE_MISC, NULL, 0); } } } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index c4f4f3be..5f68e3de 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -671,7 +671,6 @@ byte * bgp_create_end_mark(struct bgp_channel *c, byte *buf); #define PKT_ROUTE_REFRESH 0x05 /* [RFC2918] */ #define PKT_BEGIN_REFRESH 0x1e /* Dummy type for BoRR packet [RFC7313] */ #define PKT_SCHEDULE_CLOSE 0x1f /* Used internally to schedule socket close */ -#define PKT_BMP_MSG 0x20 /* BGP Monitoring Protocol message [RFC7854] */ /* Attributes */ diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index d088226e..57112cbe 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -377,12 +377,12 @@ bmp_sock_err(sock *sk, int err) log(L_WARN "[BMP:%s] Socket error: %M", conn->bmp->p.name, err); } -static void -bmp_put_ip4_addr_with_padding(buffer *stream, const ip4_addr addr) +static inline void +bmp_put_ipa(buffer *stream, const ip_addr addr) { - byte padding[BMP_PADDING_IP4_ADDR_SIZE] = { 0x00 }; - bmp_put_data(stream, padding, BMP_PADDING_IP4_ADDR_SIZE); - bmp_put_ip4(stream, addr); + bmp_put_ip6(stream, ipa_is_ip4(addr) ? + ip6_build(0,0,0, ipa_to_u32(addr)) : + ipa_to_ip6(addr)); } static void @@ -434,15 +434,7 @@ bmp_per_peer_hdr_serialize(buffer *stream, const bool is_global_instance_peer, bmp_put_u8(stream, peer_flags); // TODO: Provide appropriate peer Route Distinguisher if applicable bmp_put_u64(stream, 0x00); // 0x00 - Not supported peer distinguisher - if (ipa_is_ip4(peer_addr)) - { - bmp_put_ip4_addr_with_padding(stream, ipa_to_ip4(peer_addr)); - } - else - { - bmp_put_ip6(stream, ipa_to_ip6(peer_addr)); - } - + bmp_put_ipa(stream, peer_addr); bmp_put_u32(stream, peer_as); bmp_put_u32(stream, peer_bgp_id); bmp_put_u32(stream, ts_sec); @@ -478,15 +470,7 @@ bmp_peer_up_notif_msg_serialize(buffer *stream, const bool is_peer_global, bmp_per_peer_hdr_serialize(stream, is_peer_global, true /* TODO: Hardcoded pre-policy Adj-RIB-In */, as4_support, remote_addr, peer_as, peer_bgp_id, 0, 0); // 0, 0 - No timestamp provided - if (ipa_is_ip4(local_addr)) - { - bmp_put_ip4_addr_with_padding(stream, ipa_to_ip4(local_addr)); - } - else - { - bmp_put_ip6(stream, ipa_to_ip6(local_addr)); - } - + 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); @@ -1115,7 +1099,6 @@ bmp_init(struct proto_config *CF) p->station_port = cf->station_port; strcpy(p->sys_descr, cf->sys_descr); strcpy(p->sys_name, cf->sys_name); - p->disabled = cf->disabled; 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; @@ -1128,17 +1111,6 @@ bmp_start(struct proto *P) { struct bmp_proto *p = (void *) P; - if (p->disabled) - { - g_bmp = NULL; - return PS_DOWN; - } - - if (p->disabled) - { - return PS_DOWN; - } - p->conn = mb_allocz(P->pool, sizeof (struct bmp_conn)); p->conn->bmp = p; bmp_setup_socket(p->conn); diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index eb800f8e..73f40eb8 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -23,12 +23,6 @@ // Max length of MIB-II description object #define MIB_II_STR_LEN 255 -enum bmp_peer_down { - // Value of packet size of 'pkt_size' argument of bmp_peer_down() function - // used for pointing out that there was not any packet to pass - BMP_PEER_DOWN_NULL_PKT_SIZE = 0 -}; - // The following fields of this structure controls whether there will be put // specific routes into Route Monitoring message and send to BMP collector struct monitoring_rib { @@ -43,7 +37,6 @@ struct bmp_config { const char *sys_name; // sysName MIB-II [RFC1213] object ip_addr station_ip; // Monitoring station address u16 station_port; // Monitoring station TCP port - bool disabled; // Manually disabled 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 @@ -82,10 +75,8 @@ struct bmp_proto { char sys_name[MIB_II_STR_LEN]; // sysName MIB-II [RFC1213] object ip_addr station_ip; // Monitoring station IP address u16 station_port; // Monitoring station TCP port - bool disabled; // Manually disabled struct monitoring_rib monitoring_rib; // Below fields are for internal use - int station_socket; // Socket associated with the BMP collector 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 pool *buffer_mpool; // Memory pool used for BMP buffer allocations diff --git a/proto/bmp/config.Y b/proto/bmp/config.Y index df7822ea..776d7ecc 100644 --- a/proto/bmp/config.Y +++ b/proto/bmp/config.Y @@ -25,7 +25,6 @@ proto: bmp_proto '}' ; bmp_proto_start: proto_start BMP { this_proto = proto_config_new(&proto_bmp, $1); - BMP_CFG->disabled = false; BMP_CFG->station_ip = IPA_NONE4; BMP_CFG->station_port = 0; BMP_CFG->sys_descr = "Not defined"; @@ -39,9 +38,8 @@ bmp_proto_start: proto_start BMP { bmp_station_address: /* empty */ | bmp_station_address IP ipa { - if (!BMP_CFG->disabled) - if (ipa_zero($3)) - cf_error("Invalid BMP monitoring station IP address"); + if (ipa_zero($3)) + cf_error("Invalid BMP monitoring station IP address"); BMP_CFG->station_ip = $3; } | bmp_station_address PORT expr { @@ -54,9 +52,6 @@ bmp_station_address: bmp_proto: bmp_proto_start proto_name '{' | bmp_proto proto_item ';' - | bmp_proto ENABLED bool ';' { - BMP_CFG->disabled = $3; - } | bmp_proto STATION ADDRESS bmp_station_address ';' | bmp_proto SYSTEM DESCRIPTION text ';' { if (!$4 || (strlen($4) == 0)) @@ -81,8 +76,6 @@ bmp_proto: | bmp_proto MONITORING RIB LOCAL bool ';' { BMP_CFG->monitoring_rib_local = $5; } - | bmp_proto DISABLED bool ';' { - BMP_CFG->disabled = $3; } ; CF_CODE From 568fd666136fcf7a37eb445d18b478b6464536c4 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sun, 28 Mar 2021 16:41:53 +0200 Subject: [PATCH 05/14] BMP: Integrate bmp_conn to bmp_proto There is only one socket per BMP instance, no need to have separate struct (like in BGP). --- proto/bmp/bmp.c | 65 ++++++++++++++++++++----------------------------- proto/bmp/bmp.h | 9 ++----- 2 files changed, 29 insertions(+), 45 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 57112cbe..4728eaef 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -258,10 +258,10 @@ bmp_schedule_tx_packet(struct bmp_proto *p, const byte *payload, const size_t si tx_data->data_size = size; add_tail(&p->tx_queue, &tx_data->n); - if (sk_tx_buffer_empty(p->conn->sk) - && !ev_active(p->conn->tx_ev)) + if (sk_tx_buffer_empty(p->sk) + && !ev_active(p->tx_ev)) { - ev_schedule(p->conn->tx_ev); + ev_schedule(p->tx_ev); } } @@ -281,18 +281,11 @@ bmp_startup(struct bmp_proto *p) p->started = true; } -void -bmp_fire_tx(void *vconn) +static void +bmp_fire_tx(void *p_) { - struct bmp_conn *conn = (void *) vconn; - struct bmp_proto *p = conn->bmp; - - IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - conn->sk, - "Socket is null" - ); - - byte *buf = conn->sk->tbuf; + struct bmp_proto *p = p_; + byte *buf = p->sk->tbuf; 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" @@ -303,9 +296,9 @@ bmp_fire_tx(void *vconn) struct bmp_data_node *tx_data_next; WALK_LIST_DELSAFE(tx_data, tx_data_next, p->tx_queue) { - if (tx_data->data_size > conn->sk->tbsize) + if (tx_data->data_size > p->sk->tbsize) { - sk_set_tbsize(conn->sk, tx_data->data_size); + sk_set_tbsize(p->sk, tx_data->data_size); } size_t data_size = tx_data->data_size; @@ -314,7 +307,7 @@ bmp_fire_tx(void *vconn) rem_node((node *) tx_data); mb_free(tx_data); IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - (sk_send(conn->sk, data_size) <= 0), + (sk_send(p->sk, data_size) <= 0), "Failed to send BMP packet" ); @@ -323,9 +316,9 @@ bmp_fire_tx(void *vconn) // call if (++cnt > 32) { - if (!ev_active(conn->tx_ev)) + if (!ev_active(p->tx_ev)) { - ev_schedule(conn->tx_ev); + ev_schedule(p->tx_ev); } return; @@ -342,7 +335,7 @@ bmp_tx(struct birdsock *sk) static inline int bmp_open_socket(struct bmp_proto *p) { - sock *s = p->conn->sk; + sock *s = p->sk; s->daddr = p->station_ip; s->dport = p->station_port; s->err_hook = bmp_sock_err; @@ -358,7 +351,7 @@ bmp_open_socket(struct bmp_proto *p) static void bmp_connection_retry(timer *t) { - struct bmp_proto *p = (void *) t->data; + struct bmp_proto *p = t->data; if (bmp_open_socket(p) < 0) { @@ -373,8 +366,8 @@ bmp_connection_retry(timer *t) void bmp_sock_err(sock *sk, int err) { - struct bmp_conn *conn = (void *) sk->data; - log(L_WARN "[BMP:%s] Socket error: %M", conn->bmp->p.name, err); + struct bmp_proto *p = sk->data; + log(L_WARN "[BMP:%s] Socket error: %M", p->p.name, err); } static inline void @@ -510,7 +503,7 @@ bmp_open(const struct proto *P) 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->conn->tx_ev = ev_new_init(p->tx_mem_pool, bmp_fire_tx, p->conn); + p->tx_ev = ev_new_init(p->tx_mem_pool, bmp_fire_tx, p); 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); @@ -1040,15 +1033,14 @@ bmp_send_termination_msg(struct bmp_proto *p, + BMP_TERM_INFO_LEN_FIELD_SIZE + BMP_TERM_REASON_CODE_SIZE; const size_t term_msg_size = BMP_COMMON_HDR_SIZE + term_msg_hdr_size; - buffer stream - = bmp_buffer_alloc(p->buffer_mpool, term_msg_size); + buffer stream = bmp_buffer_alloc(p->buffer_mpool, term_msg_size); bmp_common_hdr_serialize(&stream, BMP_TERM_MSG, term_msg_hdr_size); bmp_put_u16(&stream, BMP_TERM_INFO_REASON); bmp_put_u16(&stream, BMP_TERM_REASON_CODE_SIZE); // 2-byte code indication the reason bmp_put_u16(&stream, reason); - memcpy(p->conn->sk->tbuf, bmp_buffer_data(&stream), bmp_buffer_pos(&stream)); + memcpy(p->sk->tbuf, bmp_buffer_data(&stream), bmp_buffer_pos(&stream)); IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - sk_send(p->conn->sk, bmp_buffer_pos(&stream)) < 0, + sk_send(p->sk, bmp_buffer_pos(&stream)) < 0, "Failed to send BMP termination message" ); @@ -1058,10 +1050,9 @@ bmp_send_termination_msg(struct bmp_proto *p, static void bmp_station_connected(struct birdsock *sk) { - struct bmp_conn *conn = (void *) sk->data; - struct bmp_proto *p = conn->bmp; + struct bmp_proto *p = (void *) sk->data; - conn->sk->tx_hook = bmp_tx; + sk->tx_hook = bmp_tx; p->station_connected = true; bmp_startup(p); @@ -1073,17 +1064,17 @@ bmp_station_connected(struct birdsock *sk) } static inline void -bmp_setup_socket(struct bmp_conn *conn) +bmp_setup_socket(struct bmp_proto *p) { - sock *sk = sk_new(proto_pool); + sock *sk = sk_new(p->tx_mem_pool); sk->type = SK_TCP_ACTIVE; sk->ttl = IP4_MAX_TTL; sk->tos = IP_PREC_INTERNET_CONTROL; sk->tbsize = BGP_TX_BUFFER_EXT_SIZE; sk->tx_hook = bmp_station_connected; - conn->sk = sk; - sk->data = conn; + p->sk = sk; + sk->data = p; } /** Configuration handle section **/ @@ -1111,9 +1102,7 @@ bmp_start(struct proto *P) { struct bmp_proto *p = (void *) P; - p->conn = mb_allocz(P->pool, sizeof (struct bmp_conn)); - p->conn->bmp = p; - bmp_setup_socket(p->conn); + bmp_setup_socket(p); bmp_open(P); g_bmp = p; diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 73f40eb8..ff02d3b2 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -46,12 +46,6 @@ struct bmp_config { struct bgp_proto; struct bmp_proto; -struct bmp_conn { - struct bmp_proto *bmp; - struct birdsock *sk; - event *tx_ev; -}; - // Stores sent and received BGP OPEN MSGs struct bmp_peer_open_msg { struct bmp_peer_map tx_msg; @@ -70,7 +64,8 @@ struct rt_table_info { struct bmp_proto { struct proto p; // Parent proto const struct bmp_config *cf; // Shortcut to BMP configuration - struct bmp_conn *conn; // Connection we have established + sock *sk; // TCP connection + event *tx_ev; // TX 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 station_ip; // Monitoring station IP address From 4d56b70dc5facdf4b839b76bf80c93856bcbb121 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 29 Mar 2021 04:43:04 +0200 Subject: [PATCH 06/14] BMP: Remove duplicate functions for update encoding Use existing BGP functions also for BMP update encoding. --- nest/protocol.h | 3 +- nest/rt-table.c | 10 +- proto/bgp/bgp.h | 5 +- proto/bgp/packets.c | 410 ++++++++++---------------------------------- proto/bmp/bmp.c | 8 +- 5 files changed, 101 insertions(+), 335 deletions(-) diff --git a/nest/protocol.h b/nest/protocol.h index 03b8a8ec..da6d434e 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -214,8 +214,7 @@ 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)(const struct proto *, const struct channel *, - const net *net, const struct rte *new, const struct rte *old, const struct rte_src *src); + 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 *); diff --git a/nest/rt-table.c b/nest/rt-table.c index 553e8223..2b065032 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -3097,7 +3097,7 @@ 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->proto, c, net, new, old, src); + c->proto->rte_update_in_notify(c, n, old, src); return 1; } @@ -3122,12 +3122,12 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr if (!old) goto drop_withdraw; - if (c->proto->rte_update_in_notify) - c->proto->rte_update_in_notify(c->proto, c, net, new, old, src); - 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; } @@ -3158,7 +3158,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr tab->rt_count++; if (c->proto->rte_update_in_notify) - c->proto->rte_update_in_notify(c->proto, c, net, new, old, src); + c->proto->rte_update_in_notify(c, n, e, src); return 1; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 5f68e3de..7c96e851 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -434,6 +434,7 @@ struct bgp_write_state { int as4_session; int add_path; int mpls; + int sham; eattr *mp_next_hop; const adata *mpls_labels; @@ -624,9 +625,7 @@ 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(const struct proto *P, const struct channel *C, - const net *net, const struct rte *new, const struct rte *old, - const struct rte_src *src); +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); diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index bec8cd91..42016eae 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1566,7 +1566,10 @@ bgp_encode_nlri_ip4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu memcpy(pos, &a, b); ADVANCE(pos, size, b); - bgp_free_prefix(s->channel, px); + if (!s->sham) + bgp_free_prefix(s->channel, px); + else + rem_node(&px->buck_node); } return pos - buf; @@ -1651,7 +1654,10 @@ bgp_encode_nlri_ip6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu memcpy(pos, &a, b); ADVANCE(pos, size, b); - bgp_free_prefix(s->channel, px); + if (!s->sham) + bgp_free_prefix(s->channel, px); + else + rem_node(&px->buck_node); } return pos - buf; @@ -1739,7 +1745,10 @@ bgp_encode_nlri_vpn4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b memcpy(pos, &a, b); ADVANCE(pos, size, b); - bgp_free_prefix(s->channel, px); + if (!s->sham) + bgp_free_prefix(s->channel, px); + else + rem_node(&px->buck_node); } return pos - buf; @@ -1836,7 +1845,10 @@ bgp_encode_nlri_vpn6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b memcpy(pos, &a, b); ADVANCE(pos, size, b); - bgp_free_prefix(s->channel, px); + if (!s->sham) + bgp_free_prefix(s->channel, px); + else + rem_node(&px->buck_node); } return pos - buf; @@ -1923,7 +1935,10 @@ bgp_encode_nlri_flow4(struct bgp_write_state *s, struct bgp_bucket *buck, byte * memcpy(pos, net->data, flen); ADVANCE(pos, size, flen); - bgp_free_prefix(s->channel, px); + if (!s->sham) + bgp_free_prefix(s->channel, px); + else + rem_node(&px->buck_node); } return pos - buf; @@ -2015,7 +2030,10 @@ bgp_encode_nlri_flow6(struct bgp_write_state *s, struct bgp_bucket *buck, byte * memcpy(pos, net->data, flen); ADVANCE(pos, size, flen); - bgp_free_prefix(s->channel, px); + if (!s->sham) + bgp_free_prefix(s->channel, px); + else + rem_node(&px->buck_node); } return pos - buf; @@ -2242,224 +2260,6 @@ bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to) #define MAX_ATTRS_LENGTH (end-buf+BGP_HEADER_LENGTH - 1024) -/** - * Following functions starting with prefix bgp_bmp_* compose BGP UPDATE messages. - * Their implementation has been adopted from relevant function without 'bmp_' part in - * their names. - */ - -// Buffer @buf should be big enough. It means that there should be available at least 19 bytes -static byte * -bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type) -{ - if (!buf) - { - return NULL; - } - - memset(buf + BGP_MSG_HDR_MARKER_POS, 0xff, BGP_MSG_HDR_MARKER_SIZE); - put_u16(buf + BGP_MSG_HDR_LENGTH_POS, msg_size); - put_u8(buf + BGP_MSG_HDR_TYPE_POS, msg_type); - - return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE; -} - -static uint -bgp_bmp_encode_nlri_ip4(struct bgp_write_state *s, const net *n, - const u32 path_id, byte *buf, uint size) -{ - const struct net_addr_ip4 *naddr = (net_addr_ip4 *)n->n.addr; - - byte *pos = buf; - /* Encode path ID */ - if (s->add_path) - { - put_u32(pos, path_id); - ADVANCE(pos, size, 4); - } - - /* Encode prefix length */ - *pos = naddr->pxlen; - ADVANCE(pos, size, 1); - - /* Encode MPLS labels */ - if (s->mpls) - { - bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1); - } - - /* Encode prefix body */ - ip4_addr a = ip4_hton(naddr->prefix); - uint b = (naddr->pxlen + 7) / 8; - memcpy(pos, &a, b); - ADVANCE(pos, size, b); - - return pos - buf; -} - -static uint -bgp_bmp_encode_nlri_ip6(struct bgp_write_state *s, const net *n, - const u32 path_id, byte *buf, uint size) -{ - if (size < BGP_NLRI_MAX) - { - return 0; - } - - const struct net_addr_ip6 *naddr = (net_addr_ip6 *)n->n.addr; - byte *pos = buf; - /* Encode path ID */ - if (s->add_path) - { - put_u32(pos, path_id); - ADVANCE(pos, size, 4); - } - - /* Encode prefix length */ - *pos = naddr->pxlen; - ADVANCE(pos, size, 1); - - /* Encode MPLS labels */ - if (s->mpls) - { - bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1); - } - - /* Encode prefix body */ - ip6_addr a = ip6_hton(naddr->prefix); - uint b = (naddr->pxlen + 7) / 8; - memcpy(pos, &a, b); - ADVANCE(pos, size, b); - - return pos - buf; -} - -static byte * -bgp_bmp_create_ip_reach(struct bgp_write_state *s, const net *n, - const struct rte *new, const struct rte *old, const u32 path_id, - byte *buf, uint size) -{ - /* - * 2 B Withdrawn Routes Length (zero) - * --- IPv4 Withdrawn Routes NLRI (unused) - * 2 B Total Path Attribute Length - * var Path Attributes - * var IPv4 Network Layer Reachability Information - */ - - int lr, la; // Route length, attribute length - ea_list *attrs = new ? new->attrs->eattrs : old->attrs->eattrs; - bgp_fix_attr_flags(attrs); - - la = bgp_encode_attrs(s, attrs, buf + 2, buf + size - 2); - if (la < 0) - { - /* Attribute list too long */ - log(L_ERR "Failed to encode UPDATE msg attributes"); - return NULL; - } - - put_u16(buf, la); - lr = bgp_bmp_encode_nlri_ip4(s, n, path_id, buf + 2 + la, size - (2 + la)); - - return buf + 2 + la + lr; -} - -static byte * -bgp_bmp_create_mp_reach(struct bgp_write_state *s, const net *n, - const struct rte *new, const struct rte *old, const u32 path_id, - byte *buf, uint size) -{ - /* - * 2 B IPv4 Withdrawn Routes Length (zero) - * --- IPv4 Withdrawn Routes NLRI (unused) - * 2 B Total Path Attribute Length - * 1 B MP_REACH_NLRI hdr - Attribute Flags - * 1 B MP_REACH_NLRI hdr - Attribute Type Code - * 2 B MP_REACH_NLRI hdr - Length of Attribute Data - * 2 B MP_REACH_NLRI data - Address Family Identifier - * 1 B MP_REACH_NLRI data - Subsequent Address Family Identifier - * 1 B MP_REACH_NLRI data - Length of Next Hop Network Address - * var MP_REACH_NLRI data - Network Address of Next Hop - * 1 B MP_REACH_NLRI data - Reserved (zero) - * var MP_REACH_NLRI data - Network Layer Reachability Information - * var Rest of Path Attributes - * --- IPv4 Network Layer Reachability Information (unused) - */ - - int lh, lr, la; /* Lengths of next hop, NLRI and attributes */ - - /* Begin of MP_REACH_NLRI atribute */ - buf[4] = BAF_OPTIONAL | BAF_EXT_LEN; - buf[5] = BA_MP_REACH_NLRI; - put_u16(buf+6, 0); /* Will be fixed later */ - put_af3(buf+8, s->channel->afi); - byte *pos = buf+11; - byte *end = buf + size; - /* Encode attributes to temporary buffer */ - byte *abuf = alloca(MAX_ATTRS_LENGTH); - - ea_list *attrs = new ? new->attrs->eattrs : old->attrs->eattrs; - bgp_fix_attr_flags(attrs); - - la = bgp_encode_attrs(s, attrs, abuf, abuf + MAX_ATTRS_LENGTH); - if (la < 0) - { - /* Attribute list too long */ - log(L_ERR "Failed to encode UPDATE msg attributes"); - return NULL; - } - - /* Encode the next hop */ - lh = bgp_encode_next_hop(s, s->mp_next_hop, pos+1); - *pos = lh; - pos += 1+lh; - - /* Reserved field */ - *pos++ = 0; - - /* Encode the NLRI */ - lr = bgp_bmp_encode_nlri_ip6(s, n, path_id, pos, end - (buf + la)); - pos += lr; - - /* End of MP_REACH_NLRI atribute, update data length */ - put_u16(buf+6, pos-buf-8); - - /* Copy remaining attributes */ - memcpy(pos, abuf, la); - pos += la; - - /* Initial UPDATE fields */ - put_u16(buf+0, 0); - put_u16(buf+2, pos-buf-4); - - return pos; -} - -static byte * -bgp_bmp_create_ip_unreach(struct bgp_write_state *s, const net *n, - const struct rte *new, const struct rte *old, const u32 path_id, - byte *buf, uint size) -{ - /* - * 2 B Withdrawn Routes Length - * var IPv4 Withdrawn Routes NLRI - * 2 B Total Path Attribute Length (zero) - * --- Path Attributes (unused) - * --- IPv4 Network Layer Reachability Information (unused) - */ - - uint len = 0; - bool is_withdrawn = !new && old; - if (is_withdrawn) - { - len = bgp_bmp_encode_nlri_ip4(s, n, path_id, buf + 2, size - 2); - } - - put_u16(buf, len); - return buf + 2 + len; -} - static byte * bgp_create_ip_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, byte *end) { @@ -2477,7 +2277,8 @@ bgp_create_ip_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu if (la < 0) { /* Attribute list too long */ - bgp_withdraw_bucket(s->channel, buck); + if (!s->sham) + bgp_withdraw_bucket(s->channel, buck); return NULL; } @@ -2524,7 +2325,8 @@ bgp_create_mp_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu if (la < 0) { /* Attribute list too long */ - bgp_withdraw_bucket(s->channel, buck); + if (!s->sham) + bgp_withdraw_bucket(s->channel, buck); return NULL; } @@ -2606,53 +2408,11 @@ bgp_create_mp_unreach(struct bgp_write_state *s, struct bgp_bucket *buck, byte * } static byte * -bgp_bmp_create_mp_unreach(struct bgp_write_state *s, const net *n, - const struct rte *new, const struct rte *old, const u32 path_id, - byte *buf, uint size) +bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck, bool update) { - /* - * 2 B Withdrawn Routes Length (zero) - * --- IPv4 Withdrawn Routes NLRI (unused) - * 2 B Total Path Attribute Length - * 1 B MP_UNREACH_NLRI hdr - Attribute Flags - * 1 B MP_UNREACH_NLRI hdr - Attribute Type Code - * 2 B MP_UNREACH_NLRI hdr - Length of Attribute Data - * 2 B MP_UNREACH_NLRI data - Address Family Identifier - * 1 B MP_UNREACH_NLRI data - Subsequent Address Family Identifier - * var MP_UNREACH_NLRI data - Network Layer Reachability Information - * --- IPv4 Network Layer Reachability Information (unused) - */ - - uint len = 0; - bool is_withdrawn = !new && old; - if (is_withdrawn) - { - len = bgp_bmp_encode_nlri_ip6(s, n, path_id, buf + 11, size); - } - - put_u16(buf+0, 0); - put_u16(buf+2, 7+len); - - /* Begin of MP_UNREACH_NLRI atribute */ - buf[4] = BAF_OPTIONAL | BAF_EXT_LEN; - buf[5] = BA_MP_UNREACH_NLRI; - - put_u16(buf+6, 3+len); - put_af3(buf+8, s->channel->afi); - - return buf+11+len; -} - -void -bgp_rte_update_in_notify(const struct proto *P, const struct channel *C, - const net *n, const struct rte *new, const struct rte *old, - const struct rte_src *src) -{ - struct bgp_proto *p = (struct bgp_proto *)P; - struct bgp_channel *c = (struct bgp_channel *)C; - byte buf[BGP_MAX_EXT_MSG_LENGTH] = { 0x00 }; - byte *pkt = buf + BGP_HEADER_LENGTH; - byte *end = pkt + (bgp_max_packet_length(p->conn) - BGP_HEADER_LENGTH); + struct bgp_proto *p = (void *) c->c.proto; + byte *end = buf + (BGP_MAX_EXT_MSG_LENGTH - BGP_HEADER_LENGTH); + /* FIXME: must be a bit shorter */ struct bgp_caps *peer = p->conn->remote_caps; const struct bgp_af_caps *rem = bgp_find_af_caps(peer, c->afi); @@ -2660,65 +2420,73 @@ bgp_rte_update_in_notify(const struct proto *P, const struct channel *C, .proto = p, .channel = c, .pool = tmp_linpool, - .mp_reach = (bgp_channel_is_ipv6(c) || rem->ext_next_hop), - .as4_session = peer->as4_support, + .mp_reach = (c->afi != BGP_AF_IPV4) || rem->ext_next_hop, + .as4_session = 1, .add_path = c->add_path_rx, .mpls = c->desc->mpls, + .sham = 1, }; - const u32 path_id = c->add_path_rx ? src->private_id : 0; - byte *pos = pkt; - if (!s.mp_reach) + if (!update) { - pos = bgp_bmp_create_ip_unreach(&s, n, new, old, path_id, pkt, end - pkt); - if (!pos) - { - log(L_ERR "Failed to create unreachable field in UPDATE message"); - return; - } - - pos = bgp_bmp_create_ip_reach(&s, n, new, old, path_id, pos, end - pos); - if (!pos) - { - log(L_ERR "Failed to create reachable field in UPDATE message"); - return; - } - - bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE); - bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf); + return !s.mp_reach ? + bgp_create_ip_unreach(&s, buck, buf, end): + bgp_create_mp_unreach(&s, buck, buf, end); } - else if (new) // && s.mp_reach + else { - pos = s.mp_reach - ? bgp_bmp_create_mp_reach(&s, n, new, old, path_id, pos, end - pos) - : bgp_bmp_create_ip_reach(&s, n, new, old, path_id, pos, end - pos); - if (!pos) - { - log(L_ERR "Failed to create reachable field in UPDATE message"); - return; - } - - bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE); - bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf); + return !s.mp_reach ? + bgp_create_ip_reach(&s, buck, buf, end): + bgp_create_mp_reach(&s, buck, buf, end); } +} - if (!new && old) - { - bmp_route_monitor_update_in_pre_commit(p); - bmp_route_monitor_update_in_pre_end(); - bmp_route_monitor_update_in_pre_begin(); - pkt = buf + BGP_HEADER_LENGTH; - end = pkt + (bgp_max_packet_length(p->conn) - BGP_HEADER_LENGTH); - pos = bgp_bmp_create_mp_unreach(&s, n, new, old, path_id, pkt, end - pkt); - if (!pos) - { - log(L_ERR "Failed to create unreachable field in UPDATE message"); - return; - } +static byte * +bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type) +{ + memset(buf + BGP_MSG_HDR_MARKER_POS, 0xff, BGP_MSG_HDR_MARKER_SIZE); + put_u16(buf + BGP_MSG_HDR_LENGTH_POS, msg_size); + put_u8(buf + BGP_MSG_HDR_TYPE_POS, msg_type); - bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE); - bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf); - } + 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) +{ +// struct bgp_proto *p = (void *) C->proto; + struct bgp_channel *c = (void *) C; + + byte buf[BGP_MAX_EXT_MSG_LENGTH]; + byte *pkt = buf + BGP_HEADER_LENGTH; + + ea_list *attrs = new ? new->attrs->eattrs : NULL; + uint ea_size = new ? (sizeof(ea_list) + attrs->count * sizeof(eattr)) : 0; + uint bucket_size = sizeof(struct bgp_bucket) + ea_size; + uint prefix_size = sizeof(struct bgp_prefix) + n->length; + + /* Sham bucket */ + struct bgp_bucket *b = alloca(bucket_size); + *b = (struct bgp_bucket) { }; + init_list(&b->prefixes); + + if (attrs) + memcpy(b->eattrs, attrs, ea_size); + + /* Sham prefix */ + struct bgp_prefix *px = alloca(prefix_size); + *px = (struct bgp_prefix) { }; + px->path_id = src->private_id; + net_copy(px->net, 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); } static byte * diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 4728eaef..550e4c18 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -210,7 +210,7 @@ struct bmp_data_node { }; static void -bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C); +bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C); static void bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size) @@ -881,8 +881,8 @@ bmp_route_monitor_update_in_pre_end() } } -void -bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C) +static void +bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C) { struct bmp_proto *p = g_bmp; @@ -915,7 +915,7 @@ bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C) rte *e; for (e = n->routes; e; e = e->next) { - bgp_rte_update_in_notify(P, C, n, e, NULL, e->src); + bgp_rte_update_in_notify(C, n->n.addr, e, e->src); } bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) P); From 3925e65938e7c778f650d62a721dec7a66c19ab3 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Thu, 15 Apr 2021 18:32:47 +0200 Subject: [PATCH 07/14] BMP: Add some missing bmp_buffer_free() calls They were inadvertently removed during recent code refactoring. Thanks to Dawid Macek for the bugreport and patch. --- proto/bmp/bmp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 550e4c18..dbbb5e0c 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -277,6 +277,7 @@ bmp_startup(struct bmp_proto *p) buffer payload = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); bmp_init_msg_serialize(&payload, p->sys_descr, p->sys_name); bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); + bmp_buffer_free(&payload); p->started = true; } @@ -661,6 +662,7 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, sk->saddr, sk->daddr, sk->sport, sk->dport, tx_data, tx_data_size, 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); } @@ -849,6 +851,9 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) bmp_buffer_flush(&payload); bmp_buffer_flush(&update_msgs); } + + bmp_buffer_free(&payload); + bmp_buffer_free(&update_msgs); } void From 04e3a76c9417d35acdfba96a11327e99000fe47d Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 18 Apr 2023 15:09:21 +0200 Subject: [PATCH 08/14] BMP: Fix missing template It is mandatory for protocol. --- proto/bmp/bmp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index dbbb5e0c..48d16d6c 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -1138,6 +1138,7 @@ bmp_reconfigure(struct proto *P UNUSED, struct proto_config *CF UNUSED) struct protocol proto_bmp = { .name = "BMP", + .template = "bmp%d", .class = PROTOCOL_BMP, .proto_size = sizeof(struct bmp_proto), .config_size = sizeof(struct bmp_config), From fbeef4b74dfd73fb86b1ccc5dd1c6109e3c21624 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 18 Apr 2023 15:13:24 +0200 Subject: [PATCH 09/14] BMP: Move initialization to bmp_start() That fixes BMP socket allocation from an invalid pool. --- proto/bmp/bmp.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 48d16d6c..23e250f8 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -498,23 +498,6 @@ bmp_open(const 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); - - 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); - - init_list(&p->tx_queue); - init_list(&p->rt_table_in_pre_policy.update_msg_queue); - p->station_connected = false; - p->started = false; - p->connect_retry_timer = NULL; if (bmp_open_socket(p) < 0) { log(L_DEBUG "Failed to connect to BMP station"); @@ -1107,6 +1090,24 @@ 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); + + 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); + + init_list(&p->tx_queue); + init_list(&p->rt_table_in_pre_policy.update_msg_queue); + p->station_connected = false; + p->started = false; + p->connect_retry_timer = NULL; + bmp_setup_socket(p); bmp_open(P); From 02164814b49a3385caae0ea10aa042487c6002d2 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 18 Apr 2023 17:21:13 +0200 Subject: [PATCH 10/14] BMP: Allow build without BMP and disable BMP build by default It has still several important issues to be enabled by default. --- configure.ac | 2 +- proto/bgp/bgp.c | 5 ++++- proto/bgp/packets.c | 6 ++++++ proto/bmp/bmp.h | 18 +++++++++++++++++- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index f2091219..c9c52038 100644 --- a/configure.ac +++ b/configure.ac @@ -312,7 +312,7 @@ if test "$enable_mpls_kernel" != no ; then fi fi -all_protocols="$proto_bfd babel bgp bmp mrt ospf perf pipe radv rip rpki static" +all_protocols="$proto_bfd babel bgp mrt ospf perf pipe radv rip rpki static" all_protocols=`echo $all_protocols | sed 's/ /,/g'` diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index a6d30eff..c806765a 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1694,7 +1694,6 @@ bgp_init(struct proto_config *CF) struct bgp_config *cf = (struct bgp_config *) CF; P->rt_notify = bgp_rt_notify; - P->rte_update_in_notify = bgp_rte_update_in_notify; P->preexport = bgp_preexport; P->neigh_notify = bgp_neigh_notify; P->reload_routes = bgp_reload_routes; @@ -1706,6 +1705,10 @@ 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; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 42016eae..b9537169 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2407,6 +2407,9 @@ bgp_create_mp_unreach(struct bgp_write_state *s, struct bgp_bucket *buck, byte * return buf+11+len; } + +#ifdef CONFIG_BMP + static byte * bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck, bool update) { @@ -2489,6 +2492,9 @@ bgp_rte_update_in_notify(struct channel *C, const net_addr *n, bmp_route_monitor_put_update_in_pre_msg(buf, end - buf); } +#endif /* CONFIG_BMP */ + + static byte * bgp_create_update(struct bgp_channel *c, byte *buf) { diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index ff02d3b2..22ee79c3 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -85,6 +85,9 @@ struct bmp_proto { bool started; // Flag that stores running status of BMP instance }; + +#ifdef CONFIG_BMP + /** * 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 @@ -135,4 +138,17 @@ void bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, size_t pkt_size); -#endif /* _BIRD_BMP_H_ */ + +#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) { } + +#endif /* CONFIG_BMP */ + +#endif /* _BIRD_BMP_H_ */ From 010df43519b12e83b0ff2cba9e344cba698586bb Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 18 Apr 2023 18:57:54 +0200 Subject: [PATCH 11/14] BMP: Fix reconfiguration It is not supported, but at least it must update internal config pointer to not keep old one. --- proto/bmp/bmp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 23e250f8..0ef13cd4 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -1131,10 +1131,16 @@ bmp_shutdown(struct proto *P) } static int -bmp_reconfigure(struct proto *P UNUSED, struct proto_config *CF UNUSED) +bmp_reconfigure(struct proto *P, struct proto_config *CF) { + struct bmp_proto *p = (void *) P; + const struct bmp_config *cf = (void *) CF; + log(L_WARN "Reconfiguring BMP is not supported"); - return PS_UP; + + p->cf = cf; + + return 1; } struct protocol proto_bmp = { From 2c7d2141ac86b0d482d3221447d1ad920c557108 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 20 Apr 2023 16:13:58 +0200 Subject: [PATCH 12/14] BMP: Fix connection management Replace broken TCP connection management with a simple state machine. Handle failed attempts properly with a timeout, detect and handle TCP connection close and try to reconnect after that. Remove useless 'station_connected' flag. Keep open messages saved even after the BMP session establishment, so they can be used after BMP session flaps. Use proper log messages for session events. --- proto/bmp/bmp.c | 291 ++++++++++++++++++++++++++---------------------- proto/bmp/bmp.h | 1 - 2 files changed, 158 insertions(+), 134 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 0ef13cd4..36cc30cc 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -20,6 +20,12 @@ * - Support DE_CONFIGURED PEER DOWN REASON code in PEER DOWN NOTIFICATION message * - If connection with BMP collector will lost then we don't establish connection again * - Set Peer Type by its a global and local-scope IP address + * + * 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 + * (any -> Idle), and connect timeout (Idle/Connect -> Connect, resetting the + * TCP socket). */ #include "proto/bmp/bmp.h" @@ -166,8 +172,11 @@ enum bmp_term_reason { // Default chunk size request when memory allocation #define DEFAULT_MEM_BLOCK_SIZE 4096 +// Initial delay for connection to the BMP collector +#define CONNECT_INIT_TIME (200 MS) + // Timeout for connection to the BMP collector retry -#define CONNECT_RETRY_SEC (10 S) +#define CONNECT_RETRY_TIME (10 S) #define IP4_MAX_TTL 255 @@ -188,20 +197,15 @@ enum bmp_term_reason { } while (0) -// Handle BIRD socket error event -static void -bmp_sock_err(sock *sk, int err); +static void bmp_connected(struct birdsock *sk); +static void bmp_sock_err(sock *sk, int err); +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); -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_); - // Stores necessary any data in list struct bmp_data_node { node n; @@ -250,7 +254,7 @@ bmp_init_msg_serialize(buffer *stream, const char *sys_descr, const char *sys_na static void bmp_schedule_tx_packet(struct bmp_proto *p, const byte *payload, const size_t size) { - ASSERT(p->station_connected); + ASSERT(p->started); struct bmp_data_node *tx_data = mb_alloc(p->tx_mem_pool, sizeof (struct bmp_data_node)); tx_data->data = mb_alloc(p->tx_mem_pool, size); @@ -265,23 +269,6 @@ bmp_schedule_tx_packet(struct bmp_proto *p, const byte *payload, const size_t si } } -/** - * bmp_startup - connect to the BMP collector. - * NOTE: Send Initiation Message to the BMP collector. - */ -static void -bmp_startup(struct bmp_proto *p) -{ - ASSERT(p->station_connected && !p->started); - - buffer payload = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); - bmp_init_msg_serialize(&payload, p->sys_descr, p->sys_name); - bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); - bmp_buffer_free(&payload); - - p->started = true; -} - static void bmp_fire_tx(void *p_) { @@ -333,43 +320,13 @@ bmp_tx(struct birdsock *sk) bmp_fire_tx(sk->data); } -static inline int -bmp_open_socket(struct bmp_proto *p) +/* We need RX hook just to accept socket close events */ +static int +bmp_rx(struct birdsock *sk UNUSED, uint size UNUSED) { - sock *s = p->sk; - s->daddr = p->station_ip; - s->dport = p->station_port; - s->err_hook = bmp_sock_err; - - int rc = sk_open(s); - - if (rc < 0) - sk_log_error(s, p->p.name); - - return rc; + return 0; } -static void -bmp_connection_retry(timer *t) -{ - struct bmp_proto *p = t->data; - - if (bmp_open_socket(p) < 0) - { - log(L_DEBUG "Failed to connect to BMP station"); - return; - } - - log(L_DEBUG "Connected to BMP station after connection retry"); - tm_stop(t); -} - -void -bmp_sock_err(sock *sk, int err) -{ - struct bmp_proto *p = sk->data; - log(L_WARN "[BMP:%s] Socket error: %M", p->p.name, err); -} static inline void bmp_put_ipa(buffer *stream, const ip_addr addr) @@ -489,36 +446,13 @@ bmp_peer_down_notif_msg_serialize(buffer *stream, const bool is_peer_global, bmp_put_data(stream, data, data_size); } -/** - * bmp_open - initialize internal resources of BMP implementation. - * NOTE: It does not connect to BMP collector yet. - */ -void -bmp_open(const struct proto *P) -{ - struct bmp_proto *p = (void *) P; - - if (bmp_open_socket(p) < 0) - { - log(L_DEBUG "Failed to connect to BMP station"); - p->connect_retry_timer = tm_new_init(P->pool, bmp_connection_retry, p, - CONNECT_RETRY_SEC, 0 /* not randomized */); - tm_start(p->connect_retry_timer, CONNECT_RETRY_SEC); - p->station_connected = false; - } - else - { - log(L_DEBUG "Connected to BMP station"); - } -} - -void +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_) { struct bmp_proto *p = bmp_; - ASSERT(p->station_connected); + ASSERT(p->started); 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( @@ -630,7 +564,7 @@ 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) { - ASSERT(p->station_connected); + ASSERT(p->started); const struct birdsock *sk = bmp_get_birdsock_ext(bgp); IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( @@ -661,24 +595,19 @@ bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, return; } - struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, - bgp->remote_as); - const struct bmp_peer_map_entry *map_entry + 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); - if (!map_entry || !p->started) - { - bmp_peer_map_insert(&p->peer_open_msg.tx_msg, key, pkt, pkt_size); - if (!map_entry) - { - bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); - } + bmp_peer_map_insert(&p->peer_open_msg.tx_msg, key, pkt, pkt_size); - return; - } + if (!rx_msg) + bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); - bmp_send_peer_up_notif_msg(p, bgp, pkt, pkt_size, map_entry->data.buf, - map_entry->data.buf_size); + 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 @@ -694,22 +623,17 @@ bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - const struct bmp_peer_map_entry *map_data + const struct bmp_peer_map_entry *tx_msg = bmp_peer_map_get(&p->peer_open_msg.tx_msg, key); - if (!map_data || !p->started) - { - bmp_peer_map_insert(&p->peer_open_msg.rx_msg, key, pkt, pkt_size); - if (!map_data) - { - bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); - } + bmp_peer_map_insert(&p->peer_open_msg.rx_msg, key, pkt, pkt_size); - return; - } + if (!tx_msg) + bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); - bmp_send_peer_up_notif_msg(p, bgp, map_data->data.buf, map_data->data.buf_size, - pkt, pkt_size); + 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 @@ -933,7 +857,7 @@ 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) { - ASSERT(p->station_connected); + ASSERT(p->started); const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps_ext(bgp); bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); @@ -1035,36 +959,136 @@ bmp_send_termination_msg(struct bmp_proto *p, bmp_buffer_free(&stream); } +/** + * bmp_startup - enter established state + * @p: BMP instance + * + * The bgp_startup() function is called when the BMP session is established. + * It sends initiation and peer up messagages. + */ static void -bmp_station_connected(struct birdsock *sk) +bmp_startup(struct bmp_proto *p) { - struct bmp_proto *p = (void *) sk->data; + ASSERT(!p->started); + p->started = true; - sk->tx_hook = bmp_tx; - p->station_connected = true; + TRACE(D_EVENTS, "BMP session established"); - bmp_startup(p); + /* 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); + bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); + 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); - bmp_peer_map_flush(&p->peer_open_msg.tx_msg); - bmp_peer_map_flush(&p->peer_open_msg.rx_msg); + + proto_notify_state(&p->p, PS_UP); } -static inline void -bmp_setup_socket(struct bmp_proto *p) +/** + * bmp_down - leave established state + * @p: BMP instance + * + * The bgp_down() function is called when the BMP session fails. + */ +static void +bmp_down(struct bmp_proto *p) { - sock *sk = sk_new(p->tx_mem_pool); + ASSERT(p->started); + p->started = false; + + TRACE(D_EVENTS, "BMP session closed"); + + proto_notify_state(&p->p, PS_START); +} + +/** + * bmp_connect - initiate an outgoing connection + * @p: BMP instance + * + * The bmp_connect() function creates the socket and initiates an outgoing TCP + * connection to the monitoring station. It is called to enter Connect state. + */ +static void +bmp_connect(struct bmp_proto *p) +{ + ASSERT(!p->started); + + sock *sk = sk_new(p->p.pool); sk->type = SK_TCP_ACTIVE; + sk->daddr = p->station_ip; + sk->dport = p->station_port; sk->ttl = IP4_MAX_TTL; sk->tos = IP_PREC_INTERNET_CONTROL; sk->tbsize = BGP_TX_BUFFER_EXT_SIZE; - sk->tx_hook = bmp_station_connected; + sk->tx_hook = bmp_connected; + sk->err_hook = bmp_sock_err; p->sk = sk; sk->data = p; + + int rc = sk_open(sk); + + if (rc < 0) + sk_log_error(sk, p->p.name); + + tm_start(p->connect_retry_timer, CONNECT_RETRY_TIME); } +/* BMP connect successfull event - switch from Connect to Established state */ +static void +bmp_connected(struct birdsock *sk) +{ + struct bmp_proto *p = (void *) sk->data; + + sk->rx_hook = bmp_rx; + sk->tx_hook = bmp_tx; + tm_stop(p->connect_retry_timer); + + bmp_startup(p); +} + +/* BMP socket error event - switch from any state to Idle state */ +static void +bmp_sock_err(sock *sk, int err) +{ + struct bmp_proto *p = sk->data; + + if (err) + TRACE(D_EVENTS, "Connection lost (%M)", err); + else + TRACE(D_EVENTS, "Connection closed"); + + if (p->started) + bmp_down(p); + + bmp_close_socket(p); + tm_start(p->connect_retry_timer, CONNECT_RETRY_TIME); +} + +/* BMP connect timeout event - switch from Idle/Connect state to Connect state */ +static void +bmp_connection_retry(timer *t) +{ + struct bmp_proto *p = t->data; + + if (p->started) + return; + + bmp_close_socket(p); + bmp_connect(p); +} + +static void +bmp_close_socket(struct bmp_proto *p) +{ + rfree(p->sk); + p->sk = NULL; +} + + /** Configuration handle section **/ static struct proto * bmp_init(struct proto_config *CF) @@ -1097,6 +1121,8 @@ bmp_start(struct proto *P) 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->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); @@ -1104,26 +1130,25 @@ bmp_start(struct proto *P) init_list(&p->tx_queue); init_list(&p->rt_table_in_pre_policy.update_msg_queue); - p->station_connected = false; p->started = false; - p->connect_retry_timer = NULL; - bmp_setup_socket(p); - bmp_open(P); + tm_start(p->connect_retry_timer, CONNECT_INIT_TIME); g_bmp = p; - return PS_UP; + return PS_START; } static int bmp_shutdown(struct proto *P) { struct bmp_proto *p = (void *) P; - bmp_send_termination_msg(p, BMP_TERM_REASON_ADM); - p->station_connected = false; - p->started = false; + if (p->started) + { + bmp_send_termination_msg(p, BMP_TERM_REASON_ADM); + p->started = false; + } g_bmp = NULL; diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 22ee79c3..19623e33 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -81,7 +81,6 @@ struct bmp_proto { 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 - bool station_connected; // Flag that stores connection status with BMP station bool started; // Flag that stores running status of BMP instance }; From 976dec048a25fc22efb07fa73be1316c95046420 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 20 Apr 2023 17:14:45 +0200 Subject: [PATCH 13/14] BMP: Silence some log messages Hooks called from BGP to BMP should not log warning when BMP is not connected, that is not an error (and we do not want to flood logs with a ton of messages). Blocked sk_send() should not log warning, that is expected situation. Error during sk_send() is handled in error hook anyway. --- proto/bmp/bmp.c | 47 ++++++++++++++--------------------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 36cc30cc..f04b59b8 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -294,10 +294,9 @@ bmp_fire_tx(void *p_) mb_free(tx_data->data); rem_node((node *) tx_data); mb_free(tx_data); - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - (sk_send(p->sk, data_size) <= 0), - "Failed to send BMP packet" - ); + + if (sk_send(p->sk, data_size) <= 0) + return; // BMP packets should be treat with lowest priority when scheduling sending // packets to target. That's why we want to send max. 32 packets per event @@ -641,7 +640,7 @@ bmp_route_monitor_update_in_pre_begin() { struct bmp_proto *p = g_bmp; - if (!p) + if (!p || !p->started) { return; } @@ -651,11 +650,6 @@ bmp_route_monitor_update_in_pre_begin() return; } - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !p->started, - "BMP instance not started yet" - ); - 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" @@ -672,7 +666,7 @@ bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size { struct bmp_proto *p = g_bmp; - if (!p) + if (!p || !p->started) { return; } @@ -682,11 +676,6 @@ bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size return; } - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !p->started, - "BMP instance not started yet" - ); - 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" @@ -706,7 +695,7 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) { struct bmp_proto *p = g_bmp; - if (!p) + if (!p || !p->started) { return; } @@ -716,11 +705,6 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) return; } - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - (!p->started || EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue)), - "BMP route monitoring update not started yet" - ); - const struct birdsock *sk = bmp_get_birdsock(bgp); IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( sk, @@ -768,7 +752,7 @@ bmp_route_monitor_update_in_pre_end() { struct bmp_proto *p = g_bmp; - if (!p) + if (!p || !p->started) { return; } @@ -778,11 +762,6 @@ bmp_route_monitor_update_in_pre_end() return; } - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - (!p->started || EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue)), - "BMP route monitoring update not started yet" - ); - 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) @@ -791,6 +770,8 @@ bmp_route_monitor_update_in_pre_end() rem_node((node *) upd_msg); mb_free(upd_msg); } + + p->rt_table_in_pre_policy.update_in_progress = false; } static void @@ -878,17 +859,13 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, { struct bmp_proto *p = g_bmp; - if (!p || !p->started) + if (!p) { return; } struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - if (!bmp_peer_map_get(&p->bgp_peers, key)) - { - return; - } bmp_peer_map_remove(&p->peer_open_msg.tx_msg, key); bmp_peer_map_remove(&p->peer_open_msg.rx_msg, key); @@ -896,6 +873,10 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, const size_t missing_bgp_hdr_size = BGP_MSG_HDR_MARKER_SIZE + BGP_MSG_HDR_LENGTH_SIZE + BGP_MSG_HDR_TYPE_SIZE; + + if (!p->started) + return; + buffer payload = bmp_buffer_alloc(p->buffer_mpool, pkt_size + missing_bgp_hdr_size + 1); if (pkt != NULL && pkt_size > 0) From f3b599afe5bde0c7f232421743041b305bb8afa7 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 21 Apr 2023 04:42:13 +0200 Subject: [PATCH 14/14] BMP: Add some basic documentation --- doc/bird.sgml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/doc/bird.sgml b/doc/bird.sgml index 557140b8..39eae4cd 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -3268,6 +3268,35 @@ protocol bgp { +BMP +