--- embedaddon/quagga/bgpd/bgp_packet.c 2013/07/21 23:54:37 1.1.1.4 +++ embedaddon/quagga/bgpd/bgp_packet.c 2016/11/02 10:09:10 1.1.1.5 @@ -28,8 +28,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330 #include "log.h" #include "memory.h" #include "sockunion.h" /* for inet_ntop () */ +#include "sockopt.h" #include "linklist.h" #include "plist.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -45,11 +47,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330 #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_encap.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" int stream_put_prefix (struct stream *, struct prefix *); - + /* Set up BGP packet marker and packet type. */ static int bgp_packet_set_marker (struct stream *s, u_char type) @@ -142,18 +145,23 @@ static struct stream * bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; + struct stream *snlri; struct bgp_adj_out *adj; struct bgp_advertise *adv; struct stream *packet; struct bgp_node *rn = NULL; struct bgp_info *binfo = NULL; bgp_size_t total_attr_len = 0; - unsigned long pos; + unsigned long attrlen_pos = 0; + size_t mpattrlen_pos = 0; + size_t mpattr_pos = 0; s = peer->work; stream_reset (s); + snlri = peer->scratch; + stream_reset (snlri); - adv = FIFO_HEAD (&peer->sync[afi][safi]->update); + adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update); while (adv) { @@ -164,7 +172,8 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_ binfo = adv->binfo; /* When remaining space can't include NLRI and it's length. */ - if (STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen)) + if (STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) <= + (BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size(afi,safi,&rn->p))) break; /* If packet is empty, set attribute. */ @@ -173,7 +182,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_ struct prefix_rd *prd = NULL; u_char *tag = NULL; struct peer *from = NULL; - + if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; if (binfo) @@ -182,21 +191,52 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_ if (binfo->extra) tag = binfo->extra->tag; } - + + /* 1: Write the BGP message header - 16 bytes marker, 2 bytes length, + * one byte message type. + */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); - stream_putw (s, 0); - pos = stream_get_endp (s); + + /* 2: withdrawn routes length */ stream_putw (s, 0); - total_attr_len = bgp_packet_attribute (NULL, peer, s, + + /* 3: total attributes length - attrlen_pos stores the position */ + attrlen_pos = stream_get_endp (s); + stream_putw (s, 0); + + /* 4: if there is MP_REACH_NLRI attribute, that should be the first + * attribute, according to draft-ietf-idr-error-handling. Save the + * position. + */ + mpattr_pos = stream_get_endp(s); + + /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */ + total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, - &rn->p, afi, safi, + ((afi == AFI_IP && safi == SAFI_UNICAST) ? + &rn->p : NULL), + afi, safi, from, prd, tag); - stream_putw_at (s, pos, total_attr_len); } if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); - + else + { + /* Encode the prefix in MP_REACH_NLRI attribute */ + struct prefix_rd *prd = NULL; + u_char *tag = NULL; + + if (rn->prn) + prd = (struct prefix_rd *) &rn->prn->p; + if (binfo && binfo->extra) + tag = binfo->extra->tag; + + if (stream_empty(snlri)) + mpattrlen_pos = bgp_packet_mpattr_start(snlri, afi, safi, + adv->baa->attr); + bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, tag); + } if (BGP_DEBUG (update, UPDATE_OUT)) { char buf[INET6_BUFSIZ]; @@ -216,18 +256,28 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_ adj->attr = bgp_attr_intern (adv->baa->attr); adv = bgp_advertise_clean (peer, adj, afi, safi); - - if (! (afi == AFI_IP && safi == SAFI_UNICAST)) - break; } - + if (! stream_empty (s)) { - bgp_packet_set_size (s); - packet = stream_dup (s); + if (!stream_empty(snlri)) + { + bgp_packet_mpattr_end(snlri, mpattrlen_pos); + total_attr_len += stream_get_endp(snlri); + } + + /* set the total attribute length correctly */ + stream_putw_at (s, attrlen_pos, total_attr_len); + + if (!stream_empty(snlri)) + packet = stream_dupcat(s, snlri, mpattr_pos); + else + packet = stream_dup (s); + bgp_packet_set_size (packet); bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); stream_reset (s); + stream_reset (snlri); return packet; } return NULL; @@ -237,7 +287,6 @@ static struct stream * bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; - struct stream *packet; if (DISABLE_BGP_ANNOUNCE) return NULL; @@ -270,13 +319,20 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, s } bgp_packet_set_size (s); - packet = stream_dup (s); - bgp_packet_add (peer, packet); - stream_free (s); - return packet; + bgp_packet_add (peer, s); + return s; } /* Make BGP withdraw packet. */ +/* For ipv4 unicast: + 16-octet marker | 2-octet length | 1-octet type | + 2-octet withdrawn route length | withdrawn prefixes | 2-octet attrlen (=0) +*/ +/* For other afi/safis: + 16-octet marker | 2-octet length | 1-octet type | + 2-octet withdrawn route length (=0) | 2-octet attrlen | + mp_unreach attr type | attr len | afi | safi | withdrawn prefixes +*/ static struct stream * bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) { @@ -285,44 +341,54 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, saf struct bgp_adj_out *adj; struct bgp_advertise *adv; struct bgp_node *rn; - unsigned long pos; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; + size_t mp_start = 0; + size_t attrlen_pos = 0; + size_t mplen_pos = 0; + u_char first_time = 1; s = peer->work; stream_reset (s); - while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) + while ((adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) { assert (adv->rn); adj = adv->adj; rn = adv->rn; - if (STREAM_REMAIN (s) + if (STREAM_REMAIN (s) < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) break; if (stream_empty (s)) { bgp_packet_set_marker (s, BGP_MSG_UPDATE); - stream_putw (s, 0); + stream_putw (s, 0); /* unfeasible routes length */ } + else + first_time = 0; if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); else { struct prefix_rd *prd = NULL; - + if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; - pos = stream_get_endp (s); - stream_putw (s, 0); - total_attr_len - = bgp_packet_withdraw (peer, s, &rn->p, afi, safi, prd, NULL); - - /* Set total path attribute length. */ - stream_putw_at (s, pos, total_attr_len); + + /* If first time, format the MP_UNREACH header */ + if (first_time) + { + attrlen_pos = stream_get_endp (s); + /* total attr length = 0 for now. reevaluate later */ + stream_putw (s, 0); + mp_start = stream_get_endp (s); + mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); + } + + bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, NULL); } if (BGP_DEBUG (update, UPDATE_OUT)) @@ -339,20 +405,26 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, saf bgp_adj_out_remove (rn, adj, peer, afi, safi); bgp_unlock_node (rn); - - if (! (afi == AFI_IP && safi == SAFI_UNICAST)) - break; } if (! stream_empty (s)) { if (afi == AFI_IP && safi == SAFI_UNICAST) { - unfeasible_len + unfeasible_len = stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN; stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len); stream_putw (s, 0); } + else + { + /* Set the mp_unreach attr's length */ + bgp_packet_mpunreach_end(s, mplen_pos); + + /* Set total path attribute length. */ + total_attr_len = stream_get_endp(s) - mp_start; + stream_putw_at (s, attrlen_pos, total_attr_len); + } bgp_packet_set_size (s); packet = stream_dup (s); bgp_packet_add (peer, packet); @@ -368,7 +440,6 @@ bgp_default_update_send (struct peer *peer, struct att afi_t afi, safi_t safi, struct peer *from) { struct stream *s; - struct stream *packet; struct prefix p; unsigned long pos; bgp_size_t total_attr_len; @@ -378,10 +449,8 @@ bgp_default_update_send (struct peer *peer, struct att if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); -#ifdef HAVE_IPV6 else str2prefix ("::/0", &p); -#endif /* HAVE_IPV6 */ /* Logging the attribute. */ if (BGP_DEBUG (update, UPDATE_OUT)) @@ -419,16 +488,13 @@ bgp_default_update_send (struct peer *peer, struct att /* Set size. */ bgp_packet_set_size (s); - packet = stream_dup (s); - stream_free (s); - /* Dump packet if debug option is set. */ #ifdef DEBUG /* bgp_packet_dump (packet); */ #endif /* DEBUG */ /* Add packet to the peer. */ - bgp_packet_add (peer, packet); + bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } @@ -437,25 +503,23 @@ void bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; - struct stream *packet; struct prefix p; - unsigned long pos; + unsigned long attrlen_pos = 0; unsigned long cp; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; + size_t mp_start = 0; + size_t mplen_pos = 0; if (DISABLE_BGP_ANNOUNCE) return; if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); -#ifdef HAVE_IPV6 else str2prefix ("::/0", &p); -#endif /* HAVE_IPV6 */ total_attr_len = 0; - pos = 0; if (BGP_DEBUG (update, UPDATE_OUT)) { @@ -490,21 +554,24 @@ bgp_default_withdraw_send (struct peer *peer, afi_t af } else { - pos = stream_get_endp (s); + attrlen_pos = stream_get_endp (s); stream_putw (s, 0); - total_attr_len = bgp_packet_withdraw (peer, s, &p, afi, safi, NULL, NULL); + mp_start = stream_get_endp (s); + mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); + bgp_packet_mpunreach_prefix(s, &p, afi, safi, NULL, NULL); + /* Set the mp_unreach attr's length */ + bgp_packet_mpunreach_end(s, mplen_pos); + /* Set total path attribute length. */ - stream_putw_at (s, pos, total_attr_len); + total_attr_len = stream_get_endp(s) - mp_start; + stream_putw_at (s, attrlen_pos, total_attr_len); } bgp_packet_set_size (s); - packet = stream_dup (s); - stream_free (s); - /* Add packet to the peer. */ - bgp_packet_add (peer, packet); + bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } @@ -525,7 +592,7 @@ bgp_write_packet (struct peer *peer) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw); + adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->withdraw); if (adv) { s = bgp_withdraw_packet (peer, afi, safi); @@ -537,13 +604,17 @@ bgp_write_packet (struct peer *peer) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - adv = FIFO_HEAD (&peer->sync[afi][safi]->update); + adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update); if (adv) { if (adv->binfo && adv->binfo->uptime < peer->synctime) { if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV) && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV) + && ! (CHECK_FLAG (adv->binfo->peer->cap, + PEER_CAP_RESTART_BIT_RCV) && + CHECK_FLAG (adv->binfo->peer->cap, + PEER_CAP_RESTART_BIT_ADV)) && ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE) && safi != SAFI_MPLS_VPN) { @@ -593,7 +664,7 @@ bgp_write_proceed (struct peer *peer) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) - if ((adv = FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) + if ((adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) if (adv->binfo->uptime < peer->synctime) return 1; @@ -719,14 +790,15 @@ bgp_write_notify (struct peer *peer) return 0; assert (stream_get_endp (s) >= BGP_HEADER_SIZE); - /* Put socket in blocking mode. */ - val = fcntl (peer->fd, F_GETFL, 0); - fcntl (peer->fd, F_SETFL, val & ~O_NONBLOCK); - /* Stop collecting data within the socket */ sockopt_cork (peer->fd, 0); + /* socket is in nonblocking mode, if we can't deliver the NOTIFY, well, + * we only care about getting a clean shutdown at this point. */ ret = write (peer->fd, STREAM_DATA (s), stream_get_endp (s)); + + /* only connection reset/close gets counted as TCP_fatal_error, failure + * to write the entire NOTIFY doesn't get different FSM treatment */ if (ret <= 0) { BGP_EVENT_ADD (peer, TCP_fatal_error); @@ -903,8 +975,13 @@ bgp_notify_send_with_data (struct peer *peer, u_char c } } bgp_notify_print (peer, &bgp_notify, "sending"); + if (bgp_notify.data) - XFREE (MTYPE_TMP, bgp_notify.data); + { + XFREE (MTYPE_TMP, bgp_notify.data); + bgp_notify.data = NULL; + bgp_notify.length = 0; + } } if (BGP_DEBUG (normal, NORMAL)) @@ -954,7 +1031,6 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, u_char orf_type, u_char when_to_refresh, int remove) { struct stream *s; - struct stream *packet; int length; struct bgp_filter *filter; int orf_refresh = 0; @@ -1035,12 +1111,8 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length); } - /* Make real packet. */ - packet = stream_dup (s); - stream_free (s); - /* Add packet to the peer. */ - bgp_packet_add (peer, packet); + bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } @@ -1051,7 +1123,6 @@ bgp_capability_send (struct peer *peer, afi_t afi, saf int capability_code, int action) { struct stream *s; - struct stream *packet; int length; /* Adjust safi code. */ @@ -1082,12 +1153,9 @@ bgp_capability_send (struct peer *peer, afi_t afi, saf /* Set packet size. */ length = bgp_packet_set_size (s); - /* Make real packet. */ - packet = stream_dup (s); - stream_free (s); /* Add packet to the peer. */ - bgp_packet_add (peer, packet); + bgp_packet_add (peer, s); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s send message type %d, length (incl. header) %d", @@ -1095,7 +1163,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, saf BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } - + /* RFC1771 6.8 Connection collision detection. */ static int bgp_collision_detect (struct peer *new, struct in_addr remote_id) @@ -1485,7 +1553,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); + BGP_NOTIFY_OPEN_UNSPECIFIC); return ret; } } @@ -1512,6 +1580,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* Get sockname. */ bgp_getsockname (peer); + peer->rtt = sockopt_tcp_rtt (peer->fd); BGP_EVENT_ADD (peer, Receive_OPEN_message); @@ -1522,11 +1591,29 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) return 0; } +/* 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; @@ -1534,10 +1621,16 @@ 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 i; + + 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) @@ -1551,10 +1644,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; s = peer->ibuf; @@ -1591,17 +1681,14 @@ bgp_update_receive (struct peer *peer, bgp_size_t size /* Unfeasible Route packet format check. */ if (withdraw_len > 0) { - ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), withdraw_len); - 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_DEBUG (packet, PACKET_RECV)) zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host); - withdraw.afi = AFI_IP; - withdraw.safi = SAFI_UNICAST; - withdraw.nlri = stream_pnt (s); - withdraw.length = withdraw_len; stream_forward_getp (s, withdraw_len); } @@ -1647,9 +1734,13 @@ 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) - return -1; + { + bgp_attr_unintern_sub (&attr); + bgp_attr_flush (&attr); + return -1; + } } /* Logging the attribute. */ @@ -1678,183 +1769,129 @@ bgp_update_receive (struct peer *peer, bgp_size_t size if (update_len) { - /* Check NLRI packet format and prefix length. */ - ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len); - if (ret < 0) - { - bgp_attr_unintern_sub (&attr); - return -1; - } - /* 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; + stream_forward_getp (s, update_len); } - - /* NLRI is processed only when the peer is configured specific - Address Family and Subsequent Address Family. */ - if (peer->afc[AFI_IP][SAFI_UNICAST]) + + /* Parse any given NLRIs */ + for (i = NLRI_UPDATE; i < NLRI_TYPE_MAX; i++) { - if (withdraw.length) - bgp_nlri_parse (peer, NULL, &withdraw); - - if (update.length) - { - /* We check well-known attribute only for IPv4 unicast - update. */ - ret = bgp_attr_check (peer, &attr); - if (ret < 0) - { - bgp_attr_unintern_sub (&attr); - return -1; - } - - 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 */ - SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST], - PEER_STATUS_EOR_RECEIVED); - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP][SAFI_UNICAST]) - bgp_clear_stale_route (peer, AFI_IP, SAFI_UNICAST); - - if (BGP_DEBUG (normal, NORMAL)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Unicast from %s", - peer->host); - } + /* 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)) + { + plog_info (peer->log, + "%s [Info] UPDATE with unsupported AFI/SAFI %u/%u", + peer->host, nlris[i].afi, nlris[i].safi); + continue; + } + + /* NLRI is processed only when the peer is configured specific + Address Family and Subsequent Address Family. */ + if (!peer->afc[nlris[i].afi][nlris[i].safi]) + { + plog_info (peer->log, + "%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]); + } + + if (nlri_ret < 0) + { + plog_err (peer->log, + "%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; + } } - if (peer->afc[AFI_IP][SAFI_MULTICAST]) + + /* EoR checks. + * + * Non-MP IPv4/Unicast EoR is a completely empty UPDATE + * and MP EoR should have only an empty MP_UNREACH + */ + if (!update_len && !withdraw_len + && nlris[NLRI_MP_UPDATE].length == 0) { - 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) - { + afi_t afi = 0; + safi_t safi; + + /* Non-MP IPv4/Unicast is a completely empty UPDATE - already + * checked update and withdraw NLRI lengths are 0. + */ + if (!attribute_len) + { + afi = AFI_IP; + safi = SAFI_UNICAST; + } + /* otherwise MP AFI/SAFI is an empty update, other than an empty + * MP_UNREACH_NLRI attr (with an AFI/SAFI we recognise). + */ + 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 */ - SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST], + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED); /* NSF delete stale route */ - if (peer->nsf[AFI_IP][SAFI_MULTICAST]) - bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST); + if (peer->nsf[afi][safi]) + bgp_clear_stale_route (peer, afi, safi); if (BGP_DEBUG (normal, NORMAL)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Multicast from %s", - peer->host); - } + zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for %s from %s", + peer->host, afi_safi_print (afi, safi)); + } } - if (peer->afc[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 */ - SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED); - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP6][SAFI_UNICAST]) - bgp_clear_stale_route (peer, AFI_IP6, SAFI_UNICAST); - - if (BGP_DEBUG (normal, NORMAL)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Unicast from %s", - peer->host); - } - } - if (peer->afc[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 */ - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP6][SAFI_MULTICAST]) - bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST); - - if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Multicast from %s", - peer->host); - } - } - if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) - { - if (mp_update.length - && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpnv4 (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_vpnv4 (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - - if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s", - peer->host); - } - } - + /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ bgp_attr_unintern_sub (&attr); + bgp_attr_flush (&attr); /* If peering is stopped due to some reason, do not generate BGP event. */ @@ -1926,7 +1963,11 @@ bgp_notify_receive (struct peer *peer, bgp_size_t size bgp_notify_print(peer, &bgp_notify, "received"); if (bgp_notify.data) - XFREE (MTYPE_TMP, bgp_notify.data); + { + XFREE (MTYPE_TMP, bgp_notify.data); + bgp_notify.data = NULL; + bgp_notify.length = 0; + } } /* peer count update */ @@ -1962,7 +2003,6 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size { afi_t afi; safi_t safi; - u_char reserved; struct stream *s; /* If peer does not have the capability, send notification. */ @@ -1990,7 +2030,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size /* Parse packet. */ afi = stream_getw (s); - reserved = stream_getc (s); + /* reserved byte */ + stream_getc (s); safi = stream_getc (s); if (BGP_DEBUG (normal, NORMAL)) @@ -2042,8 +2083,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) { - u_char *p_pnt = stream_pnt (s); - u_char *p_end = stream_pnt (s) + orf_len; + uint8_t *p_pnt = stream_pnt (s); + uint8_t *p_end = stream_pnt (s) + orf_len; struct orf_prefix orfp; u_char common = 0; u_int32_t seq; @@ -2080,10 +2121,10 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd Remove-All pfxlist ORF request", peer->host); - prefix_bgp_orf_remove_all (name); + prefix_bgp_orf_remove_all (afi, name); break; } - ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ; + ok = ((size_t)(p_end - p_pnt) >= sizeof(u_int32_t)) ; if (ok) { memcpy (&seq, p_pnt, sizeof (u_int32_t)); @@ -2135,18 +2176,18 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size ret = prefix_bgp_orf_set (name, afi, &orfp, (common & ORF_COMMON_PART_DENY ? 0 : 1 ), (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); - - if (!ok || (ret != CMD_SUCCESS)) + + if (!ok || (ok && ret != CMD_SUCCESS)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Received misformatted prefixlist ORF." " Remove All pfxlist", peer->host); - prefix_bgp_orf_remove_all (name); + prefix_bgp_orf_remove_all (afi, name); break; } } peer->orf_plist[afi][safi] = - prefix_list_lookup (AFI_ORF_PREFIX, name); + prefix_bgp_orf_lookup (afi, name); } stream_forward_getp (s, orf_len); } @@ -2172,11 +2213,9 @@ bgp_capability_msg_parse (struct peer *peer, u_char *p struct capability_mp_data mpc; struct capability_header *hdr; u_char action; - struct bgp *bgp; afi_t afi; safi_t safi; - bgp = peer->bgp; end = pnt + length; while (pnt < end) @@ -2310,7 +2349,7 @@ bgp_capability_receive (struct peer *peer, bgp_size_t /* Parse packet. */ return bgp_capability_msg_parse (peer, pnt, size); } - + /* BGP read utility function. */ static int bgp_read_packet (struct peer *peer)