diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2023-04-21 04:47:55 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2023-04-21 04:47:55 +0200 |
commit | 52450bc96dcedbc30cbb2e282c6706ad9e5e5774 (patch) | |
tree | e12244a788d6a26c52b3e5785c677b8d82b6a1c9 /proto/bgp | |
parent | d61505b039bf0aa6697e28b2a4e07907c89ba1fb (diff) | |
parent | f3b599afe5bde0c7f232421743041b305bb8afa7 (diff) |
Merge branch 'bmp'
Diffstat (limited to 'proto/bgp')
-rw-r--r-- | proto/bgp/attrs.c | 7 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 14 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 12 | ||||
-rw-r--r-- | proto/bgp/packets.c | 142 |
4 files changed, 165 insertions, 10 deletions
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..c806765a 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, 0); + } } 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, 0); + } 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, 0); } } 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, 0); } } 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, 0); } } } @@ -1695,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/bgp.h b/proto/bgp/bgp.h index 302f58e7..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; @@ -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_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 +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); 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 +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(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); @@ -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); +byte * bgp_create_end_mark(struct bgp_channel *c, byte *buf); /* Packet types */ diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 5c17c370..b9537169 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); } @@ -1563,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; @@ -1648,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; @@ -1736,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; @@ -1833,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; @@ -1920,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; @@ -2012,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; @@ -2256,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; } @@ -2303,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; } @@ -2384,6 +2407,94 @@ 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) +{ + 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 * 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; } -static byte * +byte * bgp_create_end_mark(struct bgp_channel *c, byte *buf) { 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_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 +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, 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 +3032,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 +3336,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 |