diff --git a/nest/mrtdump.c b/nest/mrtdump.c index 515a7c4d..fa9bbbaf 100644 --- a/nest/mrtdump.c +++ b/nest/mrtdump.c @@ -219,14 +219,14 @@ mrt_rib_table_alloc(struct mrt_rib_table *state) } void -mrt_rib_table_header(struct mrt_rib_table *state, u32 sequence_number, u8 prefix_length, ip_addr prefix) +mrt_rib_table_header(struct mrt_rib_table *state, u32 sequence_number, u8 prefix_length, ip_addr prefix, uint is_addpath) { mrt_rib_table_reset(state); #ifdef IPV6 - state->subtype = MRT_RIB_IPV6_UNICAST; + state->subtype = (is_addpath == MRT_RIB_ADDPATH) ? MRT_RIB_IPV6_UNICAST_ADDPATH : MRT_RIB_IPV6_UNICAST; #else - state->subtype = MRT_RIB_IPV4_UNICAST; + state->subtype = (is_addpath == MRT_RIB_ADDPATH) ? MRT_RIB_IPV4_UNICAST_ADDPATH : MRT_RIB_IPV4_UNICAST; #endif struct mrt_buffer *msg = &state->msg; @@ -257,6 +257,16 @@ mrt_rib_table_add_entry(struct mrt_rib_table *state, const struct mrt_rib_entry mrt_buffer_put_var_autosize(msg, entry->peer_index); mrt_buffer_put_var_autosize(msg, entry->originated_time); + + switch (state->subtype) + { + case MRT_RIB_IPV4_UNICAST_ADDPATH: + case MRT_RIB_IPV6_UNICAST_ADDPATH: + case MRT_RIB_IPV4_MULTICAST_ADDPATH: + case MRT_RIB_IPV6_MULTICAST_ADDPATH: + mrt_buffer_put_var_autosize(msg, entry->path_id); + } + mrt_buffer_put_var_autosize(msg, entry->attributes_length); mrt_buffer_put_raw(msg, entry->attributes, entry->attributes_length); diff --git a/nest/mrtdump.h b/nest/mrtdump.h index 0e23a7d3..977cc72c 100644 --- a/nest/mrtdump.h +++ b/nest/mrtdump.h @@ -37,6 +37,13 @@ #define MRT_RIB_IPV6_UNICAST 4 #define MRT_RIB_IPV6_MULTICAST 5 #define MRT_RIB_GENERIC 6 +#define MRT_RIB_IPV4_UNICAST_ADDPATH 8 /* Experimental draft-petrie-grow-mrt-add-paths */ +#define MRT_RIB_IPV4_MULTICAST_ADDPATH 9 /* Experimental draft-petrie-grow-mrt-add-paths */ +#define MRT_RIB_IPV6_UNICAST_ADDPATH 10 /* Experimental draft-petrie-grow-mrt-add-paths */ +#define MRT_RIB_IPV6_MULTICAST_ADDPATH 11 /* Experimental draft-petrie-grow-mrt-add-paths */ +#define MRT_RIB_GENERIC_ADDPATH 12 /* Experimental draft-petrie-grow-mrt-add-paths */ +#define MRT_RIB_NO_ADDPATH 0 +#define MRT_RIB_ADDPATH 1 /* MRT BGP4MP Subtypes */ #define MRT_BGP4MP_MESSAGE 1 @@ -72,6 +79,7 @@ struct mrt_rib_entry { u16 peer_index; u32 originated_time; + u32 path_id; /* draft-petrie-grow-mrt-add-paths */ u16 attributes_length; byte *attributes; /* encoded BGP attributes */ }; @@ -98,7 +106,7 @@ void mrt_peer_index_table_add_peer(struct mrt_peer_index_table *state, u32 peer_ void mrt_peer_index_table_dump(struct mrt_peer_index_table *state, int file_descriptor); void mrt_rib_table_alloc(struct mrt_rib_table *state); -void mrt_rib_table_header(struct mrt_rib_table *state, u32 sequence_number, u8 prefix_length, ip_addr prefix); +void mrt_rib_table_header(struct mrt_rib_table *state, u32 sequence_number, u8 prefix_length, ip_addr prefix, uint is_addpath); void mrt_rib_table_add_entry(struct mrt_rib_table *state, const struct mrt_rib_entry *entry); /* implemented in sysdep */ diff --git a/proto/bgp/mrt.c b/proto/bgp/mrt.c index 713be83a..ff0ca703 100644 --- a/proto/bgp/mrt.c +++ b/proto/bgp/mrt.c @@ -52,6 +52,91 @@ bgp_mrt_rib_table_dump(struct mrt_table_dump_ctx *state) mrt_dump_message(fileno(state->rfile->f), MRT_TABLE_DUMP_V2, state->rib_table.subtype, msg, msg_length); } +static void +bgp_mrt_rib_table_entry(struct mrt_table_dump_ctx *state, net *n, uint is_addpath) +{ + u32 original_rib_sequence_number = state->rib_sequence_number; + + mrt_rib_table_header(&state->rib_table, state->rib_sequence_number++, n->n.pxlen, n->n.prefix, is_addpath); + + rte *e; + for (e = n->routes; e; e = e->next) + { + u32 path_id = 0; + + if (is_addpath == MRT_RIB_ADDPATH) + if (e->attrs->src->private_id == 0) + continue; + + if (is_addpath == MRT_RIB_NO_ADDPATH) + if (e->attrs->src->private_id != 0) + continue; + + struct proto *P = e->attrs->src->proto; + + if (!is_route_good_for_table_dump(state, e)) + continue; + + u16 peer_index = 0; /* have to correspond with fake zeroed-peer in peer index table */ + uint attributes_length = 0; + static byte attributes_buffer[BGP_ATTR_BUFFER_SIZE]; /* static intends to do better performance */ + + if (P->proto == &proto_bgp) + { + struct bgp_proto *p = (struct bgp_proto *) P; + + if (p->mrt_peer_index == 0) + { + log(L_INFO "%s: MRT Table Dump for %I/%u: Skipping not-indexed BPG RIB (local ASN: %u, remote ASN: %u)", p->p.name, n->n.prefix, n->n.pxlen, p->local_as, p->remote_as); + continue; + } + + /* Set as4_session=1 to force build AS_PATH as 32bit AS in bgp_encode_attrs() */ + struct bgp_proto bgp_proto_shallow_copy; + memcpy(&bgp_proto_shallow_copy, p, sizeof(bgp_proto_shallow_copy)); + bgp_proto_shallow_copy.as4_session = 1; + + attributes_length = bgp_encode_attrs(&bgp_proto_shallow_copy, attributes_buffer, e->attrs->eattrs, BGP_ATTR_BUFFER_SIZE); + if (attributes_length == -1) + { + log(L_WARN "%s: MRT Table Dump for %I/%u: Attribute list too long, let it blank", p->p.name, n->n.prefix, n->n.pxlen); + attributes_length = 0; + } + peer_index = p->mrt_peer_index; + + if (is_addpath) + path_id = e->attrs->src->private_id; + } + + struct mrt_rib_entry entry = { + .peer_index = peer_index, + .originated_time = (u32) bird_clock_to_unix_timestamp(e->lastmod), + .path_id = path_id, + .attributes_length = attributes_length, + .attributes = attributes_buffer + }; + + mrt_rib_table_add_entry(&state->rib_table, &entry); + } + + if (state->rib_table.entry_count) + bgp_mrt_rib_table_dump(state); + else + state->rib_sequence_number = original_rib_sequence_number; +} + +static void +mrt_rib_table_without_addpath(struct mrt_table_dump_ctx *state, net *n) +{ + bgp_mrt_rib_table_entry(state, n, MRT_RIB_NO_ADDPATH); +} + +static void +mrt_rib_table_with_addpath(struct mrt_table_dump_ctx *state, net *n) +{ + bgp_mrt_rib_table_entry(state, n, MRT_RIB_ADDPATH); +} + /* * Usage: * struct mrt_table_dump_ctx ctx; @@ -66,7 +151,6 @@ bgp_mrt_table_dump_step(struct mrt_table_dump_ctx *state) return; uint max_work_size = 1; - u32 original_rib_sequence_number = state->rib_sequence_number; FIB_ITERATE_START(&state->rtable->fib, &state->fit, f) { @@ -76,58 +160,8 @@ bgp_mrt_table_dump_step(struct mrt_table_dump_ctx *state) return; } - net *n = (net *) f; - mrt_rib_table_header(&state->rib_table, state->rib_sequence_number++, n->n.pxlen, n->n.prefix); - - rte *e; - for (e = n->routes; e; e = e->next) - { - struct proto *P = e->attrs->src->proto; - - if (!is_route_good_for_table_dump(state, e)) - continue; - - u16 peer_index = 0; /* have to correspond with fake zeroed-peer in peer index table */ - uint attributes_length = 0; - static byte attributes_buffer[BGP_ATTR_BUFFER_SIZE]; /* static intends to do better performance */ - - if (P->proto == &proto_bgp) - { - struct bgp_proto *p = (struct bgp_proto *) P; - - if (p->mrt_peer_index == 0) - { - log(L_INFO "%s: MRT Table Dump for %I/%u: Skipping not-indexed BPG RIB (local ASN: %u, remote ASN: %u)", p->p.name, n->n.prefix, n->n.pxlen, p->local_as, p->remote_as); - continue; - } - - struct bgp_proto tmp_bgp_proto = { - .as4_session = 1, /* to force build AS_PATH as 32bit AS in bgp_encode_attrs() */ - }; - - attributes_length = bgp_encode_attrs(&tmp_bgp_proto, attributes_buffer, e->attrs->eattrs, BGP_ATTR_BUFFER_SIZE); - if (attributes_length == -1) - { - log(L_WARN "%s: MRT Table Dump for %I/%u: Attribute list too long, let it blank", p->p.name, n->n.prefix, n->n.pxlen); - attributes_length = 0; - } - peer_index = p->mrt_peer_index; - } - - struct mrt_rib_entry entry = { - .peer_index = peer_index, - .originated_time = (u32) bird_clock_to_unix_timestamp(e->lastmod), - .attributes_length = attributes_length, - .attributes = attributes_buffer - }; - - mrt_rib_table_add_entry(&state->rib_table, &entry); - } - - if (state->rib_table.entry_count) - bgp_mrt_rib_table_dump(state); - else - state->rib_sequence_number = original_rib_sequence_number; + mrt_rib_table_without_addpath(state, (net *) f); + mrt_rib_table_with_addpath(state, (net *) f); } FIB_ITERATE_END(f); fit_get(&state->rtable->fib, &state->fit);