From: Katerina Kubecova Date: Thu, 22 May 2025 09:09:31 +0000 (+0200) Subject: bgp: Editing bgp route parsing so it can fit parsing routes from mrtload. Renaming... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e4152742e704d62793117aa0c6ba878c53fc6706;p=thirdparty%2Fbird.git bgp: Editing bgp route parsing so it can fit parsing routes from mrtload. Renaming mrt load file. --- diff --git a/nest/protocol.h b/nest/protocol.h index 97a2ba406..68da8fd9e 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -51,6 +51,7 @@ enum protocol_class { PROTOCOL_L3VPN, PROTOCOL_OSPF, PROTOCOL_MRT, + PROTOCOL_MRTLOAD, PROTOCOL_PERF, PROTOCOL_PIPE, PROTOCOL_RADV, @@ -106,7 +107,7 @@ void protos_dump_all(struct dump_request *); extern struct protocol proto_device, proto_radv, proto_rip, proto_static, proto_mrt, - proto_ospf, proto_perf, proto_l3vpn, proto_aggregator, + proto_mrtload, proto_ospf, proto_perf, proto_l3vpn, proto_aggregator, proto_pipe, proto_bgp, proto_bmp, proto_bfd, proto_babel, proto_rpki; /* diff --git a/nest/rt-table.c b/nest/rt-table.c index ee3f11882..1be8a381d 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -3445,7 +3445,7 @@ rt_free_hostcache(rtable *tab) rta_free(he->src); if (he->uc) - log(L_ERR "Hostcache is not empty in table %s", tab->name); + log(L_ERR "Hostcache is not empty in table %s, count %i", tab->name, he->uc); } /* Freed automagically by the resource pool diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 51193d170..489405134 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -98,7 +98,11 @@ bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintp #define REPORT(msg, args...) \ - ({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); }) + ({ log(L_REMOTE "%s: " msg, s->proto_name, ## args); }) + +#define RTRACE(msg, args...) \ + ({ if (s->debug & D_ROUTES) \ + log(L_TRACE "%s: " msg, s->proto_name, ## args); }) #define DISCARD(msg, args...) \ ({ REPORT(msg, ## args); return; }) @@ -444,10 +448,9 @@ bgp_encode_as_path(struct bgp_write_state *s, eattr *a, byte *buf, uint size) static void bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to) { - struct bgp_proto *p = s->proto; int as_length = s->as4_session ? 4 : 2; - int as_sets = p->cf->allow_as_sets; - int as_confed = p->cf->confederation && p->is_interior; + int as_sets = s->allow_as_sets; + int as_confed = s->confederation && s->is_interior; char err[128]; if (!as_path_valid(data, len, as_length, as_sets, as_confed, err, sizeof(err))) @@ -462,13 +465,13 @@ bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte } /* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */ - if (p->is_interior && !p->is_internal && + if (s->is_interior && !s->is_internal && ((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE))) WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE"); /* Reject routes with first AS in AS_PATH not matching neighbor AS; RFC 4271 6.3 */ - if (!p->is_internal && p->cf->enforce_first_as && - !bgp_as_path_first_as_equal(data, len, p->remote_as)) + if (!s->is_internal && s->enforce_first_as && + !bgp_as_path_first_as_equal(data, len, s->remote_as)) WITHDRAW("Malformed AS_PATH attribute - %s", "First AS differs from neigbor AS"); bgp_set_attr_data(to, s->pool, BA_AS_PATH, flags, data, len); @@ -557,7 +560,7 @@ bgp_export_local_pref(struct bgp_export_state *s, eattr *a) static void bgp_decode_local_pref(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to) { - if (!s->proto->is_interior && !s->proto->cf->allow_local_pref) + if (!s->is_interior && !s->allow_local_pref) DISCARD(BAD_EBGP, "LOCAL_PREF"); if (len != 4) @@ -651,7 +654,7 @@ bgp_export_originator_id(struct bgp_export_state *s, eattr *a) static void bgp_decode_originator_id(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to) { - if (!s->proto->is_internal) + if (!s->is_internal) DISCARD(BAD_EBGP, "ORIGINATOR_ID"); if (len != 4) @@ -675,7 +678,7 @@ bgp_export_cluster_list(struct bgp_export_state *s UNUSED, eattr *a) static void bgp_decode_cluster_list(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to) { - if (!s->proto->is_internal) + if (!s->is_internal) DISCARD(BAD_EBGP, "CLUSTER_LIST"); if (!len || (len % 4)) @@ -821,8 +824,7 @@ bgp_decode_as4_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flag static void bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to) { - struct bgp_proto *p = s->proto; - int sets = p->cf->allow_as_sets; + int sets = s->allow_as_sets; char err[128]; @@ -1301,25 +1303,25 @@ bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end static void bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool); static inline int -bgp_as_path_loopy(struct bgp_proto *p, ea_list *attrs, u32 asn) +bgp_as_path_loopy(struct bgp_parse_state *s, ea_list *attrs, u32 asn) { eattr *e = bgp_find_attr(attrs, BA_AS_PATH); - int num = p->cf->allow_local_as + 1; + int num = s->allow_local_as + 1; return (e && (num > 0) && as_path_contains(e->u.ptr, asn, num)); } static inline int -bgp_originator_id_loopy(struct bgp_proto *p, ea_list *attrs) +bgp_originator_id_loopy(struct bgp_parse_state *s, ea_list *attrs) { eattr *e = bgp_find_attr(attrs, BA_ORIGINATOR_ID); - return (e && (e->u.data == p->local_id)); + return (e && (e->u.data == s->local_id)); } static inline int -bgp_cluster_list_loopy(struct bgp_proto *p, ea_list *attrs) +bgp_cluster_list_loopy(u32 rr_cluster_id, ea_list *attrs) { eattr *e = bgp_find_attr(attrs, BA_CLUSTER_LIST); - return (e && int_set_contains(e->u.ptr, p->rr_cluster_id)); + return (e && int_set_contains(e->u.ptr, rr_cluster_id)); } static inline void @@ -1329,7 +1331,7 @@ bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, ui if (BIT32_TEST(s->attrs_seen, code)) { if ((code == BA_MP_REACH_NLRI) || (code == BA_MP_UNREACH_NLRI)) - bgp_parse_error(s, 1); + s->parse_error(s, 1); else DISCARD("Discarding duplicate attribute (code %u)", code); } @@ -1366,9 +1368,8 @@ bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, ui * by an (uncached) &rta. */ ea_list * -bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len, void (*parse_error)(struct bgp_parse_state *, uint)) +bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len) { - struct bgp_proto *p = s->proto; ea_list *attrs = NULL; uint code, flags, alen; byte *pos = data; @@ -1430,28 +1431,30 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len, void (*parse_e /* When receiving attributes from non-AS4-aware BGP speaker, we have to reconstruct AS_PATH and AGGREGATOR attributes; RFC 6793 4.2.3 */ - if (!p->as4_session) + if (!s->as4_session) bgp_process_as4_attrs(&attrs, s->pool); +#define IS_LOOP(msg, args...) { RTRACE("update is loop (" msg "), treating as withdraw", ##args); goto loop; } + /* Reject routes with our ASN in AS_PATH attribute */ - if (bgp_as_path_loopy(p, attrs, p->local_as)) + if (bgp_as_path_loopy(s, attrs, s->local_as)) goto loop; /* Reject routes with our Confederation ID in AS_PATH attribute; RFC 5065 4.0 */ - if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as)) + if ((s->public_as != s->local_as) && bgp_as_path_loopy(s, attrs, s->public_as)) goto loop; /* Reject routes with our Router ID in ORIGINATOR_ID attribute; RFC 4456 8 */ - if (p->is_internal && bgp_originator_id_loopy(p, attrs)) + if (s->is_internal && bgp_originator_id_loopy(s, attrs)) goto loop; /* Reject routes with our Cluster ID in CLUSTER_LIST attribute; RFC 4456 8 */ - if (p->rr_client && bgp_cluster_list_loopy(p, attrs)) + if (s->rr_client && bgp_cluster_list_loopy(s->rr_cluster_id, attrs)) goto loop; /* If there is no local preference, define one */ if (!BIT32_TEST(s->attrs_seen, BA_LOCAL_PREF)) - bgp_set_attr_u32(&attrs, s->pool, BA_LOCAL_PREF, 0, p->cf->default_local_pref); + bgp_set_attr_u32(&attrs, s->pool, BA_LOCAL_PREF, 0, s->default_local_pref); return attrs; @@ -1464,7 +1467,7 @@ framing_error: withdraw: /* RFC 7606 5.2 - handle missing NLRI during errors */ if (!s->ip_reach_len && !s->mp_reach_len) - parse_error(s, 1); + s->parse_error(s, 1); s->err_withdraw = 1; return NULL; @@ -1478,39 +1481,39 @@ void bgp_finish_attrs(struct bgp_parse_state *s, rta *a) { /* AIGP test here instead of in bgp_decode_aigp() - we need to know channel */ - if (BIT32_TEST(s->attrs_seen, BA_AIGP) && !s->channel->cf->aigp) + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); + if (BIT32_TEST(s->attrs_seen, BA_AIGP) && !c->cf->aigp) { REPORT("Discarding AIGP attribute received on non-AIGP session"); bgp_unset_attr(&a->eattrs, s->pool, BA_AIGP); } /* Handle OTC ingress procedure, RFC 9234 */ - if (bgp_channel_is_role_applicable(s->channel)) + if (bgp_channel_is_role_applicable(c)) { - struct bgp_proto *p = s->proto; eattr *e = bgp_find_attr(a->eattrs, BA_ONLY_TO_CUSTOMER); /* Reject routes from downstream if they are leaked */ - if (e && (p->cf->local_role == BGP_ROLE_PROVIDER || - p->cf->local_role == BGP_ROLE_RS_SERVER)) + if (e && (s->local_role == BGP_ROLE_PROVIDER || + s->local_role == BGP_ROLE_RS_SERVER)) WITHDRAW("Route leak detected - OTC attribute from downstream"); /* Reject routes from peers if they are leaked */ - if (e && (p->cf->local_role == BGP_ROLE_PEER) && (e->u.data != p->cf->remote_as)) + if (e && (s->local_role == BGP_ROLE_PEER) && (e->u.data != s->remote_as)) WITHDRAW("Route leak detected - OTC attribute with mismatched ASN (%u)", (uint) e->u.data); /* Mark routes from upstream if it did not happened before */ - if (!e && (p->cf->local_role == BGP_ROLE_CUSTOMER || - p->cf->local_role == BGP_ROLE_PEER || - p->cf->local_role == BGP_ROLE_RS_CLIENT)) - bgp_set_attr_u32(&a->eattrs, s->pool, BA_ONLY_TO_CUSTOMER, 0, p->cf->remote_as); + if (!e && (s->local_role == BGP_ROLE_CUSTOMER || + s->local_role == BGP_ROLE_PEER || + s->local_role == BGP_ROLE_RS_CLIENT)) + bgp_set_attr_u32(&a->eattrs, s->pool, BA_ONLY_TO_CUSTOMER, 0, s->remote_as); } /* Apply MPLS policy for labeled SAFIs */ - if (s->mpls && s->proto->p.mpls_channel) + if (s->mpls && s->mpls_channel) { - struct mpls_channel *mc = (void *) s->proto->p.mpls_channel; + struct mpls_channel *mc = (void *) s->mpls_channel; ea_set_attr_u32(&a->eattrs, s->pool, EA_MPLS_POLICY, 0, EAF_TYPE_INT, mc->label_policy); } } @@ -1769,7 +1772,7 @@ bgp_preexport(struct channel *C, rte *e) /* Generally, this should be handled when path is received, but we check it also here as rr_cluster_id may be undefined or different in src. */ - if (p->rr_cluster_id && bgp_cluster_list_loopy(p, e->attrs->eattrs)) + if (p->rr_cluster_id && bgp_cluster_list_loopy(p->rr_cluster_id, e->attrs->eattrs)) return -1; } diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index c8f90fadb..1f3ae87ca 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -2278,7 +2278,7 @@ bgp_init(struct proto_config *CF) return P; } -static void +void bgp_channel_init(struct channel *C, struct channel_config *CF) { struct bgp_channel *c = (void *) C; @@ -2380,7 +2380,7 @@ bgp_channel_start(struct channel *C) return 0; /* XXXX: Currently undefined */ } -static void +void bgp_channel_shutdown(struct channel *C) { struct bgp_channel *c = (void *) C; @@ -2390,7 +2390,7 @@ bgp_channel_shutdown(struct channel *C) c->packets_to_send = 0; } -static void +void bgp_channel_cleanup(struct channel *C) { struct bgp_channel *c = (void *) C; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 017677f5c..adc1e8359 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -493,17 +493,47 @@ struct bgp_write_state { }; struct bgp_parse_state { - struct bgp_proto *proto; - struct bgp_channel *channel; + // instead of struct bgp_proto *proto; + struct proto *p; + u32 local_as; + u32 public_as; + u32 remote_as; + u32 rr_cluster_id; + u32 local_id; + u8 is_mrt_parse; + u8 is_interior; + u8 is_internal; + const char *proto_name; + u32 debug; /* Debugging flags */ + struct channel *mpls_channel; + + // from config + int allow_as_sets; + int allow_local_pref; + int allow_local_as; + int enforce_first_as; + u32 default_local_pref; + u32 confederation; + u8 local_role; + int rr_client; + ip_addr remote_ip; + + struct channel *channel; struct linpool *pool; -, void (*parse_error)(struct bgp_parse_state *, uint); - void (*rte_update)(struct bgp_parse_state *, ...); + void (*parse_error)(struct bgp_parse_state *, uint); + void (*rte_update)(struct bgp_parse_state *, const net_addr *, u32, rta *); + void (*bgp_apply_next_hop)(struct bgp_parse_state *, rta *, ip_addr, ip_addr); + bool (*get_channel)(struct bgp_parse_state *, u32); + void (*apply_mpls_labels)(struct bgp_parse_state *, rta *, u32 *, uint); + void (*end_mark)(struct bgp_parse_state *, u32); int as4_session; int add_path; int mpls; int reach_nlri_step; + const struct bgp_af_desc *desc; + u16 preference; u32 attrs_seen[256/32]; @@ -606,6 +636,11 @@ void bgp_refresh_end(struct bgp_channel *c); 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_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a0); + +void bgp_channel_init(struct channel *C, struct channel_config *CF); +void bgp_channel_shutdown(struct channel *C); +void bgp_channel_cleanup(struct channel *C); void bgp_fix_attr_flags(ea_list *attrs); @@ -664,7 +699,7 @@ int bgp_encode_mp_reach_mrt(struct bgp_write_state *s, eattr *a, byte *buf, uint const char * bgp_attr_name(uint code); int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end); ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len); -int bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea); +void bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea); void bgp_finish_attrs(struct bgp_parse_state *s, rta *a); void bgp_init_bucket_table(struct bgp_channel *c); diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index b93d4a385..42af4c99b 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -64,6 +64,25 @@ bgp_get_channel(struct bgp_proto *p, u32 afi) return NULL; } +bool +bgp_get_channel_to_parse(struct bgp_parse_state *s, u32 afi) +{ + struct bgp_proto *p = (struct bgp_proto *) s->p; + struct bgp_channel *c = bgp_get_channel(p, afi); + + if (!c) + return false; + + s->channel = &c->c; + s->add_path = c->add_path_rx; + s->mpls = c->desc->mpls; + + s->last_id = 0; + s->last_src = s->p->main_source; + s->desc = c->desc; + return true; +} + static inline void put_af3(byte *buf, u32 id) { @@ -1057,7 +1076,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len) */ #define REPORT(msg, args...) \ - ({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); }) + ({ log(L_REMOTE "%s: " msg, s->p->name, ## args); }) #define DISCARD(msg, args...) \ ({ REPORT(msg, ## args); return; }) @@ -1078,8 +1097,9 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len) static void bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll) { - struct bgp_proto *p = s->proto; - struct bgp_channel *c = s->channel; + ASSERT_DIE(s->p); + struct bgp_proto *p = (struct bgp_proto *) s->p; + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); if (c->cf->gw_mode == GW_DIRECT) { @@ -1137,7 +1157,8 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 *labels, uint lnum) if ((lnum == 1) && (labels[0] == BGP_MPLS_NULL)) lnum = 0; - if (s->channel->cf->gw_mode == GW_DIRECT) + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); + if (c->cf->gw_mode == GW_DIRECT) { a->nh.labels = lnum; memcpy(a->nh.label, labels, 4*lnum); @@ -1155,8 +1176,8 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 *labels, uint lnum) static void bgp_apply_flow_validation(struct bgp_parse_state *s, const net_addr *n, rta *a) { - struct bgp_channel *c = s->channel; - int valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior); + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); + int valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->is_interior); a->dest = valid ? RTD_NONE : RTD_UNREACHABLE; /* Invalidate cached rta if dest changes */ @@ -1184,7 +1205,7 @@ static inline int bgp_use_next_hop(struct bgp_export_state *s, eattr *a) { struct bgp_proto *p = s->proto; - struct bgp_channel *c = s->channel; + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); ip_addr *nh = (void *) a->u.ptr->data; /* Handle next hop self option */ @@ -1221,7 +1242,7 @@ static inline int bgp_use_gateway(struct bgp_export_state *s) { struct bgp_proto *p = s->proto; - struct bgp_channel *c = s->channel; + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); rta *ra = s->route->attrs; /* Handle next hop self option - also applies to gateway */ @@ -1383,7 +1404,6 @@ bgp_encode_next_hop_ip(struct bgp_write_state *s, eattr *a, byte *buf, uint size static void bgp_decode_next_hop_ip(struct bgp_parse_state *s, byte *data, uint len, rta *a) { - struct bgp_channel *c = s->channel; struct adata *ad = lp_alloc_adata(s->pool, 32); ip_addr *nh = (void *) ad->data; @@ -1417,8 +1437,12 @@ bgp_decode_next_hop_ip(struct bgp_parse_state *s, byte *data, uint len, rta *a) if (ipa_zero(nh[1])) ad->length = 16; - if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop) - WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name); + if (!s->is_mrt_parse) + { + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); + if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop) + WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name); + } // XXXX validate next hop @@ -1470,7 +1494,6 @@ bgp_encode_next_hop_vpn(struct bgp_write_state *s, eattr *a, byte *buf, uint siz static void bgp_decode_next_hop_vpn(struct bgp_parse_state *s, byte *data, uint len, rta *a) { - struct bgp_channel *c = s->channel; struct adata *ad = lp_alloc_adata(s->pool, 32); ip_addr *nh = (void *) ad->data; @@ -1508,8 +1531,13 @@ bgp_decode_next_hop_vpn(struct bgp_parse_state *s, byte *data, uint len, rta *a) if ((get_u64(data) != 0) || ((len == 48) && (get_u64(data+24) != 0))) bgp_parse_error(s, 9); - if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop) - WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name); + if (!s->is_mrt_parse) + { + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); + + if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop) + WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name); + } // XXXX validate next hop @@ -1550,12 +1578,14 @@ bgp_update_next_hop_none(struct bgp_export_state *s, eattr *a, ea_list **to) * UPDATE */ -static void +void bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a0) { + ASSERT_DIE(s->p); + if (path_id != s->last_id) { - s->last_src = rt_get_source(&s->proto->p, path_id); + s->last_src = rt_get_source(s->p, path_id); s->last_id = path_id; rta_free(s->cached_rta); @@ -1569,7 +1599,7 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a REPORT("Invalid route %N withdrawn", n); /* Route withdraw */ - rte_update3(&s->channel->c, n, NULL, s->last_src); + rte_update3(s->channel, n, NULL, s->last_src); return; } @@ -1585,7 +1615,7 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a rta *a = rta_clone(s->cached_rta); rte *e = rte_get_temp(a, s->last_src); - rte_update3(&s->channel->c, n, e, s->last_src); + rte_update3(s->channel, n, e, s->last_src); } static void @@ -1644,7 +1674,7 @@ bgp_decode_mpls_labels(struct bgp_parse_state *s, byte **pos, uint *len, uint *p memcpy(s->mpls_labels->data, labels, 4*lnum); /* Update next hop entry in rta */ - bgp_apply_mpls_labels(s, a, labels, lnum); + s->apply_mpls_labels(s, a, labels, lnum); /* Attributes were changed, invalidate cached entry */ rta_free(s->cached_rta); @@ -2095,7 +2125,7 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a) enum flow_validated_state r = flow4_validate(data, dlen); if (r != FLOW_ST_VALID) { - log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r)); + log(L_REMOTE "%s: Invalid flow route: %s", s->proto_name, flow_validated_state_str(r)); bgp_parse_error(s, 1); } @@ -2115,8 +2145,13 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a) ADVANCE(pos, len, flen); /* Apply validation procedure per RFC 8955 (6) */ - if (a && s->channel->cf->validate) - bgp_apply_flow_validation(s, n, a); + if (!s->is_mrt_parse) + { + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); + + if (a && c->cf->validate) + bgp_apply_flow_validation(s, n, a); + } bgp_rte_update(s, n, path_id, a); } @@ -2190,7 +2225,7 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a) enum flow_validated_state r = flow6_validate(data, dlen); if (r != FLOW_ST_VALID) { - log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r)); + log(L_REMOTE "%s: Invalid flow route: %s", s->proto_name, flow_validated_state_str(r)); bgp_parse_error(s, 1); } @@ -2210,8 +2245,13 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a) ADVANCE(pos, len, flen); /* Apply validation procedure per RFC 8955 (6) */ - if (a && s->channel->cf->validate) - bgp_apply_flow_validation(s, n, a); + if (!s->is_mrt_parse) + { + struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel); + + if (a && c->cf->validate) + bgp_apply_flow_validation(s, n, a); + } bgp_rte_update(s, n, path_id, a); } @@ -2723,7 +2763,7 @@ bgp_create_end_mark(struct bgp_channel *c, byte *buf) static inline void bgp_rx_end_mark(struct bgp_parse_state *s, u32 afi) { - struct bgp_proto *p = s->proto; + struct bgp_proto *p = (struct bgp_proto *) s->p; struct bgp_channel *c = bgp_get_channel(p, afi); BGP_TRACE(D_PACKETS, "Got END-OF-RIB"); @@ -2744,18 +2784,10 @@ bgp_rx_end_mark(struct bgp_parse_state *s, u32 afi) static inline void bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_list *ea, byte *nh, uint nh_len) { - struct bgp_channel *c = bgp_get_channel(s->proto, afi); - rta *a = NULL; - - if (!c) + if (!s->get_channel(s, afi)) DISCARD(BAD_AFI, BGP_AFI(afi), BGP_SAFI(afi)); - s->channel = c; - s->add_path = c->add_path_rx; - s->mpls = c->desc->mpls; - - s->last_id = 0; - s->last_src = s->proto->p.main_source; + rta *a = NULL; /* * IPv4 BGP and MP-BGP may be used together in one update, therefore we do not @@ -2770,11 +2802,11 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis a->source = RTS_BGP; a->scope = SCOPE_UNIVERSE; - a->from = s->proto->remote_ip; + a->from = s->remote_ip; a->eattrs = ea; - a->pref = c->c.preference; + a->pref = s->channel->preference; - c->desc->decode_next_hop(s, nh, nh_len, a); + s->desc->decode_next_hop(s, nh, nh_len, a); bgp_finish_attrs(s, a); /* Handle withdraw during next hop decoding */ @@ -2782,14 +2814,14 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis a = NULL; } - c->desc->decode_nlri(s, nlri, len, a); + s->desc->decode_nlri(s, nlri, len, a); rta_free(s->cached_rta); s->cached_rta = NULL; } -int -bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea, void (*parse_error)(struct bgp_parse_state *, uint)) +void +bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea) { /* * UPDATE message format @@ -2800,44 +2832,64 @@ bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea, v * var Path Attributes * var IPv4 Reachable Routes NLRI */ - log("in parse update, len %i", len); uint pos = 0; s->ip_unreach_len = get_u16(pkt + pos); - log("s->ip_unreach_len %i", s->ip_unreach_len); s->ip_unreach_nlri = pkt + pos + 2; pos += 2 + s->ip_unreach_len; if (pos + 2 > len) { - parse_error(s, 1); - return 0; + s->parse_error(s, 1); + return; } s->attr_len = get_u16(pkt + pos); - log("s->attr_len %i", s->attr_len); s->attrs = pkt + pos + 2; pos += 2 + s->attr_len; if (pos > len) { - parse_error(s, 1); - return 0; + s->parse_error(s, 1); + return; } s->ip_reach_len = len - pos; s->ip_reach_nlri = pkt + pos; if (s->attr_len) - *ea = bgp_decode_attrs(s, s->attrs, s->attr_len, parse_error); + *ea = bgp_decode_attrs(s, s->attrs, s->attr_len); else *ea = NULL; - return 1; + + /* Check for End-of-RIB marker */ + if (!s->attr_len && !s->ip_unreach_len && !s->ip_reach_len) + { s->end_mark(s, BGP_AF_IPV4); return; } + + /* Check for MP End-of-RIB marker */ + if ((s->attr_len < 8) && !s->ip_unreach_len && !s->ip_reach_len && + !s->mp_reach_len && !s->mp_unreach_len && s->mp_unreach_af) + { s->end_mark(s, s->mp_unreach_af); return; } + + if (s->ip_unreach_len) + bgp_decode_nlri(s, BGP_AF_IPV4, s->ip_unreach_nlri, s->ip_unreach_len, NULL, NULL, 0); + + if (s->mp_unreach_len) + bgp_decode_nlri(s, s->mp_unreach_af, s->mp_unreach_nlri, s->mp_unreach_len, NULL, NULL, 0); + + s->reach_nlri_step = 1; + + if (s->ip_reach_len) + bgp_decode_nlri(s, BGP_AF_IPV4, s->ip_reach_nlri, s->ip_reach_len, + *ea, s->ip_next_hop_data, s->ip_next_hop_len); + + if (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); } static void bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) { - log("bgp_rx_update"); struct bgp_proto *p = conn->bgp; ea_list *ea = NULL; @@ -2859,7 +2911,35 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) /* Initialize parse state */ struct bgp_parse_state s = { - .proto = p, + .p = &p->p, + .parse_error = bgp_parse_error, + .end_mark = bgp_rx_end_mark, + .get_channel = bgp_get_channel_to_parse, + .apply_mpls_labels = bgp_apply_mpls_labels, + + .local_as = p->local_as, + .remote_ip = p->remote_ip, + .public_as = p->public_as, + .remote_as = p->remote_as, + .rr_cluster_id = p->rr_cluster_id, + .local_id = p->local_id, + .is_interior = p->is_interior, + .is_internal = p->is_internal, + .proto_name = p->p.name, + .is_mrt_parse = 0, + .debug = p->p.debug, + .mpls_channel = p->p.mpls_channel, + + // from config + .default_local_pref = p->cf->default_local_pref, + .allow_local_pref = p->cf->allow_local_pref, + .allow_as_sets = p->cf->allow_as_sets, + .allow_local_as = p->cf->allow_local_as, + .confederation = p->cf->confederation, + .enforce_first_as = p->cf->enforce_first_as, + .local_role = p->cf->local_role, + .rr_client = p->cf->rr_client, + .pool = tmp_linpool, .as4_session = p->as4_session, }; @@ -2875,33 +2955,7 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) if (len < 23) { bgp_error(conn, 1, 2, pkt+16, 2); return; } - bgp_parse_update(&s, pkt + 19, len - 19, &ea, bgp_parse_error); /* add 19 to skip fixed header */ - log("yay update parsed"); - - /* Check for End-of-RIB marker */ - if (!s.attr_len && !s.ip_unreach_len && !s.ip_reach_len) - { bgp_rx_end_mark(&s, BGP_AF_IPV4); goto done; } - - /* Check for MP End-of-RIB marker */ - if ((s.attr_len < 8) && !s.ip_unreach_len && !s.ip_reach_len && - !s.mp_reach_len && !s.mp_unreach_len && s.mp_unreach_af) - { bgp_rx_end_mark(&s, s.mp_unreach_af); goto done; } - - if (s.ip_unreach_len) - bgp_decode_nlri(&s, BGP_AF_IPV4, s.ip_unreach_nlri, s.ip_unreach_len, NULL, NULL, 0); - - if (s.mp_unreach_len) - bgp_decode_nlri(&s, s.mp_unreach_af, s.mp_unreach_nlri, s.mp_unreach_len, NULL, NULL, 0); - - s.reach_nlri_step = 1; - - if (s.ip_reach_len) - bgp_decode_nlri(&s, BGP_AF_IPV4, s.ip_reach_nlri, s.ip_reach_len, - ea, s.ip_next_hop_data, s.ip_next_hop_len); - - if (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); + bgp_parse_update(&s, pkt + 19, len - 19, &ea); /* add 19 to skip fixed header */ done: rta_free(s.cached_rta); @@ -3504,11 +3558,9 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len) byte type = pkt[18]; DBG("BGP: Got packet %02x (%d bytes)\n", type, len); - log("BGP: Got packet %02x (%d bytes) !!!!!!!!!!!!!!!!!!\n", type, len); conn->bgp->stats.rx_messages++; conn->bgp->stats.rx_bytes += len; - log("do we want to do mrt dump ? conn->bgp->p.mrtdump %x & MD_MESSAGES %x", conn->bgp->p.mrtdump, MD_MESSAGES); if (conn->bgp->p.mrtdump & MD_MESSAGES) bgp_dump_message(conn, pkt, len); diff --git a/proto/mrt/Makefile b/proto/mrt/Makefile index a78f11a5a..93958defa 100644 --- a/proto/mrt/Makefile +++ b/proto/mrt/Makefile @@ -1,6 +1,7 @@ -src := mrt.c mrt_parse.c +src := mrt.c mrt_load.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(conf-y-targets): $(s)mrtload.Y tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index 3369c9de9..1336837a8 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -710,10 +710,6 @@ mrt_dump_cont(struct cli *c) cli_printf(c, 0, ""); mrt_table_dump_free(c->rover); c->cont = c->cleanup = c->rover = NULL; - mrt_load("mrt_dump.txt"); - log("____________________________"); - mrt_load("dump.mrt"); - mrt_load("dump_bgp.mrt"); } static void @@ -800,7 +796,6 @@ mrt_bgp_header(buffer *b, struct mrt_bgp_data *d) void mrt_dump_bgp_message(struct mrt_bgp_data *d) { - log("mrt_dump_bgp_message"); const u16 subtypes[] = { MRT_BGP4MP_MESSAGE, MRT_BGP4MP_MESSAGE_AS4, MRT_BGP4MP_MESSAGE_LOCAL, MRT_BGP4MP_MESSAGE_AS4_LOCAL, diff --git a/proto/mrt/mrt.h b/proto/mrt/mrt.h index 9371ce16c..4ff94c120 100644 --- a/proto/mrt/mrt.h +++ b/proto/mrt/mrt.h @@ -16,7 +16,6 @@ #include "nest/route.h" #include "lib/event.h" #include "lib/hash.h" -#include "proto/bgp/bgp.h" struct mrt_config { @@ -156,6 +155,4 @@ static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED) { } static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED) { } #endif -void mrt_load(char *file); - #endif /* _BIRD_MRT_H_ */ diff --git a/proto/mrt/mrt_load.c b/proto/mrt/mrt_load.c new file mode 100644 index 000000000..9ef35bde0 --- /dev/null +++ b/proto/mrt/mrt_load.c @@ -0,0 +1,400 @@ + +#include + +#include "mrt.h" +#include "mrt_load.h" + + +byte +mrtload_one(FILE *fp, u64 *remains) +{ + remains[0]--; + return fgetc(fp); +} + +void +mrtload_n_octet(FILE *fp, u64 *remains, byte *buff, int n) +{ + for (int i = 0; i < n; i++) + buff[i] = fgetc(fp); + + remains[0] = remains[0] - n; +} + +u64 +mrtload_four_octet(FILE *fp, u64 *remains) +{ + u64 ret = 0; + + for (int i = 0; i < 4; i++) + { + ret = ret << 8; + ret += fgetc(fp); + } + + remains[0] = remains[0] - 4; + + return ret; +} + +void +mrtload_ip(FILE *fp, u64 *remains, ip_addr *addr, bool is_ip6) +{ + if (is_ip6) + for (int i = 0; i < 4; i++) + addr->addr[i] = mrtload_four_octet(fp, remains); + else + { + addr->addr[0] = addr->addr[1] = addr->addr[2] = 0; + addr->addr[3] = mrtload_four_octet(fp, remains); + } +} + +u32 +mrtload_two_octet(FILE *fp, u64 *remains) +{ + remains[0] = remains[0] - 2; + return (fgetc(fp) << 8) + fgetc(fp); +} + +void +mrt_parse_error(struct bgp_parse_state * ps UNUSED, uint e UNUSED) +{ + log(L_WARN "mrt load: run into a parsing error"); +} + +/* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer AS Number | Local AS Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Interface Index | Address Family | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer IP Address (variable) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Local IP Address (variable) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | BGP Message... (variable) + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 12: BGP4MP_MESSAGE Subtype +*/ +void +mrt_parse_bgp_message(FILE *fp, u64 *remains, bool as4) +{ + u64 peer_as, local_as; + if (as4) + { + peer_as = mrtload_four_octet(fp, remains); + local_as = mrtload_four_octet(fp, remains); + } else + { + peer_as = mrtload_two_octet(fp, remains); + local_as = mrtload_two_octet(fp, remains); + } + + int interface_id = mrtload_two_octet(fp, remains); + int addr_fam = mrtload_two_octet(fp, remains); + + ip_addr peer_addr, local_addr; + mrtload_ip(fp, remains, &peer_addr, addr_fam == 2); + mrtload_ip(fp, remains, &local_addr, addr_fam == 2); + + log("peer as %lx local as %lx interface %x add fam %i peer %I loc %I", peer_as, local_as, interface_id, addr_fam, peer_addr, local_addr); +} + +static void +mrt_rx_end_mark(struct bgp_parse_state *s UNUSED, u32 afi UNUSED) +{ + /* Do nothing */ +} + +bool +mrt_get_channel_to_parse(struct bgp_parse_state *s UNUSED, u32 afi UNUSED) +{ + struct mrtload_proto *p = SKIP_BACK(struct mrtload_proto, p, s->p); + s->channel = &p->channel->c; + s->last_id = 0; + s->last_src = s->p->main_source; + s->desc = p->channel->desc; + s->channel->proto = s->p; + channel_set_state(s->channel, CS_START); + channel_set_state(s->channel, CS_UP); + return true; +} + +static void +mrt_apply_mpls_labels(struct bgp_parse_state *s UNUSED, rta *a UNUSED, u32 *labels UNUSED, uint lnum UNUSED) +{ + /* Do nothing */ +} + +static void +mrt_parse_bgp4mp_message(FILE *fp, u64 *remains, bool as4, struct proto *P) +{ + mrt_parse_bgp_message(fp, remains, as4); + + if (*remains < 19) + { + log(L_WARN "MRT parse BGP message: BGP message is too short (%i)", *remains); + return; + } + + for (int i = 0; i < 16; i++) /* skip marker */ + fgetc(fp); + + remains[0] = remains[0] - 16; + u64 length = mrtload_two_octet(fp, remains) - 16 - 2 -1; /* length without header (marker, length, type) */ + int type = mrtload_one(fp, remains); + + if (type != PKT_UPDATE) + return; + + /* This is usually done in proto_do_up, but the protocol will be used immediately */ + P->main_source = rt_get_source(P, 0); + rt_lock_source(P->main_source); + + struct bgp_parse_state s = { + .pool = lp_new(P->pool), + .parse_error = mrt_parse_error, + .end_mark = mrt_rx_end_mark, + .get_channel = mrt_get_channel_to_parse, + .apply_mpls_labels = mrt_apply_mpls_labels, + .is_mrt_parse = 1, + .p = P, + }; + + byte buf[length]; + ASSERT_DIE(length <= remains[0]); + mrtload_n_octet(fp, remains, buf, length); + ea_list *ea = NULL; + bgp_parse_update(&s, buf, length, &ea); +} + +int +mrt_parse_general_header(FILE *fp, struct proto *P) +{ + char is_eof = fgetc(fp); + u64 timestamp = is_eof; + + if (is_eof == EOF) + return 0; + else + { + for (int i = 0; i < 3; i++) + { + timestamp = timestamp << 8; + timestamp += fgetc(fp); + } + } + + int type = (fgetc(fp) << 8) + fgetc(fp); + int subtype = (fgetc(fp) << 8) + fgetc(fp); + u64 length = 0; + + for (int i = 0; i < 4; i++) + { + length = length << 8; + length += fgetc(fp); + } + u64 remains = length; + + /* We do not load MRT_TABLE_DUMP_V2 type and MRT_BGP4MP_STATE_CHANGE_AS4. */ + if (type == MRT_BGP4MP) + { + switch (subtype) + { + case (MRT_BGP4MP_MESSAGE): + case (MRT_BGP4MP_MESSAGE_LOCAL): + case (MRT_BGP4MP_MESSAGE_ADDPATH): + mrt_parse_bgp4mp_message(fp, &remains, false, P); + break; + case (MRT_BGP4MP_STATE_CHANGE_AS4): + break; + case (MRT_BGP4MP_MESSAGE_AS4): + case (MRT_BGP4MP_MESSAGE_AS4_LOCAL): + case (MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH): + case (MRT_BGP4MP_MESSAGE_AS4_ADDPATH): + mrt_parse_bgp4mp_message(fp, &remains, true, P); + break; + } + } + + ASSERT_DIE(remains <= length); + + for (u64 i = 0; i < remains; i++) + fgetc(fp); + + return 1; +} + +void +mrtload(struct proto *P) +{ + struct mrt_config *cf = SKIP_BACK(struct mrt_config, c, P->cf); + FILE *fp = fopen(cf->filename, "r"); + + if (fp == NULL) + { + log(L_WARN "Can not open file %s", fp); + return; + } + + /* Parsing mrt headers in loop. MRT_BGP4MP messages are loaded, the rest is skipped. */ + while (mrt_parse_general_header(fp, P)); +} + +void +mrtload_check_config(struct proto_config *CF, struct bgp_channel_config *CC) +{ + struct mrtload_config *cf = (void *) CF; + + if (!cf->table_cf) + cf_error("Table not specified"); + + if (!cf->filename) + cf_error("File not specified"); + + if (!CC->desc) + cf_error("Afi not specified."); +} + +static struct proto * +mrtload_init(struct proto_config *CF) +{ + struct proto *P = proto_new(CF); + struct mrtload_config *mlc = (struct mrtload_config *) CF; + proto_add_channel(P, &mlc->channel_cf->c); + + return P; +} + +static int +mrtload_start(struct proto *P) +{ + struct mrtload_proto *p = (void *) P; + struct mrtload_config *cf = (void *) (P->cf); + + p->channel = (void *) proto_add_channel(P, &cf->channel_cf->c); + + p->channel->afi = cf->channel_cf->afi; + p->channel->desc = cf->channel_cf->desc; + p->channel->c.channel = &channel_mrtload; + p->channel->c.table = cf->table_cf->table; + + if (cf->channel_cf->igp_table_ip4) + p->channel->igp_table_ip4 = cf->channel_cf->igp_table_ip4->table; + + if (cf->channel_cf->igp_table_ip6) + p->channel->igp_table_ip6 = cf->channel_cf->igp_table_ip6->table; + + mrtload(P); + + return PS_UP; +} + + +static int +mrtload_shutdown(struct proto *P) +{ + struct mrtload_proto *p = (void *) P; + proto_notify_state(&p->p, PS_DOWN); + return PS_DOWN; +} + +static int +mrtload_reconfigure(struct proto *P, struct proto_config *CF) +{ + //TODO where do we want reload mrt ? + P->cf = CF; + mrtload(P); + + return 1; +} + + +static void +mrtload_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED) +{ + /* Do nothing */ +} + +static int +mrtload_channel_start(struct channel *C) +{ + struct mrtload_proto *p = (void *) C->proto; + struct bgp_channel *c = (void *) C; + c->pool = p->p.pool; + return 0; +} + +void +mrtload_postconfig(struct proto_config *CF) +{ + struct mrtload_config *cf = (void *) CF; + if (cf->channel_cf->c.in_filter != FILTER_ACCEPT) + cf_error("MRT load channel in filter must be set to accept"); + if (cf->channel_cf->c.out_filter != FILTER_REJECT) + cf_error("MRT load channel out filter must be set to reject"); +} + + +static int +mrtload_channel_reconfigure(struct channel *C UNUSED, struct channel_config *CC UNUSED, + int *import_changed UNUSED, int *export_changed UNUSED) +{ + struct bgp_channel *c = (void *) C; + struct bgp_channel_config *new = (void *) CC; + struct bgp_channel_config *old = c->cf; + + if (old->afi != new->afi) + return 0; + if (old->desc != new->desc) + return 0; + if (old->c.table != new->c.table) + return 0; + + if (old->igp_table_ip4) + if (!new->igp_table_ip4 || old->igp_table_ip4->table != new->igp_table_ip4->table) + return 0; + + if (old->igp_table_ip6) + if (!new->igp_table_ip6 || old->igp_table_ip6->table != new->igp_table_ip6->table) + return 0; + + c->cf = new; + return 1; +} + +const struct channel_class channel_mrtload = { + .channel_size = sizeof(struct bgp_channel), + .config_size = sizeof(struct bgp_channel_config), + .init = bgp_channel_init, + .start = mrtload_channel_start, + .shutdown = bgp_channel_shutdown, + .cleanup = bgp_channel_cleanup, + .reconfigure = mrtload_channel_reconfigure, +}; + + +struct protocol proto_mrtload = { + .name = "mrtload", + .template = "mrt%d", + .class = PROTOCOL_MRTLOAD, + .proto_size = sizeof(struct mrtload_proto), + .config_size = sizeof(struct mrt_config), + .init = mrtload_init, + .start = mrtload_start, + .shutdown = mrtload_shutdown, + .reconfigure = mrtload_reconfigure, + .postconfig = mrtload_postconfig, + .copy_config = mrtload_copy_config, + .channel_mask = NB_IP | NB_VPN | NB_FLOW | NB_MPLS, +}; + +void +mrtload_build(void) +{ + proto_build(&proto_mrtload); +} diff --git a/proto/mrt/mrt_load.h b/proto/mrt/mrt_load.h new file mode 100644 index 000000000..6609d1c5b --- /dev/null +++ b/proto/mrt/mrt_load.h @@ -0,0 +1,36 @@ +#ifndef _BIRD_MRT_LOAD_H_ +#define _BIRD_MRT_LOAD_H_ + +#include "nest/bird.h" +#include "nest/protocol.h" +#include "lib/lists.h" +#include "nest/route.h" +#include "proto/bgp/bgp.h" +#include "filter/filter.h" +#include "proto/mrt/mrt.h" + +extern const struct channel_class channel_mrtload; + +struct mrtload_config { + struct proto_config c; + + struct rtable_config *table_cf; + const char *table_expr; + const struct filter *filter; + const char *filename; + int always_add_path; + struct bgp_channel_config *channel_cf; + const struct bgp_af_desc *desc; +}; + +struct mrtload_proto { + struct proto p; + + struct mrt_table_dump_state *table_dump; + struct bgp_channel *channel; +}; + + +void mrtload_check_config(struct proto_config *CF, struct bgp_channel_config *CC); + +#endif /* _BIRD_MRT_LOAD_H_ */ diff --git a/proto/mrt/mrt_parse.c b/proto/mrt/mrt_parse.c deleted file mode 100644 index e7f2b45e1..000000000 --- a/proto/mrt/mrt_parse.c +++ /dev/null @@ -1,387 +0,0 @@ - -#include "mrt.h" -#include - - -byte -mrt_load_one(FILE *fp, u64 *remains) -{ - remains[0]--; - return fgetc(fp); -} - -void -mrt_load_n_octet(FILE *fp, u64 *remains, byte *buff, int n) -{ - for (int i = 0; i < n; i++) - buff[i] = fgetc(fp); - remains[0] = remains[0] - n; -} - -u64 -mrt_load_four_octet(FILE *fp, u64 *remains) -{ - u64 ret = 0; - for (int i = 0; i < 4; i++) - { - ret = ret << 8; - ret += fgetc(fp); - } - remains[0] = remains[0] - 4; - return ret; -} - -void -mrt_load_ip(FILE *fp, u64 *remains, ip_addr *addr, bool is_ip6) -{ - if (is_ip6) - for (int i = 0; i < 4; i++) - addr->addr[i] = mrt_load_four_octet(fp, remains); - else - { - addr->addr[0] = addr->addr[1] = addr->addr[2] = 0; - addr->addr[3] = mrt_load_four_octet(fp, remains); - } -} - -u32 -mrt_load_two_octet(FILE *fp, u64 *remains) -{ - remains[0] = remains[0] - 2; - return (fgetc(fp) << 8) + fgetc(fp); -} - -/* - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Peer Type | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Peer BGP ID | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Peer IP Address (variable) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Peer AS (variable) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Figure 6: Peer Entries -*/ - -void -mrt_parse_peer(FILE *fp, u64 *remains) -{ - int peer_type = mrt_load_one(fp, remains); - u64 peer_bgp_id = mrt_load_four_octet(fp, remains); - ip_addr addr; - u64 peer_as; - mrt_load_ip(fp, remains, &addr, peer_type & MRT_PEER_TYPE_IPV6); - - if (peer_type & MRT_PEER_TYPE_32BIT_ASN) - peer_as = mrt_load_four_octet(fp,remains); - else - peer_as = mrt_load_two_octet(fp, remains); - log("peer type %i, bgp id %li adddr %I as %li", peer_type, peer_bgp_id, addr, peer_as); -} - -/* - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Collector BGP ID | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | View Name Length | View Name (variable) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Peer Count | Peer Entries (variable) - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Figure 5: PEER_INDEX_TABLE Subtype -*/ - -void -mrt_parse_peer_index_table(FILE *fp, u64 *remains) -{ - u64 collector = mrt_load_four_octet(fp, remains); - int name_len = mrt_load_two_octet(fp, remains); - log("name len %i collector %lx", name_len, collector); - char name[name_len + 1]; - name[name_len] = 0; - mrt_load_n_octet(fp, remains, name, name_len); - int peer_count = mrt_load_two_octet(fp, remains); - log("name %s, count %i", name, peer_count); - - for (int i = 0; i < peer_count; i++) - mrt_parse_peer(fp, remains); -} - -/* -0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Peer Index | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Originated Time | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Attribute Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | BGP Attributes... (variable) - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ - -void -mrt_parse_rib_entry(FILE *fp, u64 *remains, bool add_path) -{ - int peer_index = mrt_load_two_octet(fp, remains); - u64 orig_time = mrt_load_four_octet(fp, remains); - u64 path_id; - - if (add_path) - path_id = mrt_load_four_octet(fp, remains); - - int attr_len = mrt_load_two_octet(fp, remains); - log("rib entry index %lx, time %lx, attr len %i (rem %li) path %li", peer_index, orig_time, attr_len, *remains, path_id); - //TODO how are encoded the attrs? - remains[0] = remains[0] - attr_len; - - for (int i = 0; i < attr_len; i++) - fgetc(fp); -} - - -void -mrt_parse_rib_generic(FILE *fp, u64 *remains) -{ - u64 seq_num = mrt_load_four_octet(fp, remains); - int addr_fam_id = mrt_load_two_octet(fp, remains); - int subs_afi = mrt_load_one(fp, remains); - log("seq num %lx, fam %i, subs %i", seq_num, addr_fam_id, subs_afi); - //TODO length of Network layer reachebility -} - - -/* - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Prefix Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Prefix (variable) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Entry Count | RIB Entries (variable) - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ -void -mrt_parse_rib4_unicast(FILE *fp, u64 *remains, bool add_path) -{ - u64 seq_num = mrt_load_four_octet(fp, remains); - int pref_len = mrt_load_one(fp, remains); - byte prefix[pref_len/8]; - mrt_load_n_octet(fp, remains, prefix, pref_len/8); - int entry_count = mrt_load_two_octet(fp, remains); - log("seq %lx, pref len %i, enties %i", seq_num, pref_len, entry_count); - - for (int i = 0; i < entry_count; i++) - mrt_parse_rib_entry(fp, remains, add_path); -} - - -void -mrt_parse_error(struct bgp_parse_state * UNUSED, uint UNUSED) -{ - log("run into a parsing error"); -} - -/* - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Peer AS Number | Local AS Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Interface Index | Address Family | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Peer IP Address (variable) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Local IP Address (variable) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | BGP Message... (variable) - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Figure 12: BGP4MP_MESSAGE Subtype -*/ -void -mrt_parse_bgp_message(FILE *fp, u64 *remains, bool as4) -{ - u64 peer_as, local_as; - if (as4) - { - peer_as = mrt_load_four_octet(fp, remains); - local_as = mrt_load_four_octet(fp, remains); - } else - { - peer_as = mrt_load_two_octet(fp, remains); - local_as = mrt_load_two_octet(fp, remains); - } - - int interface_id = mrt_load_two_octet(fp, remains); - int addr_fam = mrt_load_two_octet(fp, remains); - - ip_addr peer_addr, local_addr; - mrt_load_ip(fp, remains, &peer_addr, addr_fam == 2); - mrt_load_ip(fp, remains, &local_addr, addr_fam == 2); - - log("peer as %lx local as %lx interface %x add fam %i peer %I loc %I", peer_as, local_as, interface_id, addr_fam, peer_addr, local_addr); -} - - -void -mrt_parse_bgp4mp_message(FILE *fp, u64 *remains, bool as4) -{ - log("hereeeee bgp message"); - mrt_parse_bgp_message(fp, remains, as4); - - if (*remains < 23) - { - log(L_WARN "MRT parse BGP message: BGP message is too short (%i)", *remains); - return; - } - - for (int i = 0; i < 16; i++) // marker - fgetc(fp); - - remains[0] = remains[0] - 16; - int length = mrt_load_two_octet(fp, remains); - int type = mrt_load_one(fp, remains); - log("message type %i", type); - - if (type != PKT_UPDATE) - { - log("Another BGP type"); - return; - } - - struct bgp_parse_state s = { - .pool = lp_new(&root_pool), - }; - byte buf[length]; - mrt_load_n_octet(fp, remains, buf, length); - ea_list *ea = NULL; - log("try to parse bgp update"); - bgp_parse_update(&s, buf, length, &ea, bgp_parse_error); - log("ok, seems parsed?"); -} - - -void -mrt_parse_bgp4mp_change_state(FILE *fp, u64 *remains, bool as4) -{ - mrt_parse_bgp_message(fp, remains, as4); - int old_state = mrt_load_two_octet(fp, remains); - int new_state = mrt_load_two_octet(fp, remains); - log("old state %i new state %i", old_state, new_state); -} - - -int -mrt_parse_general_header(FILE *fp) -{ - char is_eof = fgetc(fp); - u64 timestamp = is_eof; - - if (is_eof == EOF) - return 0; - else - { - for (int i = 0; i < 3; i++) - { - log("t %lx", timestamp); - timestamp = timestamp << 8; - timestamp += fgetc(fp); - } - } - - log("timestamp is %lx", timestamp); - int type = (fgetc(fp) << 8) + fgetc(fp); - int subtype = (fgetc(fp) << 8) + fgetc(fp); - log("type is %i, subtype %x", type, subtype); - u64 length = 0; - - for (int i = 0; i < 4; i++) - { - length = length << 8; - length += fgetc(fp); - } - u64 remains = length; - log("remains is %li", remains); - - if (type == MRT_TABLE_DUMP_V2) - { - switch (subtype) - { - case (MRT_PEER_INDEX_TABLE): - mrt_parse_peer_index_table(fp, &remains); - break; - case (MRT_RIB_IPV4_UNICAST): - case (MRT_RIB_IPV6_UNICAST): - case (MRT_RIB_IPV4_MULTICAST): - case (MRT_RIB_IPV6_MULTICAST): - mrt_parse_rib4_unicast(fp, &remains, false); - break; - 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_parse_rib4_unicast(fp, &remains, true); - break; - case (MRT_RIB_GENERIC): - case (MRT_RIB_GENERIC_ADDPATH): - mrt_parse_rib_generic(fp, &remains); - break; - default: - bug("mrt: unknown mrt table dump subtype"); - } - } else - { - ASSERT_DIE(type == MRT_BGP4MP); - - switch (subtype) - { - case (MRT_BGP4MP_MESSAGE): - case (MRT_BGP4MP_MESSAGE_LOCAL): - case (MRT_BGP4MP_MESSAGE_ADDPATH): - mrt_parse_bgp4mp_message(fp, &remains, false); - break; - case (MRT_BGP4MP_STATE_CHANGE_AS4): - mrt_parse_bgp4mp_change_state(fp, &remains, true); - break; - case (MRT_BGP4MP_MESSAGE_AS4): - case (MRT_BGP4MP_MESSAGE_AS4_LOCAL): - case (MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH): - case (MRT_BGP4MP_MESSAGE_AS4_ADDPATH): - mrt_parse_bgp4mp_message(fp, &remains, true); - break; - } - } - - ASSERT_DIE(remains < length); - - for (u64 i = 0; i < remains; i++) - fgetc(fp); - - return 1; -} - - -void -mrt_load(char *file) -{ - FILE *fp = fopen(file, "r"); - - if (fp == NULL) - { - log(L_WARN "Can not open file %s", fp); - return; - } - - while (mrt_parse_general_header(fp)); -} diff --git a/proto/mrt/mrtload.Y b/proto/mrt/mrtload.Y new file mode 100644 index 000000000..51eba5740 --- /dev/null +++ b/proto/mrt/mrtload.Y @@ -0,0 +1,98 @@ + +CF_HDR + +#include "proto/mrt/mrt_load.h" + +CF_DEFINES + +#define MRTLOAD_CFG ((struct mrtload_config *) this_proto) +#define MRT_BGP_CC ((struct bgp_channel_config *) this_channel) + +CF_DECLS + +CF_KEYWORDS(TABLE, FILTER, FILENAME, ADD, MRTLOAD, + IPV4, IPV6, MULTICAST, MPLS, VPN4, VPN6, FLOW4, FLOW6) + + +CF_GRAMMAR + +proto: mrtload_proto; + +mrtload_proto_start: proto_start MRTLOAD +{ + this_proto = proto_config_new(&proto_mrtload, $1); +}; + + +mrtload_proto_item: + proto_item + | TABLE rtable { MRTLOAD_CFG->table_cf = $2; } + | FILENAME text { MRTLOAD_CFG->filename = $2; } + ; + + + +mrt_get_table: + /* empty */ + | TABLE rtable ';' { + MRTLOAD_CFG->table_cf = $2; + log("table_cf %x", $2); + if ($2->addr_type == NET_IP4){ + BGP_CC->igp_table_ip4 = $2; + log("BGP_CC->igp_table_ip4");} + else if ($2->addr_type == NET_IP6){ + BGP_CC->igp_table_ip6 = $2; + log("BGP_CC->igp_table_ip4");} + else + cf_error("Mismatched IGP table type"); + } + ; + +mrtload_tab: + /* empty */ + | '{' mrt_get_table '}' + +mrt_get_bgp_channel: bgp_afi +{ + log("%x", $1); + const struct bgp_af_desc *desc = bgp_get_af_desc($1); + + if (!desc) + cf_error("Unknown AFI/SAFI"); + + this_channel = channel_config_get(&channel_mrtload, desc->name, desc->net, this_proto); + MRTLOAD_CFG->channel_cf = MRT_BGP_CC; + + /* New channel */ + if (!MRT_BGP_CC->desc) + { + MRT_BGP_CC->c.in_filter = FILTER_ACCEPT; + MRT_BGP_CC->c.out_filter = FILTER_REJECT; + MRT_BGP_CC->c.ra_mode = RA_UNDEF; + MRT_BGP_CC->afi = $1; + MRT_BGP_CC->desc = desc; + MRT_BGP_CC->next_hop_keep = 0xff; /* undefined */ + MRT_BGP_CC->gr_able = 0xff; /* undefined */ + MRT_BGP_CC->llgr_able = 0xff; /* undefined */ + MRT_BGP_CC->llgr_time = ~0U; /* undefined */ + MRT_BGP_CC->min_llgr_time = ~0U; /* undefined */ + MRT_BGP_CC->max_llgr_time = ~0U; /* undefined */ + MRT_BGP_CC->aigp = 0xff; /* undefined */ + } +}; + + +mrtload_proto_opts: + /* empty */ + | mrtload_proto_opts mrt_get_bgp_channel mrtload_tab ';' + | mrtload_proto_opts mrtload_proto_item ';' + ; + + +mrtload_proto: + mrtload_proto_start proto_name '{' mrtload_proto_opts '}' { mrtload_check_config(this_proto, MRT_BGP_CC); }; + + +CF_CODE + +CF_END