0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 12:18:42 +00:00

Merge branch 'bmp'

This commit is contained in:
Ondrej Zajicek 2023-04-21 04:47:55 +02:00
commit 52450bc96d
20 changed files with 1951 additions and 11 deletions

View File

@ -323,6 +323,7 @@ fi
AH_TEMPLATE([CONFIG_BABEL], [Babel protocol]) AH_TEMPLATE([CONFIG_BABEL], [Babel protocol])
AH_TEMPLATE([CONFIG_BFD], [BFD protocol]) AH_TEMPLATE([CONFIG_BFD], [BFD protocol])
AH_TEMPLATE([CONFIG_BGP], [BGP protocol]) AH_TEMPLATE([CONFIG_BGP], [BGP protocol])
AH_TEMPLATE([CONFIG_BMP], [BMP protocol])
AH_TEMPLATE([CONFIG_MRT], [MRT protocol]) AH_TEMPLATE([CONFIG_MRT], [MRT protocol])
AH_TEMPLATE([CONFIG_OSPF], [OSPF protocol]) AH_TEMPLATE([CONFIG_OSPF], [OSPF protocol])
AH_TEMPLATE([CONFIG_PIPE], [Pipe protocol]) AH_TEMPLATE([CONFIG_PIPE], [Pipe protocol])

View File

@ -3268,6 +3268,35 @@ protocol bgp {
</code> </code>
<sect>BMP
<label id="bmp">
<p>The BGP Monitoring Protocol is used for monitoring BGP sessions and obtaining
routing table data. The current implementation in BIRD is a preliminary release
with a limited feature set, it will be subject to significant changes in the
future. It is not ready for production usage and therefore it is not compiled
by default and have to be enabled during installation by the configure option
<tt/--with-protocols=/.
<p>The implementation is limited to monitor protocol state changes and routes
in <ref id="bgp-import-table" name="BGP import tables"> (not regular routing
tables), therefore import table must be enabled in BGP protocols. All BGP
protocols are monitored automatically.
<sect1>Example
<label id="bmp-exam">
<p><code>
protocol bmp {
# The monitoring station to connect to
station address ip 198.51.100.10 port 1790;
# required option
monitoring rib in pre_policy;
}
</code>
<sect>Device <sect>Device
<label id="device"> <label id="device">

View File

@ -42,6 +42,7 @@ enum protocol_class {
PROTOCOL_BABEL, PROTOCOL_BABEL,
PROTOCOL_BFD, PROTOCOL_BFD,
PROTOCOL_BGP, PROTOCOL_BGP,
PROTOCOL_BMP,
PROTOCOL_DEVICE, PROTOCOL_DEVICE,
PROTOCOL_DIRECT, PROTOCOL_DIRECT,
PROTOCOL_KERNEL, PROTOCOL_KERNEL,
@ -103,7 +104,7 @@ void protos_dump_all(void);
extern struct protocol extern struct protocol
proto_device, proto_radv, proto_rip, proto_static, proto_mrt, proto_device, proto_radv, proto_rip, proto_static, proto_mrt,
proto_ospf, proto_perf, 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 * Routing Protocol Instance
@ -213,6 +214,7 @@ struct proto {
void (*if_notify)(struct proto *, unsigned flags, struct iface *i); void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a); 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 (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old);
void (*rte_update_in_notify)(struct channel *, const net_addr *, const struct rte *, const struct rte_src *);
void (*neigh_notify)(struct neighbor *neigh); void (*neigh_notify)(struct neighbor *neigh);
int (*preexport)(struct channel *, struct rte *rt); int (*preexport)(struct channel *, struct rte *rt);
void (*reload_routes)(struct channel *); void (*reload_routes)(struct channel *);

View File

@ -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)) if (old->flags & (REF_STALE | REF_DISCARD | REF_MODIFY))
{ {
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, n, old, src);
return 1; return 1;
} }
@ -3121,6 +3125,9 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
if (!net->routes) if (!net->routes)
fib_delete(&tab->fib, net); fib_delete(&tab->fib, net);
if (c->proto->rte_update_in_notify)
c->proto->rte_update_in_notify(c, n, NULL, src);
return 1; return 1;
} }
@ -3149,6 +3156,10 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
e->next = *pos; e->next = *pos;
*pos = e; *pos = e;
tab->rt_count++; tab->rt_count++;
if (c->proto->rte_update_in_notify)
c->proto->rte_update_in_notify(c, n, e, src);
return 1; return 1;
drop_update: drop_update:

View File

@ -2,6 +2,7 @@ H Protocols
C babel C babel
C bfd C bfd
C bgp C bgp
C bmp
C ospf C ospf
C pipe C pipe
C radv C radv

View File

@ -1151,6 +1151,13 @@ bgp_attr_known(uint code)
return (code < ARRAY_SIZE(bgp_attr_table)) && bgp_attr_table[code].name; 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 * Attribute export

View File

@ -125,6 +125,7 @@
#include "lib/string.h" #include "lib/string.h"
#include "bgp.h" #include "bgp.h"
#include "proto/bmp/bmp.h"
static list STATIC_LIST_INIT(bgp_sockets); /* Global list of listening sockets */ static list STATIC_LIST_INIT(bgp_sockets); /* Global list of listening sockets */
@ -866,7 +867,10 @@ bgp_graceful_restart_timeout(timer *t)
} }
} }
else else
{
bgp_stop(p, 0, NULL, 0); bgp_stop(p, 0, NULL, 0);
bmp_peer_down(p, BE_NONE, NULL, 0);
}
} }
static void static void
@ -990,7 +994,10 @@ bgp_sock_err(sock *sk, int err)
if (err) if (err)
BGP_TRACE(D_EVENTS, "Connection lost (%M)", err); BGP_TRACE(D_EVENTS, "Connection lost (%M)", err);
else else
{
BGP_TRACE(D_EVENTS, "Connection closed"); BGP_TRACE(D_EVENTS, "Connection closed");
bmp_peer_down(p, BE_SOCKET, NULL, 0);
}
if ((conn->state == BS_ESTABLISHED) && p->gr_ready) if ((conn->state == BS_ESTABLISHED) && p->gr_ready)
bgp_handle_graceful_restart(p); bgp_handle_graceful_restart(p);
@ -1315,6 +1322,7 @@ bgp_neigh_notify(neighbor *n)
bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST); bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST);
/* Perhaps also run bgp_update_startup_delay(p)? */ /* Perhaps also run bgp_update_startup_delay(p)? */
bgp_stop(p, 0, NULL, 0); bgp_stop(p, 0, NULL, 0);
bmp_peer_down(p, BE_MISC, NULL, 0);
} }
} }
else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP)) 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) if (ps == PS_UP)
bgp_update_startup_delay(p); bgp_update_startup_delay(p);
bgp_stop(p, 0, NULL, 0); bgp_stop(p, 0, NULL, 0);
bmp_peer_down(p, BE_MISC, NULL, 0);
} }
} }
else else
@ -1367,6 +1376,7 @@ bgp_bfd_notify(struct bfd_request *req)
if (ps == PS_UP) if (ps == PS_UP)
bgp_update_startup_delay(p); bgp_update_startup_delay(p);
bgp_stop(p, 0, NULL, 0); bgp_stop(p, 0, NULL, 0);
bmp_peer_down(p, BE_MISC, NULL, 0);
} }
} }
} }
@ -1695,6 +1705,10 @@ bgp_init(struct proto_config *CF)
P->rte_modify = bgp_rte_modify_stale; P->rte_modify = bgp_rte_modify_stale;
P->rte_igp_metric = bgp_rte_igp_metric; 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->cf = cf;
p->is_internal = (cf->local_as == cf->remote_as); p->is_internal = (cf->local_as == cf->remote_as);
p->is_interior = p->is_internal || cf->confederation_member; p->is_interior = p->is_internal || cf->confederation_member;

View File

@ -434,6 +434,7 @@ struct bgp_write_state {
int as4_session; int as4_session;
int add_path; int add_path;
int mpls; int mpls;
int sham;
eattr *mp_next_hop; eattr *mp_next_hop;
const adata *mpls_labels; const adata *mpls_labels;
@ -496,6 +497,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_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_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) static inline int bgp_channel_is_ipv4(struct bgp_channel *c)
{ return BGP_AFI(c->afi) == BGP_AFI_IPV4; } { return BGP_AFI(c->afi) == BGP_AFI_IPV4; }
@ -542,6 +550,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); void bgp_stop(struct bgp_proto *p, int subcode, byte *data, uint len);
const char *bgp_format_role_name(u8 role); const char *bgp_format_role_name(u8 role);
void bgp_fix_attr_flags(ea_list *attrs);
static inline int static inline int
rte_resolvable(rte *rt) rte_resolvable(rte *rt)
{ {
@ -615,6 +625,7 @@ struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
u32 bgp_rte_igp_metric(struct rte *); u32 bgp_rte_igp_metric(struct rte *);
void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old); void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old);
int bgp_preexport(struct channel *, struct rte *); int bgp_preexport(struct channel *, struct rte *);
void bgp_rte_update_in_notify(struct channel *C, const net_addr *n, const struct rte *new, const struct rte_src *src);
int bgp_get_attr(const struct eattr *e, byte *buf, int buflen); int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
void bgp_get_route_info(struct rte *, byte *buf); void bgp_get_route_info(struct rte *, byte *buf);
int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad); int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad);
@ -648,6 +659,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); 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 */ /* Packet types */

View File

@ -26,6 +26,7 @@
#include "nest/cli.h" #include "nest/cli.h"
#include "bgp.h" #include "bgp.h"
#include "proto/bmp/bmp.h"
#define BGP_RR_REQUEST 0 #define BGP_RR_REQUEST 0
@ -166,6 +167,7 @@ bgp_create_notification(struct bgp_conn *conn, byte *buf)
buf[0] = conn->notify_code; buf[0] = conn->notify_code;
buf[1] = conn->notify_subcode; buf[1] = conn->notify_subcode;
memcpy(buf+2, conn->notify_data, conn->notify_size); 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; 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_schedule_packet(conn, NULL, PKT_KEEPALIVE);
bgp_start_timer(conn->hold_timer, conn->hold_time); bgp_start_timer(conn->hold_timer, conn->hold_time);
bgp_conn_enter_openconfirm_state(conn); bgp_conn_enter_openconfirm_state(conn);
bmp_put_recv_bgp_open_msg(p, pkt, len);
} }
@ -1563,7 +1566,10 @@ bgp_encode_nlri_ip4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
memcpy(pos, &a, b); memcpy(pos, &a, b);
ADVANCE(pos, size, 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; return pos - buf;
@ -1648,7 +1654,10 @@ bgp_encode_nlri_ip6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
memcpy(pos, &a, b); memcpy(pos, &a, b);
ADVANCE(pos, size, 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; return pos - buf;
@ -1736,7 +1745,10 @@ bgp_encode_nlri_vpn4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b
memcpy(pos, &a, b); memcpy(pos, &a, b);
ADVANCE(pos, size, 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; return pos - buf;
@ -1833,7 +1845,10 @@ bgp_encode_nlri_vpn6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b
memcpy(pos, &a, b); memcpy(pos, &a, b);
ADVANCE(pos, size, 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; return pos - buf;
@ -1920,7 +1935,10 @@ bgp_encode_nlri_flow4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *
memcpy(pos, net->data, flen); memcpy(pos, net->data, flen);
ADVANCE(pos, size, 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; return pos - buf;
@ -2012,7 +2030,10 @@ bgp_encode_nlri_flow6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *
memcpy(pos, net->data, flen); memcpy(pos, net->data, flen);
ADVANCE(pos, size, 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; return pos - buf;
@ -2256,7 +2277,8 @@ bgp_create_ip_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
if (la < 0) if (la < 0)
{ {
/* Attribute list too long */ /* Attribute list too long */
bgp_withdraw_bucket(s->channel, buck); if (!s->sham)
bgp_withdraw_bucket(s->channel, buck);
return NULL; return NULL;
} }
@ -2303,7 +2325,8 @@ bgp_create_mp_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
if (la < 0) if (la < 0)
{ {
/* Attribute list too long */ /* Attribute list too long */
bgp_withdraw_bucket(s->channel, buck); if (!s->sham)
bgp_withdraw_bucket(s->channel, buck);
return NULL; return NULL;
} }
@ -2384,6 +2407,94 @@ bgp_create_mp_unreach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *
return buf+11+len; 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)
{
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);
struct bgp_write_state s = {
.proto = p,
.channel = c,
.pool = tmp_linpool,
.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,
};
if (!update)
{
return !s.mp_reach ?
bgp_create_ip_unreach(&s, buck, buf, end):
bgp_create_mp_unreach(&s, buck, buf, end);
}
else
{
return !s.mp_reach ?
bgp_create_ip_reach(&s, buck, buf, end):
bgp_create_mp_reach(&s, buck, buf, end);
}
}
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);
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);
}
#endif /* CONFIG_BMP */
static byte * static byte *
bgp_create_update(struct bgp_channel *c, byte *buf) bgp_create_update(struct bgp_channel *c, byte *buf)
{ {
@ -2484,7 +2595,7 @@ bgp_create_mp_end_mark(struct bgp_channel *c, byte *buf)
return buf+10; return buf+10;
} }
static byte * byte *
bgp_create_end_mark(struct bgp_channel *c, byte *buf) bgp_create_end_mark(struct bgp_channel *c, byte *buf)
{ {
struct bgp_proto *p = (void *) c->c.proto; struct bgp_proto *p = (void *) c->c.proto;
@ -2635,6 +2746,7 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
s.ip_reach_len = len - pos; s.ip_reach_len = len - pos;
s.ip_reach_nlri = pkt + pos; s.ip_reach_nlri = pkt + pos;
bmp_route_monitor_update_in_pre_begin();
if (s.attr_len) if (s.attr_len)
ea = bgp_decode_attrs(&s, s.attrs, s.attr_len); ea = bgp_decode_attrs(&s, s.attrs, s.attr_len);
@ -2666,6 +2778,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, 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); 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: done:
rta_free(s.cached_rta); rta_free(s.cached_rta);
lp_restore(tmp_linpool, &tmpp); lp_restore(tmp_linpool, &tmpp);
@ -2917,7 +3032,12 @@ bgp_fire_tx(struct bgp_conn *conn)
{ {
conn->packets_to_send &= ~(1 << PKT_OPEN); conn->packets_to_send &= ~(1 << PKT_OPEN);
end = bgp_create_open(conn, pkt); 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)) else if (s & (1 << PKT_KEEPALIVE))
{ {
@ -3216,6 +3336,8 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len)
p->p.disabled = 1; p->p.disabled = 1;
} }
} }
bmp_peer_down(p, BE_NONE, pkt, len);
} }
static void static void

1
proto/bmp/Doc Normal file
View File

@ -0,0 +1 @@
S bmp.c

2
proto/bmp/LICENSE Normal file
View File

@ -0,0 +1,2 @@
The patch is provided under the terms of the GNU General Public License, either
version 2, or any later version.

6
proto/bmp/Makefile Normal file
View File

@ -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)

6
proto/bmp/README.txt Normal file
View File

@ -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.

1168
proto/bmp/bmp.c Normal file

File diff suppressed because it is too large Load Diff

153
proto/bmp/bmp.h Normal file
View File

@ -0,0 +1,153 @@
/*
* 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 <stdbool.h>
// Max length of MIB-II description object
#define MIB_II_STR_LEN 255
// 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;
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 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;
// 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
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
u16 station_port; // Monitoring station TCP port
struct monitoring_rib monitoring_rib;
// Below fields are for internal use
struct bmp_peer_map bgp_peers; // Stores 'bgp_proto' structure per BGP peer
struct bmp_peer_open_msg peer_open_msg; // Stores sent and received BGP OPEN MSG per BGP peer
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 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
* 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);
#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_ */

58
proto/bmp/buffer.c Normal file
View File

@ -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;
}

77
proto/bmp/buffer.h Normal file
View File

@ -0,0 +1,77 @@
/*
* 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 <stdlib.h>
#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_ */

83
proto/bmp/config.Y Normal file
View File

@ -0,0 +1,83 @@
/*
* 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->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 (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 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;
}
;
CF_CODE
CF_END

119
proto/bmp/map.c Normal file
View File

@ -0,0 +1,119 @@
/*
* BIRD -- The BGP Monitoring Protocol (BMP)
*
* (c) 2020 Akamai Technologies, Inc. (Pawel Maslanka, pmaslank@akamai.com)
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "proto/bmp/map.h"
/* Peer Index Table */
#define PEER_KEY(n) (n)->peer_as, (n)->peer_ip
#define PEER_NEXT(n) (n)->next
#define PEER_EQ(as1,ip1,as2,ip2) \
(as1) == (as2) && ipa_equal(ip1, ip2)
#define PEER_FN(as,ip) ipa_hash(ip)
#define PEER_REHASH bmp_peer_rehash
#define PEER_PARAMS /8, *2, 2, 2, 6, 20
HASH_DEFINE_REHASH_FN(PEER, struct bmp_peer_map_key)
#define PEER_INIT_ORDER 6
void
bmp_peer_map_init(struct bmp_peer_map *map, pool *mpool)
{
map->mpool = mpool;
HASH_INIT(map->peer_hash, map->mpool, PEER_INIT_ORDER);
}
struct bmp_peer_map_key
bmp_peer_map_key_create(const ip_addr peer_ip, const u32 peer_as)
{
struct bmp_peer_map_key key;
key.next = NULL;
key.peer_ip = peer_ip;
key.peer_as = peer_as;
return key;
}
void
bmp_peer_map_flush(struct bmp_peer_map *map)
{
struct bmp_peer_map_entry *entry;
HASH_WALK_DELSAFE(map->peer_hash, next, e)
{
entry = (struct bmp_peer_map_entry *) e;
mb_free(entry->data.buf);
HASH_DELETE(map->peer_hash, PEER, PEER_KEY(&entry->key));
mb_free(entry);
}
HASH_WALK_DELSAFE_END;
HASH_MAY_RESIZE_DOWN(map->peer_hash, PEER, map->mpool);
}
void
bmp_peer_map_free(struct bmp_peer_map *map)
{
bmp_peer_map_flush(map);
HASH_FREE(map->peer_hash);
}
void
bmp_peer_map_insert(struct bmp_peer_map *map, const struct bmp_peer_map_key key,
const byte *data, const size_t data_size)
{
struct bmp_peer_map_entry *entry
= (void *) HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key));
if (entry)
{
mb_free(entry->data.buf);
entry->data.buf = mb_alloc(map->mpool, data_size);
memcpy(entry->data.buf, data, data_size);
entry->data.buf_size = data_size;
return;
}
entry = mb_alloc(map->mpool, sizeof (struct bmp_peer_map_entry));
entry->data.buf = mb_alloc(map->mpool, data_size);
memcpy(entry->data.buf, data, data_size);
entry->data.buf_size = data_size;
entry->key = key;
HASH_INSERT2(map->peer_hash, PEER, map->mpool, &entry->key);
}
void
bmp_peer_map_remove(struct bmp_peer_map *map, const struct bmp_peer_map_key key)
{
struct bmp_peer_map_entry *entry
= (void *) HASH_DELETE(map->peer_hash, PEER, PEER_KEY(&key));
if (!entry)
return;
mb_free(entry->data.buf);
mb_free(entry);
}
const struct bmp_peer_map_entry *
bmp_peer_map_get(struct bmp_peer_map *map, const struct bmp_peer_map_key key)
{
return (struct bmp_peer_map_entry *) HASH_FIND(map->peer_hash, PEER, PEER_KEY(&key));
}
void
bmp_peer_map_walk(const struct bmp_peer_map *map, bmp_peer_map_walk_action action, void *arg)
{
struct bmp_peer_map_entry *entry;
HASH_WALK_FILTER(map->peer_hash, next, e, _)
{
entry = (struct bmp_peer_map_entry *) e;
action(entry->key, entry->data.buf, entry->data.buf_size, arg);
}
HASH_WALK_FILTER_END;
}

68
proto/bmp/map.h Normal file
View File

@ -0,0 +1,68 @@
/*
* BIRD -- The BGP Monitoring Protocol (BMP)
*
* (c) 2020 Akamai Technologies, Inc. (Pawel Maslanka, pmaslank@akamai.com)
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
/**
* This map implementation binds peer IP address as container key with custom data.
*/
#ifndef _BIRD_BMP_MAP_H_
#define _BIRD_BMP_MAP_H_
#include "nest/bird.h"
#include "lib/hash.h"
#include "lib/resource.h"
struct bmp_peer_map_key {
struct bmp_peer_map_key *next;
ip_addr peer_ip;
u32 peer_as;
};
struct bmp_peer_map_data {
void *buf;
size_t buf_size;
};
struct bmp_peer_map_entry {
struct bmp_peer_map_key key;
struct bmp_peer_map_data data;
};
struct bmp_peer_map {
pool *mpool; // Memory pool for peer entries in peer_hash
HASH(struct bmp_peer_map_key) peer_hash; // Hash for peers to find the index
};
void
bmp_peer_map_init(struct bmp_peer_map *map, pool *mpool);
struct bmp_peer_map_key
bmp_peer_map_key_create(const ip_addr peer_ip, const u32 peer_as);
void
bmp_peer_map_free(struct bmp_peer_map *map);
void
bmp_peer_map_flush(struct bmp_peer_map *map);
void
bmp_peer_map_insert(struct bmp_peer_map *map, const struct bmp_peer_map_key key,
const byte *data, const size_t data_size);
void
bmp_peer_map_remove(struct bmp_peer_map *map, const struct bmp_peer_map_key key);
const struct bmp_peer_map_entry *
bmp_peer_map_get(struct bmp_peer_map *map, const struct bmp_peer_map_key key);
typedef void (*bmp_peer_map_walk_action)(const struct bmp_peer_map_key key,
const byte *data, const size_t data_size, void *arg);
void
bmp_peer_map_walk(const struct bmp_peer_map *map, bmp_peer_map_walk_action action, void *arg);
#endif /* _BIRD_BMP_MAP_H_ */