summaryrefslogtreecommitdiff
path: root/proto/bmp/bmp.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2023-08-22 01:24:21 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2023-08-22 01:26:06 +0200
commit4558adabfbbe3696156d20767168010d6238f434 (patch)
tree43f17ffb951f75cb3dc70401b98a422dada87b8b /proto/bmp/bmp.c
parent52641e086675832e9f43f86237b0cddbd5ec551e (diff)
BMP: Improve peer_down handling
Move all bmp_peer_down() calls to one place and make it synchronous with BGP session down, ensuring that BMP receives peer_down before route withdraws from flushing. Also refactor bmp_peer_down_() message generating code.
Diffstat (limited to 'proto/bmp/bmp.c')
-rw-r--r--proto/bmp/bmp.c69
1 files changed, 44 insertions, 25 deletions
diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c
index 22b9f2fb..261e9fdd 100644
--- a/proto/bmp/bmp.c
+++ b/proto/bmp/bmp.c
@@ -888,7 +888,7 @@ bmp_send_peer_down_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp,
static void
bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp,
- const int err_class, const byte *msg, size_t msg_length)
+ int err_class, int err_code, int err_subcode, const byte *data, int length)
{
if (!p->started)
return;
@@ -899,31 +899,43 @@ bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp,
TRACE(D_STATES, "Peer down for %s", bgp->p.name);
- buffer payload = bmp_buffer_alloc(p->buffer_mpool, 1 + BGP_HEADER_LENGTH + msg_length);
+ uint bmp_code = 0;
+ uint fsm_code = 0;
- if (msg)
+ switch (err_class)
{
- if (err_class == BE_BGP_TX)
- bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION);
- else
- bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION);
-
- bmp_put_bgp_hdr(&payload, BGP_HEADER_LENGTH + msg_length, PKT_NOTIFICATION);
- bmp_put_data(&payload, msg, msg_length);
+ case BE_BGP_RX:
+ bmp_code = BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION;
+ break;
+
+ case BE_BGP_TX:
+ case BE_AUTO_DOWN:
+ case BE_MAN_DOWN:
+ bmp_code = BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION;
+ break;
+
+ default:
+ bmp_code = BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION;
+ length = 0;
+ break;
}
- else
+
+ buffer payload = bmp_buffer_alloc(p->buffer_mpool, 1 + BGP_HEADER_LENGTH + 2 + length);
+ bmp_put_u8(&payload, bmp_code);
+
+ switch (bmp_code)
{
- // TODO: Handle De-configured Peer Down Reason Code
- if (err_class == BE_SOCKET || err_class == BE_MISC)
- {
- bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION);
- }
- else
- {
- bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION);
- // TODO: Fill in with appropriate FSM event code
- bmp_put_u16(&payload, 0x00); // no relevant Event code is defined
- }
+ case BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION:
+ case BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION:
+ bmp_put_bgp_hdr(&payload, BGP_HEADER_LENGTH + 2 + length, PKT_NOTIFICATION);
+ bmp_put_u8(&payload, err_code);
+ bmp_put_u8(&payload, err_subcode);
+ bmp_put_data(&payload, data, length);
+ break;
+
+ case BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION:
+ bmp_put_u16(&payload, fsm_code);
+ break;
}
bmp_send_peer_down_notif_msg(p, bgp, bmp_buffer_data(&payload), bmp_buffer_pos(&payload));
@@ -934,12 +946,12 @@ bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp,
}
void
-bmp_peer_down(const struct bgp_proto *bgp, const int err_class,
- const byte *msg, size_t msg_length)
+bmp_peer_down(const struct bgp_proto *bgp,
+ int err_class, int code, int subcode, const byte *data, int length)
{
struct bmp_proto *p; node *n;
WALK_LIST2(p, n, bmp_proto_list, bmp_node)
- bmp_peer_down_(p, bgp, err_class, msg, msg_length);
+ bmp_peer_down_(p, bgp, err_class, code, subcode, data, length);
}
static void
@@ -988,6 +1000,13 @@ bmp_rt_notify(struct proto *P, struct channel *c, struct network *net,
struct bgp_proto *bgp = (void *) src->c.proto;
bool policy = (c->table == src->c.table);
+ /*
+ * We assume that we receive peer_up before the first route and peer_down
+ * synchronously with BGP session close. So if bmp_stream exists, the related
+ * BGP session is up and could be accessed. That may not be true in
+ * multithreaded setup.
+ */
+
struct bmp_stream *bs = bmp_find_stream(p, bgp, src->afi, policy);
if (!bs)
return;