From c0319183a50c8fd07d9febae9f866fc6f0675b31 Mon Sep 17 00:00:00 2001 From: Katerina Kubecova Date: Fri, 11 Oct 2024 12:38:18 +0200 Subject: [PATCH] BGP: exporting protocol-specific state information --- proto/bgp/attrs.c | 106 +++++++++++++++++++++++++++++++++- proto/bgp/bgp.c | 137 +++++++++++++++++++++++++++++++++++++++++--- proto/bgp/bgp.h | 25 +++++++- proto/bgp/packets.c | 35 +++++++++++ 4 files changed, 292 insertions(+), 11 deletions(-) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 3951b25f..d293a71b 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1215,6 +1215,79 @@ bgp_find_attr(ea_list *attrs, uint code) return ea_find(attrs, BGP_EA_ID(code)); } +struct ea_class ea_bgp_rem_id = { + .name = "proto_bgp_rem_id", + .type = T_INT, +}; + +struct ea_class ea_bgp_rem_as = { + .name = "proto_bgp_rem_as", + .type = T_INT, +}; + +struct ea_class ea_bgp_loc_as = { + .name = "proto_bgp_loc_as", + .type = T_INT, +}; + +struct ea_class ea_bgp_rem_ip = { + .name = "proto_bgp_rem_ip", + .type = T_IP, +}; + +struct ea_class ea_bgp_afi = { + .name = "bgp_afi", + .type = T_INT, +}; + +struct ea_class ea_bgp_peer_type = { + .name = "bgp_peer_type", + .type = T_INT, +}; + +/* + * Protocol connections information + */ + +struct ea_class ea_bgp_in_conn_local_open_msg = { + .name = "bgp_in_conn_local_open_msg", + .type = T_BYTESTRING, +}; + +struct ea_class ea_bgp_in_conn_remote_open_msg = { + .name = "bgp_in_conn_remote_open_msg", + .type = T_BYTESTRING, +}; + +struct ea_class ea_bgp_out_conn_local_open_msg = { + .name = "bgp_out_conn_local_open_msg", + .type = T_BYTESTRING, +}; + +struct ea_class ea_bgp_out_conn_remote_open_msg = { + .name = "bgp_out_conn_remote_open_msg", + .type = T_BYTESTRING, +}; + +struct ea_class ea_bgp_in_conn_state = { + .name = "bgp_in_conn_state", + .type = T_INT, +}; + +struct ea_class ea_bgp_out_conn_state = { + .name = "bgp_out_conn_state", + .type = T_INT, +}; + +struct ea_class ea_bgp_in_conn_sk = { + .name = "bgp_in_conn_sk", + .type = T_OPAQUE, +}; + +struct ea_class ea_bgp_out_conn_sk = { + .name = "bgp_out_conn_sk", + .type = T_OPAQUE, +}; /* * Protocol extended state information @@ -1225,6 +1298,31 @@ struct ea_class ea_bgp_state_startup = { .type = T_INT, }; +struct ea_class ea_bgp_close_bmp = { + .name = "bgp_close_bmp", + .type = T_OPAQUE, +}; + +struct ea_class ea_bgp_close_bmp_set = { + .name = "bgp_close_bmp_set", + .type = T_INT, +}; + +struct ea_class ea_bgp_as4_session = { + .name = "bgp_as4_session", + .type = T_INT, +}; + +struct ea_class ea_bgp_as4_in_conn = { + .name = "bgp_as4_in_conn", + .type = T_INT, +}; + +struct ea_class ea_bgp_as4_out_conn = { + .name = "bgp_as4_out_conn", + .type = T_INT, +}; + void bgp_register_attrs(void) { @@ -1246,7 +1344,11 @@ bgp_register_attrs(void) } EA_REGISTER_ALL( - &ea_bgp_state_startup + &ea_bgp_rem_id, &ea_bgp_rem_as, &ea_bgp_loc_as, &ea_bgp_rem_ip, &ea_bgp_peer_type, &ea_bgp_afi, + &ea_bgp_in_conn_local_open_msg, &ea_bgp_out_conn_local_open_msg, &ea_bgp_in_conn_remote_open_msg, + &ea_bgp_out_conn_remote_open_msg, &ea_bgp_close_bmp, &ea_bgp_close_bmp_set, &ea_bgp_as4_session, + &ea_bgp_state_startup, &ea_bgp_in_conn_state, &ea_bgp_out_conn_state, + &ea_bgp_in_conn_sk, &ea_bgp_out_conn_sk, &ea_bgp_as4_in_conn, &ea_bgp_as4_out_conn ); } @@ -1892,7 +1994,7 @@ bgp_tx_resend(struct bgp_proto *p, struct bgp_channel *bc) */ static void -bgp_out_item_done(struct lfjour *j, struct lfjour_item *i) +bgp_out_item_done(struct lfjour *j UNUSED, struct lfjour_item *i UNUSED) {} static struct rt_export_feed * diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index be3f643f..1a284df8 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -486,6 +486,23 @@ bgp_close_conn(struct bgp_conn *conn) conn->local_open_length = 0; conn->remote_open_length = 0; + ea_list *attr = conn->bgp->p.ea_state; + if (conn == &conn->bgp->incoming_conn) + { + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_in_conn_local_open_msg, 0, NULL, 0)); + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_in_conn_remote_open_msg, 0, NULL, 0)); + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_in_conn_sk, 0, NULL, 0)); + } + else + { + ASSERT_DIE(conn == &conn->bgp->outgoing_conn); + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_out_conn_local_open_msg, 0, NULL, 0)); + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_out_conn_remote_open_msg, 0, NULL, 0)); + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_out_conn_sk, 0, NULL, 0)); + } + conn->bgp->p.ea_state = ea_lookup(conn->bgp->p.ea_state, 0, EALS_CUSTOM); + proto_announce_state_later(&conn->bgp->p, attr); + mb_free(conn->local_caps); conn->local_caps = NULL; mb_free(conn->remote_caps); @@ -640,6 +657,16 @@ bgp_conn_set_state(struct bgp_conn *conn, uint new_state) bgp_dump_state_change(conn, conn->state, new_state); conn->state = new_state; + + if (conn == &conn->bgp->incoming_conn) + ea_set_attr(&conn->bgp->p.ea_state, EA_LITERAL_EMBEDDED(&ea_bgp_in_conn_state, 0, new_state)); + else + { + ASSERT_DIE(conn == &conn->bgp->outgoing_conn); + ea_set_attr(&conn->bgp->p.ea_state, EA_LITERAL_EMBEDDED(&ea_bgp_out_conn_state, 0, new_state)); + } + conn->bgp->p.ea_state = ea_lookup(conn->bgp->p.ea_state, 0, EALS_CUSTOM); + proto_announce_state_later(&conn->bgp->p, conn->bgp->p.ea_state); } void @@ -680,6 +707,9 @@ bgp_conn_enter_established_state(struct bgp_conn *conn) p->last_error_code = 0; p->as4_session = conn->as4_session; + ea_set_attr(&p->p.ea_state, EA_LITERAL_EMBEDDED(&ea_bgp_as4_session, 0, conn->as4_session)); + p->p.ea_state = ea_lookup(p->p.ea_state, 0, EALS_CUSTOM); + proto_announce_state_later(&conn->bgp->p, conn->bgp->p.ea_state); p->route_refresh = peer->route_refresh; p->enhanced_refresh = local->enhanced_refresh && peer->enhanced_refresh; @@ -791,11 +821,6 @@ bgp_conn_enter_established_state(struct bgp_conn *conn) bgp_conn_set_state(conn, BS_ESTABLISHED); proto_notify_state(&p->p, PS_UP); - -#ifdef CONFIG_BMP - bmp_peer_up(p, conn->local_open_msg, conn->local_open_length, - conn->remote_open_msg, conn->remote_open_length); -#endif } static void @@ -809,9 +834,28 @@ bgp_conn_leave_established_state(struct bgp_conn *conn, struct bgp_proto *p) bgp_stop(p, 0, NULL, 0); #ifdef CONFIG_BMP - bmp_peer_down(p, p->last_error_class, - conn->notify_code, conn->notify_subcode, - conn->notify_data, conn->notify_size); + struct { + struct closing_bgp closing_struct; + byte data[conn->notify_size]; + } to_ea; + + to_ea.closing_struct = (struct closing_bgp) { + .err_class = p->last_error_class, + .err_code = conn->notify_code, + .err_subcode = conn->notify_subcode, + .length = conn->notify_size, + }; + memcpy(to_ea.data, conn->notify_data, conn->notify_size); + + ea_set_attr(&p->p.ea_state, EA_LITERAL_STORE_ADATA(&ea_bgp_close_bmp, 0, &to_ea.closing_struct, sizeof(to_ea))); + ea_set_attr(&p->p.ea_state, EA_LITERAL_EMBEDDED(&ea_bgp_close_bmp_set, 0, 1)); + p->p.ea_state = ea_lookup(p->p.ea_state, 0, EALS_CUSTOM); + + proto_announce_state_later(&p->p, p->p.ea_state); + + //bmp_peer_down(p, p->last_error_class, + // conn->notify_code, conn->notify_subcode, + // conn->notify_data, conn->notify_size); #endif } @@ -1205,6 +1249,17 @@ bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn) conn->hold_timer = tm_new_init(p->p.pool, bgp_hold_timeout, conn, 0, 0); conn->keepalive_timer = tm_new_init(p->p.pool, bgp_keepalive_timeout, conn, 0, 0); conn->send_hold_timer = tm_new_init(p->p.pool, bgp_send_hold_timeout, conn, 0, 0); + + ea_list *attr = conn->bgp->p.ea_state; + if (conn == &conn->bgp->incoming_conn) + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_in_conn_sk, 0, NULL, 0)); + else + { + ASSERT_DIE(conn == &conn->bgp->outgoing_conn); + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_out_conn_sk, 0, NULL, 0)); + } + conn->bgp->p.ea_state = ea_lookup(conn->bgp->p.ea_state, 0, EALS_CUSTOM); + proto_announce_state_later(&p->p, attr); } static void @@ -1214,6 +1269,24 @@ bgp_setup_sk(struct bgp_conn *conn, sock *s) s->err_hook = bgp_sock_err; s->fast_rx = 1; conn->sk = s; + + struct bgp_conn_sk_ea sk_ea = { + .saddr = s->saddr, + .daddr = s->daddr, + .sport = s->sport, + .dport = s->dport + }; + + ea_list *attr = conn->bgp->p.ea_state; + if (conn == &conn->bgp->incoming_conn) + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_in_conn_sk, 0, (byte*)(&sk_ea), sizeof(sk_ea))); + else + { + ASSERT_DIE(conn == &conn->bgp->outgoing_conn); + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_out_conn_sk, 0, (byte*)(&sk_ea), sizeof(sk_ea))); + } + conn->bgp->p.ea_state = ea_lookup(conn->bgp->p.ea_state, 0, EALS_CUSTOM); + proto_announce_state_later(&conn->bgp->p, attr); } static void @@ -1734,6 +1807,17 @@ bgp_start(struct proto *P) p->remote_id = 0; p->link_addr = IPA_NONE; + ea_list *eal = p->p.ea_state; + ea_set_attr(&eal, EA_LITERAL_EMBEDDED(&ea_bgp_rem_id, 0, p->remote_id)); + ea_set_attr(&eal, EA_LITERAL_EMBEDDED(&ea_bgp_loc_as, 0, p->local_as)); + ea_set_attr(&eal, EA_LITERAL_EMBEDDED(&ea_bgp_rem_as, 0, p->remote_as)); + ea_set_attr(&eal, EA_LITERAL_STORE_ADATA(&ea_bgp_rem_ip, 0, &p->remote_ip, sizeof(ip_addr))); + + ea_set_attr(&eal, EA_LITERAL_EMBEDDED(&ea_bgp_out_conn_state, 0, BS_IDLE)); + ea_set_attr(&eal, EA_LITERAL_EMBEDDED(&ea_bgp_in_conn_state, 0, BS_IDLE)); + + proto_announce_state(&p->p, eal); + /* Lock all channels when in GR recovery mode */ if (p->p.gr_recovery && p->cf->gr_mode) { @@ -1905,6 +1989,9 @@ bgp_init(struct proto_config *CF) /* Add MPLS channel */ proto_configure_mpls_channel(P, CF, RTS_BGP); + PST_LOCKED(ts) + bgp_state_to_eattr(P, ts->states[P->id]); + return P; } @@ -1926,6 +2013,14 @@ bgp_channel_init(struct channel *C, struct channel_config *CF) if (cf->base_table) c->base_table = cf->base_table->table; + + PST_LOCKED(ts) + { + ea_list *eal = ea_free_later(ts->channels[c->c.id]); + ea_set_attr(&eal, EA_LITERAL_EMBEDDED(&ea_bgp_afi, 0, c->afi)); + ts->channels[c->c.id] = ea_lookup_slow(eal, 0, EALS_IN_TABLE); + } + } static int @@ -2363,6 +2458,11 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF) /* We should update our copy of configuration ptr as old configuration will be freed */ p->cf = new; + ea_list *eal = proto_get_state(p->p.id); + ea_set_attr(&eal, EA_LITERAL_EMBEDDED(&ea_bgp_peer_type, 0, p->cf->peer_type)); + p->p.ea_state = ea_lookup(p->p.ea_state, 0, EALS_CUSTOM); + proto_announce_state_later(&p->p, eal); + /* Check whether existing connections are compatible with required capabilities */ struct bgp_conn *ci = &p->incoming_conn; if (((ci->state == BS_OPENCONFIRM) || (ci->state == BS_ESTABLISHED)) && !bgp_check_capabilities(ci)) @@ -2566,6 +2666,27 @@ bgp_get_status(struct proto *P, byte *buf) bsprintf(buf, "%-14s%s%s", bgp_state_dsc(p), err1, err2); } +int +bgp_state_to_eattr(struct proto *P, struct ea_list *state) +{ + struct bgp_proto *p = (struct bgp_proto *) P; + ea_set_attr(&state, EA_LITERAL_EMBEDDED(&ea_bgp_rem_id, 0, p->remote_id)); + ea_set_attr(&state, EA_LITERAL_STORE_ADATA(&ea_bgp_rem_ip, 0, &p->remote_ip, sizeof(ip_addr))); + ea_set_attr(&state, EA_LITERAL_EMBEDDED(&ea_bgp_peer_type, 0, p->cf->peer_type)); + ea_set_attr(&state, EA_LITERAL_EMBEDDED(&ea_bgp_loc_as, 0, p->local_as)); + ea_set_attr(&state, EA_LITERAL_EMBEDDED(&ea_bgp_rem_as, 0, p->remote_as)); + ea_set_attr(&state, EA_LITERAL_EMBEDDED(&ea_bgp_as4_session, 0, p->as4_session)); + + ea_set_attr(&state, EA_LITERAL_STORE_ADATA(&ea_bgp_in_conn_local_open_msg, 0, NULL, 0)); + ea_set_attr(&state, EA_LITERAL_STORE_ADATA(&ea_bgp_in_conn_remote_open_msg, 0, NULL, 0)); + ea_set_attr(&state, EA_LITERAL_STORE_ADATA(&ea_bgp_out_conn_local_open_msg, 0, NULL, 0)); + ea_set_attr(&state, EA_LITERAL_STORE_ADATA(&ea_bgp_out_conn_remote_open_msg, 0, NULL, 0)); + + ea_set_attr(&state, EA_LITERAL_STORE_ADATA(&ea_bgp_close_bmp, 0, NULL, 0)); + ea_set_attr(&state, EA_LITERAL_EMBEDDED(&ea_bgp_close_bmp_set, 0, 0)); + return 1; +} + static void bgp_show_afis(int code, char *s, u32 *afis, uint count) { diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 41c6840a..e6db1114 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -293,7 +293,7 @@ struct bgp_stats { struct bgp_conn { struct bgp_proto *bgp; struct birdsock *sk; - u8 state; /* State of connection state machine */ + u8 state; /* State of connection state machine */ u8 as4_session; /* Session uses 4B AS numbers in AS_PATH (both sides support it) */ u8 ext_messages; /* Session uses extended message length */ u32 received_as; /* ASN received in OPEN message */ @@ -319,6 +319,21 @@ struct bgp_conn { uint hold_time, keepalive_time, send_hold_time; /* Times calculated from my and neighbor's requirements */ }; +struct bgp_conn_sk_ea { + ip_addr saddr; + ip_addr daddr; + int sport; + int dport; +}; + +struct closing_bgp { + int err_class; + int err_code; + int err_subcode; + int length; + byte data[0]; +}; + struct bgp_listen_request { node n; /* Node in bgp_socket / pending list */ struct bgp_socket *sock; /* Assigned socket */ @@ -644,6 +659,7 @@ extern struct rte_owner_class bgp_rte_owner_class; eattr * bgp_find_attr(ea_list *attrs, uint code); +int bgp_state_to_eattr(struct proto *P, struct ea_list *state); void bgp_set_attr_u32(ea_list **to, uint code, uint flags, u32 val); void bgp_set_attr_ptr(ea_list **to, uint code, uint flags, const struct adata *ad); void bgp_set_attr_data(ea_list **to, uint code, uint flags, void *data, uint len); @@ -698,6 +714,13 @@ bgp_total_aigp_metric(const rte *e) return metric; } +/* bgp protocol journal attributes */ +extern struct ea_class ea_bgp_rem_id, ea_bgp_rem_as, ea_bgp_loc_as, ea_bgp_rem_ip, ea_bgp_peer_type, ea_bgp_afi, + ea_bgp_in_conn_local_open_msg, ea_bgp_out_conn_local_open_msg, ea_bgp_in_conn_remote_open_msg, + ea_bgp_out_conn_remote_open_msg, ea_bgp_close_bmp, ea_bgp_close_bmp_set, ea_bgp_as4_session, + ea_bgp_state_startup, ea_bgp_in_conn_state, ea_bgp_out_conn_state, + ea_bgp_in_conn_sk, ea_bgp_out_conn_sk, ea_bgp_as4_out_conn, ea_bgp_as4_in_conn; + /* Extended state attributes */ extern struct ea_class ea_bgp_state_startup; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 10ee4bc0..401e2814 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -918,6 +918,17 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len) conn->remote_open_msg = bgp_copy_open(p, pkt, len); conn->remote_open_length = len - BGP_HEADER_LENGTH; + ea_list *attr = p->p.ea_state; + if (conn == &conn->bgp->incoming_conn) + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_in_conn_remote_open_msg, 0, conn->remote_open_msg, conn->remote_open_length)); + else + { + ASSERT_DIE(conn == &conn->bgp->outgoing_conn); + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_out_conn_remote_open_msg, 0, conn->remote_open_msg, conn->remote_open_length)); + } + p->p.ea_state = ea_lookup(p->p.ea_state, 0, EALS_CUSTOM); + proto_announce_state_later(&p->p, attr); + if (bgp_read_options(conn, pkt+29, pkt[28], len-29) < 0) return; @@ -1048,6 +1059,19 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len) conn->ext_messages = conn->local_caps->ext_messages && caps->ext_messages; p->remote_id = id; + ea_set_attr(&p->p.ea_state, EA_LITERAL_EMBEDDED(&ea_bgp_rem_id, 0, p->remote_id)); + + if (conn == &p->incoming_conn) + ea_set_attr(&p->p.ea_state, EA_LITERAL_EMBEDDED(&ea_bgp_as4_in_conn, 0, conn->as4_session)); + else + { + ASSERT_DIE(conn == &p->outgoing_conn); + ea_set_attr(&p->p.ea_state, EA_LITERAL_EMBEDDED(&ea_bgp_as4_out_conn, 0, conn->as4_session)); + } + + p->p.ea_state = ea_lookup(p->p.ea_state, 0, EALS_CUSTOM); + proto_announce_state_later(&p->p, p->p.ea_state); + DBG("BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x, AS4 session to %d\n", conn->hold_time, conn->keepalive_time, p->remote_as, p->remote_id, conn->as4_session); @@ -3084,6 +3108,17 @@ bgp_fire_tx(struct bgp_conn *conn) conn->local_open_msg = bgp_copy_open(p, buf, end - buf); conn->local_open_length = end - buf - BGP_HEADER_LENGTH; + ea_list *attr = p->p.ea_state; + if (conn == &conn->bgp->incoming_conn) + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_in_conn_local_open_msg, 0, conn->local_open_msg, conn->local_open_length)); + else + { + ASSERT_DIE(conn == &conn->bgp->outgoing_conn); + ea_set_attr(&attr, EA_LITERAL_STORE_ADATA(&ea_bgp_out_conn_local_open_msg, 0, conn->local_open_msg, conn->local_open_length)); + } + p->p.ea_state = ea_lookup(p->p.ea_state, 0, EALS_CUSTOM); + proto_announce_state_later(&p->p, attr); + return bgp_send(conn, PKT_OPEN, end - buf); } else if (s & (1 << PKT_KEEPALIVE))