diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 24ba00ba..0688c7cd 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1845,6 +1845,10 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old) { struct ea_list *attrs = bgp_update_attrs(p, c, new, new->attrs->eattrs, bgp_linpool2); + /* Error during attribute processing */ + if (!attrs) + log(L_ERR "%s: Invalid route %N withdrawn", p->p.name, n->n.addr); + /* If attributes are invalid, we fail back to withdraw */ buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c); path = new->attrs->src->global_id; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 5e025ccd..db05b693 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -423,6 +423,7 @@ struct bgp_parse_state { int as4_session; int add_path; int mpls; + int reach_nlri_step; u32 attrs_seen[256/32]; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 99b5d5b4..9843a9e0 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1335,7 +1335,7 @@ bgp_update_next_hop_none(struct bgp_export_state *s, eattr *a, ea_list **to) */ static void -bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0) +bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a0) { if (path_id != s->last_id) { @@ -1348,6 +1348,10 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0) if (!a0) { + /* Route update was changed to withdraw */ + if (s->err_withdraw && s->reach_nlri_step) + REPORT("Invalid route %N withdrawn", n); + /* Route withdraw */ rte_update3(&s->channel->c, n, NULL, s->last_src); return; @@ -2543,6 +2547,8 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) 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);