diff options
Diffstat (limited to 'bgpd/bgp_packet.c')
-rw-r--r-- | bgpd/bgp_packet.c | 796 |
1 files changed, 445 insertions, 351 deletions
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 740b0f1c..3fd584c5 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -103,8 +103,8 @@ bgp_packet_delete (struct peer *peer) } /* Check file descriptor whether connect is established. */ -static void -bgp_connect_check (struct peer *peer) +int +bgp_connect_check (struct peer *peer, int change_state) { int status; socklen_t slen; @@ -121,22 +121,25 @@ bgp_connect_check (struct peer *peer) /* If getsockopt is fail, this is fatal error. */ if (ret < 0) { - zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect"); + zlog_info ("can't get sockopt for nonblocking connect"); BGP_EVENT_ADD (peer, TCP_fatal_error); - return; + return -1; } /* When status is 0 then TCP connection is established. */ if (status == 0) { BGP_EVENT_ADD (peer, TCP_connection_open); + return 1; } else { - if (BGP_DEBUG (events, EVENTS)) - plog_debug (peer->log, "%s [Event] Connect failed (%s)", - peer->host, safe_strerror (errno)); - BGP_EVENT_ADD (peer, TCP_connection_open_failed); + if (bgp_debug_neighbor_events(peer)) + zlog_debug ("%s [Event] Connect failed (%s)", + peer->host, safe_strerror (errno)); + if (change_state) + BGP_EVENT_ADD (peer, TCP_connection_open_failed); + return 0; } } @@ -153,8 +156,13 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) struct bgp_info *binfo = NULL; bgp_size_t total_attr_len = 0; unsigned long attrlen_pos = 0; + int space_remaining = 0; + int space_needed = 0; size_t mpattrlen_pos = 0; size_t mpattr_pos = 0; + int num_pfx_adv = 0; + char send_attr_str[BUFSIZ]; + int send_attr_printed = 0; s = peer->work; stream_reset (s); @@ -171,9 +179,12 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) if (adv->binfo) binfo = adv->binfo; + space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) - + BGP_MAX_PACKET_SIZE_OVERFLOW; + space_needed = BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p); + /* When remaining space can't include NLRI and it's length. */ - if (STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) <= - (BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size(afi,safi,&rn->p))) + if (space_remaining < space_needed) break; /* If packet is empty, set attribute. */ @@ -217,6 +228,29 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) &rn->p : NULL), afi, safi, from, prd, tag); + space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) - + BGP_MAX_PACKET_SIZE_OVERFLOW; + space_needed = BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p);; + + /* If the attributes alone do not leave any room for NLRI then + * return */ + if (space_remaining < space_needed) + { + zlog_err ("%s cannot send UPDATE, the attributes do not leave " + "room for NLRI", peer->host); + /* Flush the FIFO update queue */ + while (adv) + adv = bgp_advertise_clean (peer, adv->adj, afi, safi); + return NULL; + } + + if (BGP_DEBUG (update, UPDATE_OUT) || + BGP_DEBUG (update, UPDATE_PREFIX)) + { + memset (send_attr_str, 0, BUFSIZ); + send_attr_printed = 0; + bgp_dump_attr (peer, adv->baa->attr, send_attr_str, BUFSIZ); + } } if (afi == AFI_IP && safi == SAFI_UNICAST) @@ -237,14 +271,21 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) adv->baa->attr); bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, tag); } - if (BGP_DEBUG (update, UPDATE_OUT)) + num_pfx_adv++; + + if (bgp_debug_update(peer, &rn->p, 0)) { + if (!send_attr_printed) + { + zlog_debug ("%s send UPDATE w/ attr: %s", peer->host, send_attr_str); + send_attr_printed = 1; + } char buf[INET6_BUFSIZ]; - zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d", - peer->host, - inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), - rn->p.prefixlen); + zlog_debug ("%s send UPDATE %s/%d", + peer->host, + inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), + rn->p.prefixlen); } /* Synchnorize attribute. */ @@ -274,8 +315,11 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) else packet = stream_dup (s); bgp_packet_set_size (packet); + if (BGP_DEBUG (update, UPDATE_OUT)) + zlog_debug("%s form UPDATE (adv) total len %zd numPfx %d", + peer->host, + (stream_get_endp (s) - stream_get_getp (s)), num_pfx_adv); bgp_packet_add (peer, packet); - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); stream_reset (s); stream_reset (snlri); return packet; @@ -291,7 +335,7 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) if (DISABLE_BGP_ANNOUNCE) return NULL; - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi), peer->host); s = stream_new (BGP_MAX_PACKET_SIZE); @@ -347,6 +391,9 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) size_t attrlen_pos = 0; size_t mplen_pos = 0; u_char first_time = 1; + int space_remaining = 0; + int space_needed = 0; + int num_pfx_wd = 0; s = peer->work; stream_reset (s); @@ -357,8 +404,12 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) adj = adv->adj; rn = adv->rn; - if (STREAM_REMAIN (s) - < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) + space_remaining = STREAM_REMAIN (s) - + BGP_MAX_PACKET_SIZE_OVERFLOW; + space_needed = (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p)); + + if (space_remaining < space_needed) break; if (stream_empty (s)) @@ -390,15 +441,16 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, NULL); } + num_pfx_wd++; - if (BGP_DEBUG (update, UPDATE_OUT)) + if (bgp_debug_update(peer, &rn->p, 0)) { char buf[INET6_BUFSIZ]; - zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", - peer->host, - inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), - rn->p.prefixlen); + zlog_debug ("%s send UPDATE %s/%d -- unreachable", + peer->host, + inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), + rn->p.prefixlen); } peer->scount[afi][safi]--; @@ -426,6 +478,10 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) stream_putw_at (s, attrlen_pos, total_attr_len); } bgp_packet_set_size (s); + if (BGP_DEBUG (update, UPDATE_OUT)) + zlog_debug("%s form UPDATE (wd) total len %zd numPfx %d", + peer->host, + (stream_get_endp (s) - stream_get_getp (s)), num_pfx_wd); packet = stream_dup (s); bgp_packet_add (peer, packet); stream_reset (s); @@ -453,16 +509,16 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, str2prefix ("::/0", &p); /* Logging the attribute. */ - if (BGP_DEBUG (update, UPDATE_OUT)) + if (bgp_debug_update(peer, &p, 0)) { char attrstr[BUFSIZ]; char buf[INET6_BUFSIZ]; attrstr[0] = '\0'; bgp_dump_attr (peer, attr, attrstr, BUFSIZ); - zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d %s", - peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ), - p.prefixlen, attrstr); + zlog_debug ("%s send UPDATE %s/%d %s", + peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ), + p.prefixlen, attrstr); } s = stream_new (BGP_MAX_PACKET_SIZE); @@ -521,13 +577,13 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) total_attr_len = 0; - if (BGP_DEBUG (update, UPDATE_OUT)) + if (bgp_debug_update(peer, &p, 0)) { char buf[INET6_BUFSIZ]; - zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", - peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ), - p.prefixlen); + zlog_debug ("%s send UPDATE %s/%d -- unreachable", + peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ), + p.prefixlen); } s = stream_new (BGP_MAX_PACKET_SIZE); @@ -589,6 +645,12 @@ bgp_write_packet (struct peer *peer) if (s) return s; + /* The code beyond this part deals with update packets, check if updates + are on hold as part of the update-delay post processing stages. */ + if (peer->bgp && (peer->bgp->main_peers_update_hold || + peer->bgp->rsclient_peers_update_hold)) + return NULL; + for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { @@ -607,7 +669,7 @@ bgp_write_packet (struct peer *peer) adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update); if (adv) { - if (adv->binfo && adv->binfo->uptime < peer->synctime) + 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) @@ -645,28 +707,82 @@ bgp_write_packet (struct peer *peer) return NULL; } -/* Is there partially written packet or updates we can send right - now. */ -static int -bgp_write_proceed (struct peer *peer) +/* Are there prefixes queued for being withdrawn? */ +int +bgp_peer_wd_fifo_exists (struct peer *peer) { afi_t afi; safi_t safi; - struct bgp_advertise *adv; - - if (stream_fifo_head (peer->obuf)) - return 1; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) if (FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) return 1; + return 0; +} + +/* Are there prefixes queued for being advertised? + * Are they recent? + */ +int +bgp_peer_adv_fifo_exists (struct peer *peer, int chk_recent) +{ + afi_t afi; + safi_t safi; + struct bgp_advertise *adv; + for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) if ((adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) - if (adv->binfo->uptime < peer->synctime) - return 1; + { + if (!chk_recent) + return 1; + if (adv->binfo->uptime < peer->synctime) + return 1; + } + + return 0; +} + +/* + * Schedule updates for the peer, if needed. + */ +void +bgp_peer_schedule_updates(struct peer *peer) +{ + /* If withdraw FIFO exists, immediately schedule write */ + if (bgp_peer_wd_fifo_exists(peer) && !peer->t_write) + { + if (bgp_debug_update(peer, NULL, 0)) + zlog_debug("%s scheduling write thread", peer->host); + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + } + + /* If update FIFO exists, fire MRAI timer */ + if (bgp_peer_adv_fifo_exists(peer, 0) && !peer->radv_adjusted) + { + if (bgp_debug_update(peer, NULL, 0)) + zlog_debug("%s scheduling MRAI timer", peer->host); + bgp_adjust_routeadv(peer); + } +} + +/* Is there partially written packet or updates we can send right + now. */ +static int +bgp_write_proceed (struct peer *peer) +{ + /* If queued packet exists, we should try to write it */ + if (stream_fifo_head (peer->obuf)) + return 1; + + /* If there are prefixes to be withdrawn or to be advertised (and + * queued before last MRAI timer expiry), schedule write + */ + if (bgp_peer_wd_fifo_exists(peer) + || bgp_peer_adv_fifo_exists(peer, 1)) + return 1; return 0; } @@ -680,6 +796,7 @@ bgp_write (struct thread *thread) struct stream *s; int num; unsigned int count = 0; + unsigned int oc = 0; /* Yes first of all get peer pointer. */ peer = THREAD_ARG (thread); @@ -688,7 +805,7 @@ bgp_write (struct thread *thread) /* For non-blocking IO check. */ if (peer->status == Connect) { - bgp_connect_check (peer); + bgp_connect_check (peer, 1); return 0; } @@ -698,6 +815,8 @@ bgp_write (struct thread *thread) sockopt_cork (peer->fd, 1); + oc = peer->update_out; + /* Nonblocking write until TCP output buffer is full. */ do { @@ -765,13 +884,17 @@ bgp_write (struct thread *thread) /* OK we send packet so delete it. */ bgp_packet_delete (peer); } - while (++count < BGP_WRITE_PACKET_MAX && + while (++count < peer->bgp->wpkt_quanta && (s = bgp_write_packet (peer)) != NULL); - + if (bgp_write_proceed (peer)) BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); done: + /* Update the last write if some updates were written. */ + if (peer->update_out > oc) + peer->last_write = bgp_clock (); + sockopt_cork (peer->fd, 0); return 0; } @@ -826,6 +949,8 @@ bgp_write_notify (struct peer *peer) if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); + /* Handle Graceful Restart case where the state changes to + Connect instead of Idle */ BGP_EVENT_ADD (peer, BGP_Stop); return 0; @@ -836,7 +961,6 @@ void bgp_keepalive_send (struct peer *peer) { struct stream *s; - int length; s = stream_new (BGP_MAX_PACKET_SIZE); @@ -844,16 +968,13 @@ bgp_keepalive_send (struct peer *peer) bgp_packet_set_marker (s, BGP_MSG_KEEPALIVE); /* Set packet size. */ - length = bgp_packet_set_size (s); + (void)bgp_packet_set_size (s); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ - if (BGP_DEBUG (keepalive, KEEPALIVE)) + if (bgp_debug_keepalive(peer)) zlog_debug ("%s sending KEEPALIVE", peer->host); - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s send message type %d, length (incl. header) %d", - peer->host, BGP_MSG_KEEPALIVE, length); /* Add packet to the peer. */ bgp_packet_add (peer, s); @@ -866,7 +987,6 @@ void bgp_open_send (struct peer *peer) { struct stream *s; - int length; u_int16_t send_holdtime; as_t local_as; @@ -897,17 +1017,13 @@ bgp_open_send (struct peer *peer) bgp_open_capability (s, peer); /* Set BGP packet length. */ - length = bgp_packet_set_size (s); + (void)bgp_packet_set_size (s); - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s", peer->host, BGP_VERSION_4, local_as, send_holdtime, inet_ntoa (peer->local_id)); - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s send message type %d, length (incl. header) %d", - peer->host, BGP_MSG_OPEN, length); - /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ @@ -984,33 +1100,16 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, } } - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s send message type %d, length (incl. header) %d", - peer->host, BGP_MSG_NOTIFY, length); - /* peer reset cause */ if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE) { if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET) - { peer->last_reset = PEER_DOWN_USER_RESET; - zlog_info ("Notification sent to neighbor %s: User reset", peer->host); - } else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) - { peer->last_reset = PEER_DOWN_USER_SHUTDOWN; - zlog_info ("Notification sent to neighbor %s: shutdown", peer->host); - } else - { peer->last_reset = PEER_DOWN_NOTIFY_SEND; - zlog_info ("Notification sent to neighbor %s: type %u/%u", - peer->host, code, sub_code); - } } - else - zlog_info ("Notification sent to neighbor %s: configuration change", - peer->host); /* Call immediately. */ BGP_WRITE_OFF (peer->t_write); @@ -1031,7 +1130,6 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, u_char orf_type, u_char when_to_refresh, int remove) { struct stream *s; - int length; struct bgp_filter *filter; int orf_refresh = 0; @@ -1074,7 +1172,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, { UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); stream_putc (s, ORF_COMMON_PART_REMOVE_ALL); - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d", peer->host, orf_type, (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), @@ -1086,7 +1184,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist, ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT, ORF_COMMON_PART_DENY); - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d", peer->host, orf_type, (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), @@ -1099,16 +1197,13 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, } /* Set packet size. */ - length = bgp_packet_set_size (s); + (void)bgp_packet_set_size (s); - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) { if (! orf_refresh) zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d", peer->host, afi, safi); - zlog_debug ("%s send message type %d, length (incl. header) %d", - peer->host, CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV) ? - BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length); } /* Add packet to the peer. */ @@ -1123,7 +1218,6 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, int capability_code, int action) { struct stream *s; - int length; /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) @@ -1144,23 +1238,18 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, stream_putc (s, 0); stream_putc (s, safi); - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d", peer->host, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", afi, safi); } /* Set packet size. */ - length = bgp_packet_set_size (s); - + (void)bgp_packet_set_size (s); /* Add packet to the peer. */ bgp_packet_add (peer, s); - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s send message type %d, length (incl. header) %d", - peer->host, BGP_MSG_CAPABILITY, length); - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } @@ -1169,13 +1258,7 @@ static int bgp_collision_detect (struct peer *new, struct in_addr remote_id) { struct peer *peer; - struct listnode *node, *nnode; - struct bgp *bgp; - bgp = bgp_get_default (); - if (! bgp) - return 0; - /* Upon receipt of an OPEN message, the local system must examine all of its connections that are in the OpenConfirm state. A BGP speaker may also examine connections in an OpenSent state if it @@ -1185,31 +1268,42 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) OPEN message, then the local system performs the following collision resolution procedure: */ - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) + if ((peer = new->doppelganger) != NULL) { - /* Under OpenConfirm status, local peer structure already hold - remote router ID. */ - - if (peer != new - && (peer->status == OpenConfirm || peer->status == OpenSent) - && sockunion_same (&peer->su, &new->su)) + /* Do not accept the new connection in Established or Clearing states. + * Note that a peer GR is handled by closing the existing connection + * upon receipt of new one. + */ + if (peer->status == Established || peer->status == Clearing) + { + bgp_notify_send (new, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + return (-1); + } + else if ((peer->status == OpenConfirm) || (peer->status == OpenSent)) { /* 1. The BGP Identifier of the local system is compared to the BGP Identifier of the remote system (as specified in the OPEN message). */ if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr)) - { - /* 2. If the value of the local BGP Identifier is less - than the remote one, the local system closes BGP - connection that already exists (the one that is - already in the OpenConfirm state), and accepts BGP - connection initiated by the remote system. */ - - if (peer->fd >= 0) - bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); - return 1; - } + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + /* 2. If the value of the local BGP Identifier is less + than the remote one, the local system closes BGP + connection that already exists (the one that is + already in the OpenConfirm state), and accepts BGP + connection initiated by the remote system. */ + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + return 1; + } + else + { + bgp_notify_send (new, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + return -1; + } else { /* 3. Otherwise, the local system closes newly created @@ -1217,11 +1311,18 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) received OPEN message), and continues to use the existing one (the one that is already in the OpenConfirm state). */ - - if (new->fd >= 0) - bgp_notify_send (new, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); - return -1; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + return 1; + } + else + { + bgp_notify_send (new, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + return -1; + } } } } @@ -1238,24 +1339,23 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) u_int16_t send_holdtime; as_t remote_as; as_t as4 = 0; - struct peer *realpeer; struct in_addr remote_id; int mp_capability; u_int8_t notify_data_remote_as[2]; u_int8_t notify_data_remote_id[4]; + u_int16_t *holdtime_ptr; - realpeer = NULL; - /* Parse open packet. */ version = stream_getc (peer->ibuf); memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2); remote_as = stream_getw (peer->ibuf); + holdtime_ptr = (u_int16_t *)stream_pnt (peer->ibuf); holdtime = stream_getw (peer->ibuf); memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4); remote_id.s_addr = stream_get_ipv4 (peer->ibuf); /* Receive OPEN message log */ - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %u," " holdtime %d, id %s", peer->host, version, remote_as, holdtime, @@ -1294,8 +1394,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_BAD_PEER_AS); + bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_BAD_PEER_AS); return -1; } @@ -1325,154 +1425,12 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) } } - /* Lookup peer from Open packet. */ - if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) - { - int as = 0; - - realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as); - - if (! realpeer) - { - /* Peer's source IP address is check in bgp_accept(), so this - must be AS number mismatch or remote-id configuration - mismatch. */ - if (as) - { - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s bad OPEN, wrong router identifier %s", - peer->host, inet_ntoa (remote_id)); - bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_BAD_BGP_IDENT, - notify_data_remote_id, 4); - } - else - { - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s bad OPEN, remote AS is %u, expected %u", - peer->host, remote_as, peer->as); - bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_BAD_PEER_AS, - notify_data_remote_as, 2); - } - return -1; - } - } - - /* When collision is detected and this peer is closed. Retrun - immidiately. */ - ret = bgp_collision_detect (peer, remote_id); - if (ret < 0) - return ret; - - /* Hack part. */ - if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) - { - if (realpeer->status == Established - && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE)) - { - realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; - SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT); - } - else if (ret == 0 && realpeer->status != Active - && realpeer->status != OpenSent - && realpeer->status != OpenConfirm - && realpeer->status != Connect) - { - /* XXX: This is an awful problem.. - * - * According to the RFC we should just let this connection (of the - * accepted 'peer') continue on to Established if the other - * connection (the 'realpeer' one) is in state Connect, and deal - * with the more larval FSM as/when it gets far enough to receive - * an Open. We don't do that though, we instead close the (more - * developed) accepted connection. - * - * This means there's a race, which if hit, can loop: - * - * FSM for A FSM for B - * realpeer accept-peer realpeer accept-peer - * - * Connect Connect - * Active - * OpenSent OpenSent - * <arrive here, - * Notify, delete> - * Idle Active - * OpenSent OpenSent - * <arrive here, - * Notify, delete> - * Idle - * <wait> <wait> - * Connect Connect - * - * - * If both sides are Quagga, they're almost certain to wait for - * the same amount of time of course (which doesn't preclude other - * implementations also waiting for same time). The race is - * exacerbated by high-latency (in bgpd and/or the network). - * - * The reason we do this is because our FSM is tied to our peer - * structure, which carries our configuration information, etc. - * I.e. we can't let the accepted-peer FSM continue on as it is, - * cause it's not associated with any actual peer configuration - - * it's just a dummy. - * - * It's possible we could hack-fix this by just bgp_stop'ing the - * realpeer and continueing on with the 'transfer FSM' below. - * Ideally, we need to seperate FSMs from struct peer. - * - * Setting one side to passive avoids the race, as a workaround. - */ - if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("%s peer status is %s close connection", - realpeer->host, LOOKUP (bgp_status_msg, - realpeer->status)); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_CONNECT_REJECT); - - return -1; - } - - if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("%s [Event] Transfer accept BGP peer to real (state %s)", - peer->host, - LOOKUP (bgp_status_msg, realpeer->status)); - - bgp_stop (realpeer); - - /* Transfer file descriptor. */ - realpeer->fd = peer->fd; - peer->fd = -1; - - /* Transfer input buffer. */ - stream_free (realpeer->ibuf); - realpeer->ibuf = peer->ibuf; - realpeer->packet_size = peer->packet_size; - peer->ibuf = NULL; - - /* Transfer status. */ - realpeer->status = peer->status; - bgp_stop (peer); - - /* peer pointer change. Open packet send to neighbor. */ - peer = realpeer; - bgp_open_send (peer); - if (peer->fd < 0) - { - zlog_err ("bgp_open_receive peer's fd is negative value %d", - peer->fd); - return -1; - } - BGP_READ_ON (peer->t_read, bgp_read, peer->fd); - } - /* remote router-id check. */ if (remote_id.s_addr == 0 || IPV4_CLASS_DE (ntohl (remote_id.s_addr)) || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr)) { - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s bad OPEN, wrong router identifier %s", peer->host, inet_ntoa (remote_id)); bgp_notify_send_with_data (peer, @@ -1490,7 +1448,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { u_int16_t maxver = htons(BGP_VERSION_4); /* XXX this reply may not be correct if version < 4 XXX */ - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s bad protocol version, remote requested %d, local request %d", peer->host, version, BGP_VERSION_4); /* Data must be in network byte order here */ @@ -1504,7 +1462,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* Check neighbor as number. */ if (remote_as != peer->as) { - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s bad OPEN, remote AS is %u, expected %u", peer->host, remote_as, peer->as); bgp_notify_send_with_data (peer, @@ -1522,9 +1480,10 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) if (holdtime < 3 && holdtime != 0) { - bgp_notify_send (peer, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, + (u_int8_t *)holdtime_ptr, 2); return -1; } @@ -1559,7 +1518,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) } else { - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s rcvd OPEN w/ OPTION parameter len: 0", peer->host); } @@ -1578,11 +1537,28 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; } + /* When collision is detected and this peer is closed. Retrun + immidiately. */ + ret = bgp_collision_detect (peer, remote_id); + if (ret < 0) + return ret; + /* Get sockname. */ - bgp_getsockname (peer); + if ((ret = bgp_getsockname (peer)) < 0) + { + zlog_err("%s: bgp_getsockname() failed for peer: %s", __FUNCTION__, + peer->host); + return (ret); + } peer->rtt = sockopt_tcp_rtt (peer->fd); - BGP_EVENT_ADD (peer, Receive_OPEN_message); + if ((ret = bgp_event_update(peer, Receive_OPEN_message)) < 0) + { + zlog_err("%s: BGP event update failed for peer: %s", __FUNCTION__, + peer->host); + /* DD: bgp send notify and reset state */ + return (ret); + } peer->packet_size = 0; if (peer->ibuf) @@ -1609,6 +1585,117 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) return -1; } +/* Called when there is a change in the EOR(implicit or explicit) status of a peer. + Ends the update-delay if all expected peers are done with EORs. */ +void +bgp_check_update_delay(struct bgp *bgp) +{ + struct listnode *node, *nnode; + struct peer *peer = NULL; + + if (bgp_debug_neighbor_events(peer)) + zlog_debug ("Checking update delay, T: %d R: %d I:%d E: %d", bgp->established, + bgp->restarted_peers, bgp->implicit_eors, bgp->explicit_eors); + + if (bgp->established <= + bgp->restarted_peers + bgp->implicit_eors + bgp->explicit_eors) + { + /* This is an extra sanity check to make sure we wait for all the + eligible configured peers. This check is performed if establish wait + timer is on, or establish wait option is not given with the + update-delay command */ + if (bgp->t_establish_wait || + (bgp->v_establish_wait == bgp->v_update_delay)) + for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) + { + if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) + && !CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN) + && !peer->update_delay_over) + { + if (bgp_debug_neighbor_events(peer)) + zlog_debug (" Peer %s pending, continuing read-only mode", + peer->host); + return; + } + } + + zlog_info ("Update delay ended, restarted: %d, EORs implicit: %d, explicit: %d", + bgp->restarted_peers, bgp->implicit_eors, bgp->explicit_eors); + bgp_update_delay_end(bgp); + } +} + +/* Called if peer is known to have restarted. The restart-state bit in + Graceful-Restart capability is used for that */ +void +bgp_update_restarted_peers (struct peer *peer) +{ + if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */ + if (peer->update_delay_over) return; /* This peer has already been considered */ + + if (bgp_debug_neighbor_events(peer)) + zlog_debug ("Peer %s: Checking restarted", peer->host); + + if (peer->status == Established) + { + peer->update_delay_over = 1; + peer->bgp->restarted_peers++; + bgp_check_update_delay(peer->bgp); + } +} + +/* Called as peer receives a keep-alive. Determines if this occurence can be + taken as an implicit EOR for this peer. + NOTE: The very first keep-alive after the Established state of a peer is + considered implicit EOR for the update-delay purposes */ +void +bgp_update_implicit_eors (struct peer *peer) +{ + if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */ + if (peer->update_delay_over) return; /* This peer has already been considered */ + + if (bgp_debug_neighbor_events(peer)) + zlog_debug ("Peer %s: Checking implicit EORs", peer->host); + + if (peer->status == Established) + { + peer->update_delay_over = 1; + peer->bgp->implicit_eors++; + bgp_check_update_delay(peer->bgp); + } +} + +/* Should be called only when there is a change in the EOR_RECEIVED status + for any afi/safi on a peer */ +static void +bgp_update_explicit_eors (struct peer *peer) +{ + afi_t afi; + safi_t safi; + + if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */ + if (peer->update_delay_over) return; /* This peer has already been considered */ + + if (bgp_debug_neighbor_events(peer)) + zlog_debug ("Peer %s: Checking explicit EORs", peer->host); + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + if (peer->afc_nego[afi][safi] && + !CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) + { + if (bgp_debug_neighbor_events(peer)) + zlog_debug (" afi %d safi %d didnt receive EOR", afi, safi); + return; + } + } + + peer->update_delay_over = 1; + peer->bgp->explicit_eors++; + bgp_check_update_delay(peer->bgp); +} + /* Parse BGP Update packet and make attribute object. */ static int bgp_update_receive (struct peer *peer, bgp_size_t size) @@ -1646,6 +1733,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) memset (&extra, 0, sizeof (struct attr_extra)); memset (&nlris, 0, sizeof nlris); attr.extra = &extra; + memset (peer->rcvd_attr_str, 0, BUFSIZ); + peer->rcvd_attr_printed = 0; s = peer->ibuf; end = stream_pnt (s) + size; @@ -1686,8 +1775,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) 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); + zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host); stream_forward_getp (s, withdraw_len); } @@ -1744,24 +1832,21 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) } /* Logging the attribute. */ - if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW - || BGP_DEBUG (update, UPDATE_IN)) + if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW || + BGP_DEBUG (update, UPDATE_IN) || + BGP_DEBUG (update, UPDATE_PREFIX)) { - char attrstr[BUFSIZ]; - attrstr[0] = '\0'; - - ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); - int lvl = (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) - ? LOG_ERR : LOG_DEBUG; + ret = bgp_dump_attr (peer, &attr, peer->rcvd_attr_str, BUFSIZ); if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) - zlog (peer->log, LOG_ERR, - "%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", - peer->host); + zlog_err ("%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", + peer->host); - if (ret) - zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s", - peer->host, attrstr); + if (ret && bgp_debug_update(peer, NULL, 1)) + { + zlog_debug ("%s rcvd UPDATE w/ attr: %s", peer->host, peer->rcvd_attr_str); + peer->rcvd_attr_printed = 1; + } } /* Network Layer Reachability Information. */ @@ -1796,8 +1881,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) */ 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", + zlog_info ("%s [Info] UPDATE with unsupported AFI/SAFI %u/%u", peer->host, nlris[i].afi, nlris[i].safi); continue; } @@ -1806,8 +1890,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) 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", + zlog_info ("%s [Info] UPDATE for non-enabled AFI/SAFI %u/%u", peer->host, nlris[i].afi, nlris[i].safi); continue; } @@ -1829,8 +1912,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (nlri_ret < 0) { - plog_err (peer->log, - "%s [Error] Error parsing NLRI", peer->host); + zlog_err ("%s [Error] Error parsing NLRI", peer->host); if (peer->status == Established) bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, i <= NLRI_WITHDRAW @@ -1877,14 +1959,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* End-of-RIB received */ SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED); + if (!CHECK_FLAG (peer->af_sflags[afi][safi], + 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][safi]) bgp_clear_stale_route (peer, afi, safi); - if (BGP_DEBUG (normal, NORMAL)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for %s from %s", - peer->host, afi_safi_print (afi, safi)); + zlog_debug ("rcvd End-of-RIB for %s from %s", + peer->host, afi_safi_print (afi, safi)); } } @@ -1991,7 +2079,7 @@ bgp_notify_receive (struct peer *peer, bgp_size_t size) static void bgp_keepalive_receive (struct peer *peer, bgp_size_t size) { - if (BGP_DEBUG (keepalive, KEEPALIVE)) + if (bgp_debug_keepalive(peer)) zlog_debug ("%s KEEPALIVE rcvd", peer->host); BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message); @@ -2008,7 +2096,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) /* If peer does not have the capability, send notification. */ if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV)) { - plog_err (peer->log, "%s [Error] BGP route refresh is not enabled", + zlog_err ("%s [Error] BGP route refresh is not enabled", peer->host); bgp_notify_send (peer, BGP_NOTIFY_HEADER_ERR, @@ -2019,8 +2107,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) /* Status must be Established. */ if (peer->status != Established) { - plog_err (peer->log, - "%s [Error] Route refresh packet received under status %s", + zlog_err ("%s [Error] Route refresh packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); return; @@ -2034,7 +2121,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) stream_getc (s); safi = stream_getc (s); - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_update(peer, NULL, 0)) zlog_debug ("%s rcvd REFRESH_REQ for afi/safi: %d/%d", peer->host, afi, safi); @@ -2043,11 +2130,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != SAFI_MPLS_LABELED_VPN)) { - if (BGP_DEBUG (normal, NORMAL)) - { - zlog_debug ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored", - peer->host, afi, safi); - } + zlog_info ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored", + peer->host, afi, safi); return; } @@ -2092,7 +2176,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) char name[BUFSIZ]; int ret; - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) { zlog_debug ("%s rcvd Prefixlist ORF(%d) length %d", peer->host, orf_type, orf_len); @@ -2119,7 +2203,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) /* after ++: p_pnt <= p_end */ if (common & ORF_COMMON_PART_REMOVE_ALL) { - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s rcvd Remove-All pfxlist ORF request", peer->host); prefix_bgp_orf_remove_all (afi, name); break; @@ -2158,7 +2242,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) memcpy (&orfp.p.u.prefix, p_pnt, psize); p_pnt += psize; - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) { char buf[INET6_BUFSIZ]; @@ -2179,9 +2263,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) if (!ok || (ok && ret != CMD_SUCCESS)) { - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s Received misformatted prefixlist ORF." - " Remove All pfxlist", peer->host); + zlog_info ("%s Received misformatted prefixlist ORF." + " Remove All pfxlist", peer->host); prefix_bgp_orf_remove_all (afi, name); break; } @@ -2191,7 +2274,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) } stream_forward_getp (s, orf_len); } - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s rcvd Refresh %s ORF request", peer->host, when_to_refresh == REFRESH_DEFER ? "Defer" : "Immediate"); if (when_to_refresh == REFRESH_DEFER) @@ -2240,7 +2323,7 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) return -1; } - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s CAPABILITY has action: %d, code: %u, length %u", peer->host, action, hdr->code, hdr->length); @@ -2267,14 +2350,14 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) if (!bgp_afi_safi_valid_indices (afi, &safi)) { - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid " "(%u/%u)", peer->host, afi, safi); continue; } /* Address family check. */ - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u", peer->host, action == CAPABILITY_ACTION_SET @@ -2323,13 +2406,13 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size) /* Fetch pointer. */ pnt = stream_pnt (peer->ibuf); - if (BGP_DEBUG (normal, NORMAL)) + if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s rcv CAPABILITY", peer->host); /* If peer does not have the capability, send notification. */ if (! CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV)) { - plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled", + zlog_err ("%s [Error] BGP dynamic capability is not enabled", peer->host); bgp_notify_send (peer, BGP_NOTIFY_HEADER_ERR, @@ -2340,8 +2423,8 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size) /* Status must be Established. */ if (peer->status != Established) { - plog_err (peer->log, - "%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); + zlog_err ("%s [Error] Dynamic capability packet received under status %s", + peer->host, LOOKUP (bgp_status_msg, peer->status)); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); return -1; } @@ -2373,8 +2456,8 @@ bgp_read_packet (struct peer *peer) if (nbytes == -2) return -1; - plog_err (peer->log, "%s [Error] bgp_read_packet error: %s", - peer->host, safe_strerror (errno)); + zlog_err ("%s [Error] bgp_read_packet error: %s", + peer->host, safe_strerror (errno)); if (peer->status == Established) { @@ -2394,9 +2477,9 @@ bgp_read_packet (struct peer *peer) /* When read byte is zero : clear bgp peer and return */ if (nbytes == 0) { - if (BGP_DEBUG (events, EVENTS)) - plog_debug (peer->log, "%s [Event] BGP connection closed fd %d", - peer->host, peer->fd); + if (bgp_debug_neighbor_events(peer)) + zlog_debug ("%s [Event] BGP connection closed fd %d", + peer->host, peer->fd); if (peer->status == Established) { @@ -2451,15 +2534,19 @@ bgp_read (struct thread *thread) struct peer *peer; bgp_size_t size; char notify_data_length[2]; + u_int32_t notify_out; /* Yes first of all get peer pointer. */ peer = THREAD_ARG (thread); peer->t_read = NULL; + /* Note notify_out so we can check later to see if we sent another one */ + notify_out = peer->notify_out; + /* For non-blocking IO check. */ if (peer->status == Connect) { - bgp_connect_check (peer); + bgp_connect_check (peer, 1); goto done; } else @@ -2490,10 +2577,6 @@ bgp_read (struct thread *thread) size = stream_getw (peer->ibuf); type = stream_getc (peer->ibuf); - if (BGP_DEBUG (normal, NORMAL) && type != 2 && type != 0) - zlog_debug ("%s rcv message type %d, length (excl. header) %d", - peer->host, type, size - BGP_HEADER_SIZE); - /* Marker check */ if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE)) && ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE)) @@ -2511,10 +2594,9 @@ bgp_read (struct thread *thread) && type != BGP_MSG_ROUTE_REFRESH_OLD && type != BGP_MSG_CAPABILITY) { - if (BGP_DEBUG (normal, NORMAL)) - plog_debug (peer->log, - "%s unknown message type 0x%02x", - peer->host, type); + if (bgp_debug_neighbor_events(peer)) + zlog_debug ("%s unknown message type 0x%02x", + peer->host, type); bgp_notify_send_with_data (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE, @@ -2532,12 +2614,11 @@ bgp_read (struct thread *thread) || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE)) { - if (BGP_DEBUG (normal, NORMAL)) - plog_debug (peer->log, - "%s bad message length - %d for %s", - peer->host, size, - type == 128 ? "ROUTE-REFRESH" : - bgp_type_str[(int) type]); + if (bgp_debug_neighbor_events(peer)) + zlog_debug ("%s bad message length - %d for %s", + peer->host, size, + type == 128 ? "ROUTE-REFRESH" : + bgp_type_str[(int) type]); bgp_notify_send_with_data (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESLEN, @@ -2591,17 +2672,30 @@ bgp_read (struct thread *thread) break; } + /* If reading this packet caused us to send a NOTIFICATION then store a copy + * of the packet for troubleshooting purposes + */ + if (notify_out < peer->notify_out) + { + memcpy(peer->last_reset_cause, peer->ibuf->data, peer->packet_size); + peer->last_reset_cause_size = peer->packet_size; + notify_out = peer->notify_out; + } + /* Clear input buffer. */ peer->packet_size = 0; if (peer->ibuf) stream_reset (peer->ibuf); done: - if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + /* If reading this packet caused us to send a NOTIFICATION then store a copy + * of the packet for troubleshooting purposes + */ + if (notify_out < peer->notify_out) { - if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("%s [Event] Accepting BGP peer delete", peer->host); - peer_delete (peer); + memcpy(peer->last_reset_cause, peer->ibuf->data, peer->packet_size); + peer->last_reset_cause_size = peer->packet_size; } + return 0; } |