diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index dd9740843f..664c4b40bb 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1320,11 +1320,29 @@ bgp_update_explicit_eors (struct peer *peer) bgp_check_update_delay(peer->bgp); } +/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers */ +int +bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) +{ + switch (packet->safi) + { + case SAFI_UNICAST: + case SAFI_MULTICAST: + return bgp_nlri_parse_ip (peer, attr, packet); + case SAFI_MPLS_VPN: + case SAFI_MPLS_LABELED_VPN: + return bgp_nlri_parse_vpn (peer, attr, packet); + case SAFI_ENCAP: + return bgp_nlri_parse_encap (peer, attr, packet); + } + return -1; +} + /* Parse BGP Update packet and make attribute object. */ static int bgp_update_receive (struct peer *peer, bgp_size_t size) { - int ret; + int ret, nlri_ret; u_char *end; struct stream *s; struct attr attr; @@ -1332,12 +1350,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) bgp_size_t attribute_len; bgp_size_t update_len; bgp_size_t withdraw_len; - struct bgp_nlri update; - struct bgp_nlri withdraw; - struct bgp_nlri mp_update; - struct bgp_nlri mp_withdraw; int num_pfx_adv, num_pfx_wd; + enum NLRI_TYPES { + NLRI_UPDATE, + NLRI_WITHDRAW, + NLRI_MP_UPDATE, + NLRI_MP_WITHDRAW, + NLRI_TYPE_MAX + }; + struct bgp_nlri nlris[NLRI_TYPE_MAX]; + /* Status must be Established. */ if (peer->status != Established) { @@ -1350,10 +1373,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Set initial values. */ memset (&attr, 0, sizeof (struct attr)); memset (&extra, 0, sizeof (struct attr_extra)); - memset (&update, 0, sizeof (struct bgp_nlri)); - memset (&withdraw, 0, sizeof (struct bgp_nlri)); - memset (&mp_update, 0, sizeof (struct bgp_nlri)); - memset (&mp_withdraw, 0, sizeof (struct bgp_nlri)); + memset (&nlris, 0, sizeof (nlris)); attr.extra = &extra; num_pfx_adv = num_pfx_wd = 0; memset (peer->rcvd_attr_str, 0, BUFSIZ); @@ -1393,13 +1413,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Unfeasible Route packet format check. */ if (withdraw_len > 0) { - withdraw.afi = AFI_IP; - withdraw.safi = SAFI_UNICAST; - withdraw.nlri = stream_pnt (s); - withdraw.length = withdraw_len; - ret = bgp_nlri_sanity_check (peer, &withdraw, &num_pfx_wd); - if (ret < 0) - return -1; + nlris[NLRI_WITHDRAW].afi = AFI_IP; + nlris[NLRI_WITHDRAW].safi = SAFI_UNICAST; + nlris[NLRI_WITHDRAW].nlri = stream_pnt (s); + nlris[NLRI_WITHDRAW].length = withdraw_len; + + if (bgp_nlri_sanity_check (peer, &nlris[NLRI_WITHDRAW], &num_pfx_wd) < 0) + { + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } stream_forward_getp (s, withdraw_len); } @@ -1446,7 +1470,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (attribute_len) { attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len, - &mp_update, &mp_withdraw); + &nlris[NLRI_MP_UPDATE], &nlris[NLRI_MP_WITHDRAW]); if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) { bgp_attr_unintern_sub (&attr); @@ -1478,15 +1502,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (update_len) { /* Set NLRI portion to structure. */ - update.afi = AFI_IP; - update.safi = SAFI_UNICAST; - update.nlri = stream_pnt (s); - update.length = update_len; + nlris[NLRI_UPDATE].afi = AFI_IP; + nlris[NLRI_UPDATE].safi = SAFI_UNICAST; + nlris[NLRI_UPDATE].nlri = stream_pnt (s); + nlris[NLRI_UPDATE].length = update_len; /* Check NLRI packet format and prefix length. */ - ret = bgp_nlri_sanity_check (peer, &update, &num_pfx_adv); + ret = bgp_nlri_sanity_check (peer, &nlris[NLRI_UPDATE], &num_pfx_adv); if (ret < 0) { + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); bgp_attr_unintern_sub (&attr); return -1; } @@ -1499,263 +1525,115 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) peer->host, withdraw_len, num_pfx_wd, attribute_len, update_len, num_pfx_adv); - /* NLRI is processed only when the the corresponding address-family - * has been negotiated with the peer. + /* Parse any given NLRIs */ + for (int i = NLRI_UPDATE; i < NLRI_TYPE_MAX; i++) + { + /* We use afi and safi as indices into tables and what not. It would + * be impossible, at this time, to support unknown afi/safis. And + * anyway, the peer needs to be configured to enable the afi/safi + * explicitly which requires UI support. + * + * Ignore unknown afi/safi NLRIs. + * + * Note: This means nlri[x].afi/safi still can not be trusted for + * indexing later in this function! + * + * Note2: This will also remap the wire code-point for VPN safi to the + * internal safi_t point, as needs be. + */ + if(!bgp_afi_safi_valid_indices (nlris[i].afi, &nlris[i].safi)) + { + zlog_info ("%s [Info] UPDATE with unsupported AFI/SAFI %u/%u", + peer->host, nlris[i].afi, nlris[i].safi); + continue; + } + + /* NLRI is processed iff the peer if configured for the specific afi/safi */ + if (!peer->afc[nlris[i].afi][nlris[i].safi]) + { + zlog_info ("%s [Info] UPDATE for non-enabled AFI/SAFI %u/%u", + peer->host, nlris[i].afi, nlris[i].safi); + continue; + } + + /* EoR handled later */ + if (nlris[i].length == 0) + continue; + + switch (i) + { + case NLRI_UPDATE: + case NLRI_MP_UPDATE: + nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i]); + break; + case NLRI_WITHDRAW: + case NLRI_MP_WITHDRAW: + nlri_ret = bgp_nlri_parse (peer, NULL, &nlris[i]); + break; + default: + nlri_ret = -1; + } + + if (nlri_ret < 0) + { + zlog_err("%s [Error] Error parsing NLRI", peer->host); + if (peer->status == Established) + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + i <= NLRI_WITHDRAW ? BGP_NOTIFY_UPDATE_INVAL_NETWORK + : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); + bgp_attr_unintern_sub (&attr); + return -1; + } + } + + /* EoR checks + * + * Non-MP IPv4/Unicast EoR is a completely empty UPDATE + * and MP EoR should have only an empty MP_UNREACH */ - if (peer->afc_nego[AFI_IP][SAFI_UNICAST]) + if (!update_len && !withdraw_len + && nlris[NLRI_MP_UPDATE].length == 0) { - if (withdraw.length) - bgp_nlri_parse (peer, NULL, &withdraw); + afi_t afi = 0; + safi_t safi; - if (update.length) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update); - - if (mp_update.length - && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, NULL, &mp_withdraw); - - if (! attribute_len && ! withdraw_len) - { - /* End-of-RIB received */ - if (!CHECK_FLAG(peer->af_sflags[AFI_IP][SAFI_UNICAST], - PEER_STATUS_EOR_RECEIVED)) - { - SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST], - PEER_STATUS_EOR_RECEIVED); - bgp_update_explicit_eors(peer); - } - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP][SAFI_UNICAST]) - bgp_clear_stale_route (peer, AFI_IP, SAFI_UNICAST); - - if (bgp_debug_neighbor_events(peer)) - zlog_debug ("rcvd End-of-RIB for IPv4 Unicast from %s", peer->host); - } - } - if (peer->afc_nego[AFI_IP][SAFI_MULTICAST]) - { - if (mp_update.length - && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MULTICAST - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - if (!CHECK_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST], - PEER_STATUS_EOR_RECEIVED)) - { - SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST], - PEER_STATUS_EOR_RECEIVED); - bgp_update_explicit_eors(peer); - } - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP][SAFI_MULTICAST]) - bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST); - - if (bgp_debug_neighbor_events(peer)) - zlog_debug ("rcvd End-of-RIB for IPv4 Multicast from %s", peer->host); - } - } - if (peer->afc_nego[AFI_IP6][SAFI_UNICAST]) - { - if (mp_update.length - && mp_update.afi == AFI_IP6 - && mp_update.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_UNICAST - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - if (!CHECK_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], - PEER_STATUS_EOR_RECEIVED)) - { - SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED); - bgp_update_explicit_eors(peer); - } - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP6][SAFI_UNICAST]) - bgp_clear_stale_route (peer, AFI_IP6, SAFI_UNICAST); - - if (bgp_debug_neighbor_events(peer)) - zlog_debug ("rcvd End-of-RIB for IPv6 Unicast from %s", peer->host); - } - } - if (peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) - { - if (mp_update.length - && mp_update.afi == AFI_IP6 - && mp_update.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MULTICAST - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - if (!CHECK_FLAG (peer->af_sflags[AFI_IP6][SAFI_MULTICAST], - PEER_STATUS_EOR_RECEIVED)) - { - SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_MULTICAST], PEER_STATUS_EOR_RECEIVED); - bgp_update_explicit_eors(peer); - } - - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP6][SAFI_MULTICAST]) - bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST); - - if (bgp_debug_neighbor_events(peer)) - zlog_debug ("rcvd End-of-RIB for IPv6 Multicast from %s", peer->host); - } - } - if (peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]) - { - if (mp_update.length - && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpn (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpn (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN - && mp_withdraw.length == 0) - { + /* Non-MP IPv4/Unicast is a completely emtpy UPDATE - already checked + * update and withdraw NLRI lengths are 0. + */ + if (!attribute_len) + { + afi = AFI_IP; + safi = SAFI_UNICAST; + } + else if (attr.flag == BGP_ATTR_MP_UNREACH_NLRI + && nlris[NLRI_MP_WITHDRAW].length == 0 + && bgp_afi_safi_valid_indices (nlris[NLRI_MP_WITHDRAW].afi, + &nlris[NLRI_MP_WITHDRAW].safi)) + { + afi = nlris[NLRI_MP_WITHDRAW].afi; + safi = nlris[NLRI_MP_WITHDRAW].safi; + } + if (afi && peer->afc[afi][safi]) + { /* End-of-RIB received */ - if (!CHECK_FLAG (peer->af_sflags[AFI_IP][SAFI_MPLS_VPN], - PEER_STATUS_EOR_RECEIVED)) + if (!CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) { - SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MPLS_VPN], PEER_STATUS_EOR_RECEIVED); + SET_FLAG (peer->af_sflags[afi][safi], + PEER_STATUS_EOR_RECEIVED); bgp_update_explicit_eors(peer); } + /* NSF delete stale route */ + if (peer->nsf[afi][safi]) + bgp_clear_stale_route (peer, afi, safi); + if (bgp_debug_neighbor_events(peer)) - zlog_debug ("rcvd End-of-RIB for VPNv4 Unicast from %s", peer->host); - } - } - if (peer->afc[AFI_IP6][SAFI_MPLS_VPN]) - { - if (mp_update.length - && mp_update.afi == AFI_IP6 - && mp_update.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpn (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpn (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - if (!CHECK_FLAG (peer->af_sflags[AFI_IP6][SAFI_MPLS_VPN], - PEER_STATUS_EOR_RECEIVED)) { - SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_MPLS_VPN], PEER_STATUS_EOR_RECEIVED); - bgp_update_explicit_eors(peer); + zlog_debug ("rcvd End-of-RIB for %s from %s", + afi_safi_print (afi, safi), peer->host); } - - if (bgp_debug_neighbor_events(peer)) - zlog_debug ("rcvd End-of-RIB for VPNv6 Unicast from %s", peer->host); - } - } - if (peer->afc[AFI_IP][SAFI_ENCAP]) - { - if (mp_update.length - && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_ENCAP - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - if (!CHECK_FLAG (peer->af_sflags[AFI_IP][SAFI_ENCAP], - PEER_STATUS_EOR_RECEIVED)) - { - SET_FLAG (peer->af_sflags[AFI_IP][SAFI_ENCAP], PEER_STATUS_EOR_RECEIVED); - bgp_update_explicit_eors(peer); - } - - if (bgp_debug_neighbor_events(peer)) - zlog_debug ("rcvd End-of-RIB for IPv4 Encap from %s", peer->host); - } - } - if (peer->afc[AFI_IP6][SAFI_ENCAP]) - { - if (mp_update.length - && mp_update.afi == AFI_IP6 - && mp_update.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_ENCAP - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - if (!CHECK_FLAG (peer->af_sflags[AFI_IP6][SAFI_ENCAP], - PEER_STATUS_EOR_RECEIVED)) - { - SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_ENCAP], PEER_STATUS_EOR_RECEIVED); - bgp_update_explicit_eors(peer); - } - - if (bgp_debug_neighbor_events(peer)) - zlog_debug ("rcvd End-of-RIB for IPv6 Encap from %s", peer->host); - } + } } /* Everything is done. We unintern temporary structures which diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index b699866b01..78855c3425 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -54,6 +54,9 @@ extern void bgp_default_update_send (struct peer *, struct attr *, extern void bgp_default_withdraw_send (struct peer *, afi_t, safi_t); extern int bgp_capability_receive (struct peer *, bgp_size_t); + +extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); + extern void bgp_update_restarted_peers (struct peer *); extern void bgp_update_implicit_eors (struct peer *); extern void bgp_check_update_delay (struct bgp *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 57faf46f15..e744de10c4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3405,7 +3405,8 @@ bgp_addpath_encode_rx (struct peer *peer, afi_t afi, safi_t safi) /* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr value. */ int -bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) +bgp_nlri_parse_ip (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet) { u_char *pnt; u_char *lim; @@ -3619,6 +3620,7 @@ bgp_nlri_sanity_check (struct peer *peer, struct bgp_nlri *nlri, int *numpfx) switch (nlri->safi) { case SAFI_MPLS_LABELED_VPN: + case SAFI_MPLS_VPN: return bgp_nlri_sanity_check_vpn (peer, nlri, numpfx); case SAFI_UNICAST: case SAFI_MULTICAST: diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index b76393ecd6..5b1893cdd6 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -265,7 +265,7 @@ extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t extern void bgp_info_path_with_addpath_rx_str (struct bgp_info *ri, char *buf); extern int bgp_nlri_sanity_check (struct peer *, struct bgp_nlri *, int *); -extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); +extern int bgp_nlri_parse_ip (struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 2e6b892b70..dfb8ed9f7a 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -34,6 +34,7 @@ #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_route.h" +#include "bgpd/bgp_packet.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_nexthop.h" @@ -725,16 +726,10 @@ parse_test (struct peer *peer, struct test_segment *t, int type) if (!parse_ret) { - int (*f) (struct peer *, struct attr *, struct bgp_nlri *) - = bgp_nlri_parse; - - if (t->safi == SAFI_MPLS_LABELED_VPN) - f = bgp_nlri_parse_vpn; - if (type == BGP_ATTR_MP_REACH_NLRI) - nlri_ret = f (peer, &attr, &nlri); + nlri_ret = bgp_nlri_parse (peer, &attr, &nlri); else - nlri_ret = f (peer, NULL, &nlri); + nlri_ret = bgp_nlri_parse (peer, NULL, &nlri); } handle_result (peer, t, parse_ret, nlri_ret);