diff options
Diffstat (limited to 'bgpd/bgp_packet.c')
-rw-r--r-- | bgpd/bgp_packet.c | 918 |
1 files changed, 465 insertions, 453 deletions
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 1d9fcc97..b21cec4e 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -29,9 +29,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "sockunion.h" /* for inet_ntop () */ #include "linklist.h" -#include "plist.h" #include "bgpd/bgpd.h" + +#include "bgpd/bgp_peer.h" + #include "bgpd/bgp_table.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_attr.h" @@ -47,9 +49,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" +#include "bgpd/bgp_route_refresh.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) @@ -84,21 +87,7 @@ bgp_packet_set_size (struct stream *s) return cp; } -/* Add new packet to the peer. */ -static void -bgp_packet_add (struct peer *peer, struct stream *s) -{ - /* Add packet to the end of list. */ - stream_fifo_push (peer->obuf, s); -} - -/* Free first packet. */ -static void -bgp_packet_delete (struct peer *peer) -{ - stream_free (stream_fifo_pop (peer->obuf)); -} - +#if 0 /* Check file descriptor whether connect is established. */ static void bgp_connect_check (struct peer *peer) @@ -121,7 +110,7 @@ bgp_connect_check (struct peer *peer) zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect"); BGP_EVENT_ADD (peer, TCP_fatal_error); return; - } + } /* When status is 0 then TCP connection is established. */ if (status == 0) @@ -136,15 +125,22 @@ bgp_connect_check (struct peer *peer) BGP_EVENT_ADD (peer, TCP_connection_open_failed); } } +#endif -/* Make BGP update packet. */ +/*------------------------------------------------------------------------------ + * Construct an update from head of peer->sync[afi][safi]->update. + * + * Generates complete BGP message in the peer->work stream structure. + * + * Returns: peer->work -- if have something to be written. + * NULL -- otherwise + */ static struct stream * bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; 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; @@ -154,7 +150,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) s = peer->work; stream_reset (s); - adv = FIFO_HEAD (&peer->sync[afi][safi]->update); + adv = bgp_advertise_fifo_head(&peer->sync[afi][safi]->update); while (adv) { @@ -174,7 +170,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t 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) @@ -183,21 +179,21 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) if (binfo->extra) tag = binfo->extra->tag; } - + bgp_packet_set_marker (s, BGP_MSG_UPDATE); - stream_putw (s, 0); + stream_putw (s, 0); pos = stream_get_endp (s); stream_putw (s, 0); - total_attr_len = bgp_packet_attribute (NULL, peer, s, + total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, - &rn->p, afi, safi, + &rn->p, 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); - + if (BGP_DEBUG (update, UPDATE_OUT)) zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d", peer->host, @@ -217,24 +213,26 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) if (! (afi == AFI_IP && safi == SAFI_UNICAST)) break; } - - if (! stream_empty (s)) - { - bgp_packet_set_size (s); - packet = stream_dup (s); - bgp_packet_add (peer, packet); - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); - stream_reset (s); - return packet; - } - return NULL; + + if (stream_empty (s)) + return NULL ; + + bgp_packet_set_size (s) ; + return s ; } +/*------------------------------------------------------------------------------ + * Construct an End-of-RIB update message for given AFI/SAFI. + * + * Generates complete BGP message in the peer->work stream structure. + * + * Returns: peer->work -- if have something to be written. + * NULL -- otherwise + */ 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; @@ -242,7 +240,8 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi), peer->host); - s = stream_new (BGP_MAX_PACKET_SIZE); + s = peer->work; + stream_reset (s); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); @@ -267,18 +266,21 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) } bgp_packet_set_size (s); - packet = stream_dup (s); - bgp_packet_add (peer, packet); - stream_free (s); - return packet; + return s ; } -/* Make BGP withdraw packet. */ +/*------------------------------------------------------------------------------ + * Construct a withdraw update from from head of peer->sync[afi][safi]->withdraw + * + * Generates complete BGP message in the peer->work stream structure. + * + * Returns: peer->work -- if have something to be written. + * NULL -- otherwise + */ static struct stream * bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; - struct stream *packet; struct bgp_adj_out *adj; struct bgp_advertise *adv; struct bgp_node *rn; @@ -290,13 +292,14 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) s = peer->work; stream_reset (s); - while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) + while ((adv = bgp_advertise_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; @@ -311,14 +314,14 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) 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); } @@ -332,37 +335,38 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) peer->scount[afi][safi]--; 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 (stream_empty (s)) + return NULL ; + + if (afi == AFI_IP && safi == SAFI_UNICAST) { - 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); - } - bgp_packet_set_size (s); - packet = stream_dup (s); - bgp_packet_add (peer, packet); - stream_reset (s); - return packet; - } + stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len); + stream_putw (s, 0); + } ; - return NULL; + bgp_packet_set_size (s); + return s ; } +/*------------------------------------------------------------------------------ + * Construct an update for the default route, place it in the obuf queue + * and kick write. + * + * Uses peer->work stream structure, but copies result to new stream, which is + * pushed onto the obuf queue. + */ void bgp_default_update_send (struct peer *peer, struct attr *attr, 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; @@ -375,7 +379,7 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); #ifdef HAVE_IPV6 - else + else str2prefix ("::/0", &p); #endif /* HAVE_IPV6 */ @@ -388,7 +392,8 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, p.prefixlen, attrstr); } - s = stream_new (BGP_MAX_PACKET_SIZE); + s = peer->work ; + stream_reset (s); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); @@ -411,25 +416,26 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, /* 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); */ + /* bgp_packet_dump (s); */ #endif /* DEBUG */ /* Add packet to the peer. */ - bgp_packet_add (peer, packet); - - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + bgp_write(peer, s); } +/*------------------------------------------------------------------------------ + * Construct a withdraw update for the default route, place it in the obuf + * queue and kick write. + * + * Uses peer->work stream structure, but copies result to new stream, which is + * pushed onto the obuf queue. + */ 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 cp; @@ -443,7 +449,7 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); #ifdef HAVE_IPV6 - else + else str2prefix ("::/0", &p); #endif /* HAVE_IPV6 */ @@ -455,7 +461,8 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ), p.prefixlen); - s = stream_new (BGP_MAX_PACKET_SIZE); + s = peer->work ; + stream_reset (s); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); @@ -489,16 +496,18 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) bgp_packet_set_size (s); - packet = stream_dup (s); - stream_free (s); - /* Add packet to the peer. */ - bgp_packet_add (peer, packet); - - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + bgp_write(peer, s); } -/* Get next packet to be written. */ +/*------------------------------------------------------------------------------ + * Get next update message to be written. + * + * Generates complete BGP message in the peer->work stream structure. + * + * Returns: peer->work -- if have something to be written. + * NULL -- otherwise + */ static struct stream * bgp_write_packet (struct peer *peer) { @@ -507,14 +516,10 @@ bgp_write_packet (struct peer *peer) struct stream *s = NULL; struct bgp_advertise *adv; - s = stream_fifo_head (peer->obuf); - if (s) - return s; - 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_advertise_fifo_head(&peer->sync[afi][safi]->withdraw); if (adv) { s = bgp_withdraw_packet (peer, afi, safi); @@ -522,11 +527,11 @@ bgp_write_packet (struct peer *peer) return s; } } - + 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_advertise_fifo_head(&peer->sync[afi][safi]->update); if (adv) { if (adv->binfo && adv->binfo->uptime < peer->synctime) @@ -563,6 +568,7 @@ bgp_write_packet (struct peer *peer) return NULL; } +#if 0 /* Is there partially written packet or updates we can send right now. */ static int @@ -588,118 +594,52 @@ bgp_write_proceed (struct peer *peer) return 0; } +#endif -/* Write packet to the peer. */ +/*------------------------------------------------------------------------------ + * Write packets to the peer -- subject to the XON flow control. + * + * Takes an optional stream argument, if not NULL then must be peer->work, + * in which there is a message to be sent. + * + * Then processes the peer->sync structure to generate further updates. + * + * TODO: work out how bgp_routeadv_timer fits into this. + */ int -bgp_write (struct thread *thread) +bgp_write (bgp_peer peer, struct stream* s) { - struct peer *peer; - u_char type; - struct stream *s; - int num; - unsigned int count = 0; - - /* Yes first of all get peer pointer. */ - peer = THREAD_ARG (thread); - peer->t_write = NULL; - - /* For non-blocking IO check. */ - if (peer->status == Connect) - { - bgp_connect_check (peer); - return 0; - } - - s = bgp_write_packet (peer); - if (!s) - return 0; /* nothing to send */ - - sockopt_cork (peer->fd, 1); + if (s != NULL) + stream_fifo_push(peer->obuf, stream_dup(s)) ; - /* Nonblocking write until TCP output buffer is full. */ - do + while (bgp_session_is_XON(peer)) { - int writenum; + s = bgp_write_packet(peer); /* uses peer->work */ + if (s == NULL) + break; - /* Number of bytes to be sent. */ - writenum = stream_get_endp (s) - stream_get_getp (s); + stream_fifo_push (peer->obuf, stream_dup(s)) ; - /* Call write() system call. */ - num = write (peer->fd, STREAM_PNT (s), writenum); - if (num < 0) - { - /* write failed either retry needed or error */ - if (ERRNO_IO_RETRY(errno)) - break; - - BGP_EVENT_ADD (peer, TCP_fatal_error); - return 0; - } + /* Count down flow control, send fifo if hits BGP_XON_KICK */ + if (bgp_session_dec_flow_count(peer)) + bgp_session_update_send(peer->session, peer->obuf) ; + } ; - if (num != writenum) - { - /* Partial write */ - stream_forward_getp (s, num); - break; - } - - /* Retrieve BGP packet type. */ - stream_set_getp (s, BGP_MARKER_SIZE + 2); - type = stream_getc (s); - - switch (type) - { - case BGP_MSG_OPEN: - peer->open_out++; - break; - case BGP_MSG_UPDATE: - peer->update_out++; - break; - case BGP_MSG_NOTIFY: - peer->notify_out++; - /* Double start timer. */ - peer->v_start *= 2; - - /* Overflow check. */ - if (peer->v_start >= (60 * 2)) - peer->v_start = (60 * 2); - - /* Flush any existing events */ - BGP_EVENT_ADD (peer, BGP_Stop); - return 0; - case BGP_MSG_KEEPALIVE: - peer->keepalive_out++; - break; - case BGP_MSG_ROUTE_REFRESH_NEW: - case BGP_MSG_ROUTE_REFRESH_OLD: - peer->refresh_out++; - break; - case BGP_MSG_CAPABILITY: - peer->dynamic_cap_out++; - break; - } + /* In any case, send what's in the FIFO */ + if (stream_fifo_head(peer->obuf) != NULL) + bgp_session_update_send(peer->session, peer->obuf) ; - /* OK we send packet so delete it. */ - bgp_packet_delete (peer); - } - while (++count < BGP_WRITE_PACKET_MAX && - (s = bgp_write_packet (peer)) != NULL); - - if (bgp_write_proceed (peer)) - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); - else - sockopt_cork (peer->fd, 0); - return 0; } +#if 0 /* This is only for sending NOTIFICATION message to neighbor. */ static int bgp_write_notify (struct peer *peer) { int ret, val; u_char type; - struct stream *s; + struct stream *s; /* There should be at least one packet. */ s = stream_fifo_head (peer->obuf); @@ -738,7 +678,9 @@ bgp_write_notify (struct peer *peer) return 0; } +#endif +#if 0 /* Make keepalive packet and send it to the peer. */ void bgp_keepalive_send (struct peer *peer) @@ -756,19 +698,20 @@ bgp_keepalive_send (struct peer *peer) /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ - - if (BGP_DEBUG (keepalive, KEEPALIVE)) - zlog_debug ("%s sending KEEPALIVE", peer->host); + + if (BGP_DEBUG (keepalive, KEEPALIVE)) + 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); - - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + bgp_write(peer); } +#endif +#if 0 /* Make open packet and send it to the peer. */ void bgp_open_send (struct peer *peer) @@ -785,9 +728,9 @@ bgp_open_send (struct peer *peer) /* local-as Change */ if (peer->change_local_as) - local_as = peer->change_local_as; + local_as = peer->change_local_as; else - local_as = peer->local_as; + local_as = peer->local_as; s = stream_new (BGP_MAX_PACKET_SIZE); @@ -796,7 +739,7 @@ bgp_open_send (struct peer *peer) /* Set open packet values. */ stream_putc (s, BGP_VERSION_4); /* BGP version */ - stream_putw (s, (local_as <= BGP_AS_MAX) ? (u_int16_t) local_as + stream_putw (s, (local_as <= BGP_AS_MAX) ? (u_int16_t) local_as : BGP_AS_TRANS); stream_putw (s, send_holdtime); /* Hold Time */ stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */ @@ -808,9 +751,9 @@ bgp_open_send (struct peer *peer) length = bgp_packet_set_size (s); if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s", + 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)); + send_holdtime, safe_inet_ntoa (peer->local_id)); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s send message type %d, length (incl. header) %d", @@ -821,105 +764,89 @@ bgp_open_send (struct peer *peer) /* Add packet to the peer. */ bgp_packet_add (peer, s); - - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + bgp_write(peer); } +#endif + +/* Send route refresh message to the peer. */ -/* Send BGP notify packet with data potion. */ void -bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, - u_char *data, size_t datalen) +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; - - /* Allocate new stream. */ - s = stream_new (BGP_MAX_PACKET_SIZE); + bgp_route_refresh rr = NULL; + struct bgp_filter *filter = NULL; + bgp_session session = peer->session; + bgp_orf_entry orfpe = NULL; + struct prefix_list *plist = NULL; + struct orf_prefix orfp; + vector_index i; + int orf_refresh = 0; + enum prefix_list_type pe_type; - /* Make nitify packet. */ - bgp_packet_set_marker (s, BGP_MSG_NOTIFY); + if (DISABLE_BGP_ANNOUNCE) + return; - /* Set notify packet values. */ - stream_putc (s, code); /* BGP notify code */ - stream_putc (s, sub_code); /* BGP notify sub_code */ + filter = &peer->filter[afi][safi]; - /* If notify data is present. */ - if (data) - stream_write (s, data, datalen); - - /* Set BGP packet length. */ - length = bgp_packet_set_size (s); - - /* Add packet to the peer. */ - stream_fifo_clean (peer->obuf); - bgp_packet_add (peer, s); + /* Adjust safi code. */ + if (safi == SAFI_MPLS_VPN) + safi = BGP_SAFI_VPNV4; - /* For debug */ - { - struct bgp_notify bgp_notify; - int first = 0; - int i; - char c[4]; + rr = bgp_route_refresh_new(afi, safi, 1); + rr->defer = (when_to_refresh == REFRESH_DEFER); - bgp_notify.code = code; - bgp_notify.subcode = sub_code; - bgp_notify.data = NULL; - bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE; - - if (bgp_notify.length) + if (orf_type == ORF_TYPE_PREFIX + || orf_type == ORF_TYPE_PREFIX_OLD) + if (remove || filter->plist[FILTER_IN].ref) { - bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); - for (i = 0; i < bgp_notify.length; i++) - if (first) - { - sprintf (c, " %02x", data[i]); - strcat (bgp_notify.data, c); - } - else - { - first = 1; - sprintf (c, "%02x", data[i]); - strcpy (bgp_notify.data, c); - } + orf_refresh = 1; + if (remove) + { + UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); + bgp_orf_add_remove_all(rr, BGP_ORF_T_PREFIX, bgp_form_none); + if (BGP_DEBUG (normal, NORMAL)) + 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", + afi, safi); + } + else + { + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); + plist = prefix_list_ref_plist(filter->plist[FILTER_IN].ref) ; + for (i = 0; prefix_bgp_orf_get(plist, i, &orfp, &pe_type); ++i) + { + orfpe = bgp_orf_add(rr, BGP_ORF_T_PREFIX, bgp_form_none, 0, + pe_type == PREFIX_DENY); + orfpe->body.orf_prefix = orfp; + } + if (BGP_DEBUG (normal, NORMAL)) + 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", + afi, safi); + } } - bgp_notify_print (peer, &bgp_notify, "sending"); - if (bgp_notify.data) - XFREE (MTYPE_TMP, bgp_notify.data); - } 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; - else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) - peer->last_reset = PEER_DOWN_USER_SHUTDOWN; - else - peer->last_reset = PEER_DOWN_NOTIFY_SEND; + if (! orf_refresh) + zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d", + peer->host, afi, safi); } - /* Call imidiately. */ - BGP_WRITE_OFF (peer->t_write); - - bgp_write_notify (peer); -} + bgp_session_route_refresh_send(session, rr); -/* Send BGP notify packet. */ -void -bgp_notify_send (struct peer *peer, u_char code, u_char sub_code) -{ - bgp_notify_send_with_data (peer, code, sub_code, NULL, 0); -} +#if 0 + /* old code */ -/* Send route refresh message to the peer. */ -void -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; struct stream *packet; int length; @@ -934,7 +861,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) safi = BGP_SAFI_VPNV4; - + s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ @@ -947,15 +874,15 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, stream_putw (s, afi); stream_putc (s, 0); stream_putc (s, safi); - + if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) - if (remove || filter->plist[FILTER_IN].plist) + if (remove || filter->plist[FILTER_IN].ref) { u_int16_t orf_len; unsigned long orfp; - orf_refresh = 1; + orf_refresh = 1; stream_putc (s, when_to_refresh); stream_putc (s, orf_type); orfp = stream_get_endp (s); @@ -966,7 +893,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)) - zlog_debug ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d", + 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"), afi, safi); @@ -974,11 +901,11 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, else { SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); - prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist, + prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].ref, ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT, ORF_COMMON_PART_DENY); if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d", + 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"), afi, safi); @@ -995,7 +922,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, if (BGP_DEBUG (normal, NORMAL)) { if (! orf_refresh) - zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d", + 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) ? @@ -1008,24 +935,27 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, /* Add packet to the peer. */ bgp_packet_add (peer, packet); - - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + bgp_write(peer); +#endif } /* Send capability message to the peer. */ + +/* TODO: require BGP Engine support for Dynamic Capability messages. */ + void bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, int capability_code, int action) { struct stream *s; - struct stream *packet; int length; /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) safi = BGP_SAFI_VPNV4; - s = stream_new (BGP_MAX_PACKET_SIZE); + s = peer->work; + stream_reset (s); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_CAPABILITY); @@ -1049,20 +979,15 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, /* 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); - if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s send message type %d, length (incl. header) %d", - peer->host, BGP_MSG_CAPABILITY, length); + peer->host, BGP_MSG_CAPABILITY, length); - BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + /* Add packet to the peer. */ + bgp_write(peer, s); } - + +#if 0 /* RFC1771 6.8 Connection collision detection. */ static int bgp_collision_detect (struct peer *new, struct in_addr remote_id) @@ -1074,7 +999,7 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) 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 @@ -1118,7 +1043,7 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) OpenConfirm state). */ if (new->fd >= 0) - bgp_notify_send (new, BGP_NOTIFY_CEASE, + bgp_notify_send (new, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return -1; } @@ -1126,7 +1051,9 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) } return 0; } +#endif +#if 0 static int bgp_open_receive (struct peer *peer, bgp_size_t size) { @@ -1144,7 +1071,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) u_int8_t notify_data_remote_id[4]; realpeer = NULL; - + /* Parse open packet. */ version = stream_getc (peer->ibuf); memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2); @@ -1158,21 +1085,21 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %u," " holdtime %d, id %s", peer->host, version, remote_as, holdtime, - inet_ntoa (remote_id)); - + safe_inet_ntoa (remote_id)); + /* BEGIN to read the capability here, but dont do it yet */ capability = 0; optlen = stream_getc (peer->ibuf); - + if (optlen != 0) { /* We need the as4 capability value *right now* because * if it is there, we have not got the remote_as yet, and without * that we do not know which peer is connecting to us now. - */ + */ as4 = peek_for_as4_capability (peer, optlen); } - + /* Just in case we have a silly peer who sends AS4 capability set to 0 */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) && !as4) { @@ -1182,7 +1109,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) BGP_NOTIFY_OPEN_BAD_PEER_AS); return -1; } - + if (remote_as == BGP_AS_TRANS) { /* Take the AS4 from the capability. We must have received the @@ -1197,7 +1124,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) BGP_NOTIFY_OPEN_BAD_PEER_AS); return -1; } - + if (!as4 && BGP_DEBUG (as4, AS4)) zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4." " Odd, but proceeding.", peer->host); @@ -1206,8 +1133,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) "in 2-bytes, very odd peer.", peer->host, as4); if (as4) remote_as = as4; - } - else + } + else { /* We may have a partner with AS4 who has an asno < BGP_AS_MAX */ /* If we have got the capability, peer->as4cap must match remote_as */ @@ -1240,8 +1167,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { 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, + peer->host, safe_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); } @@ -1278,7 +1205,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) && realpeer->status != OpenConfirm && realpeer->status != Connect) { - /* XXX: This is an awful problem.. + /* 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 @@ -1296,7 +1223,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) * Active * OpenSent OpenSent * <arrive here, - * Notify, delete> + * Notify, delete> * Idle Active * OpenSent OpenSent * <arrive here, @@ -1312,13 +1239,13 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) * 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. + * 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. + * 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. @@ -1335,11 +1262,11 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s [Event] Transfer accept BGP peer to real (state %s)", - peer->host, + peer->host, LOOKUP (bgp_status_msg, realpeer->status)); bgp_stop (realpeer); - + /* Transfer file descriptor. */ realpeer->fd = peer->fd; peer->fd = -1; @@ -1353,7 +1280,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* Transfer status. */ realpeer->status = peer->status; bgp_stop (peer); - + /* peer pointer change. Open packet send to neighbor. */ peer = realpeer; bgp_open_send (peer); @@ -1373,9 +1300,9 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { 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, + peer->host, safe_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); return -1; @@ -1391,8 +1318,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad protocol version, remote requested %d, local request %d", peer->host, version, BGP_VERSION_4); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_VERSION, &maxver, 1); return -1; @@ -1404,8 +1331,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) 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_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return -1; @@ -1420,11 +1347,11 @@ 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_ERR, BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); return -1; } - + /* From the rfc: A reasonable maximum time between KEEPALIVE messages would be one third of the Hold Time interval. KEEPALIVE messages MUST NOT be sent more frequently than one per second. An @@ -1444,7 +1371,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) peer->v_keepalive = peer->v_holdtime / 3; /* Open option part parse. */ - if (optlen != 0) + if (optlen != 0) { ret = bgp_open_option_parse (peer, optlen, &capability); if (ret < 0) @@ -1477,9 +1404,10 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) return 0; } +#endif /* Parse BGP Update packet and make attribute object. */ -static int +int bgp_update_receive (struct peer *peer, bgp_size_t size) { int ret; @@ -1494,13 +1422,14 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) struct bgp_nlri mp_update; struct bgp_nlri mp_withdraw; char attrstr[BUFSIZ] = ""; + bgp_attr_parse_ret_t ap_ret ; /* Status must be Established. */ - if (peer->status != Established) + if (peer->state != bgp_peer_pEstablished) { zlog_err ("%s [FSM] Update packet received under status %s", - peer->host, LOOKUP (bgp_status_msg, peer->status)); - bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); + peer->host, LOOKUP (bgp_peer_status_msg, peer->state)); + bgp_peer_down_error (peer, BGP_NOTIFY_FSM_ERR, 0); return -1; } @@ -1523,8 +1452,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) zlog_err ("%s [Error] Update packet error" " (packet length is short for unfeasible length)", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } @@ -1537,8 +1466,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) zlog_err ("%s [Error] Update packet error" " (packet unfeasible length overflow %d)", peer->host, withdraw_len); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } @@ -1558,15 +1487,15 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) withdraw.length = withdraw_len; stream_forward_getp (s, withdraw_len); } - + /* Attribute total length check. */ if (stream_pnt (s) + 2 > end) { zlog_warn ("%s [Error] Packet Error" " (update packet is short for attribute length)", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } @@ -1579,42 +1508,41 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) zlog_warn ("%s [Error] Packet Error" " (update packet attribute length overflow %d)", peer->host, attribute_len); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } - + /* Certain attribute parsing errors should not be considered bad enough * to reset the session for, most particularly any partial/optional * attributes that have 'tunneled' over speakers that don't understand * them. Instead we withdraw only the prefix concerned. - * + * * Complicates the flow a little though.. */ - bgp_attr_parse_ret_t attr_parse_ret = BGP_ATTR_PARSE_PROCEED; + ap_ret = BGP_ATTR_PARSE_PROCEED; + /* This define morphs the update case into a withdraw when lower levels * have signalled an error condition where this is best. */ -#define NLRI_ATTR_ARG (attr_parse_ret != BGP_ATTR_PARSE_WITHDRAW ? &attr : NULL) +#define NLRI_ATTR_ARG (ap_ret != BGP_ATTR_PARSE_WITHDRAW ? &attr : NULL) /* Parse attribute when it exists. */ if (attribute_len) { - attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len, - &mp_update, &mp_withdraw); - if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) + ap_ret = bgp_attr_parse (peer, &attr, attribute_len, + &mp_update, &mp_withdraw); + if (ap_ret == BGP_ATTR_PARSE_ERROR) return -1; } - + /* Logging the attribute. */ - if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW - || BGP_DEBUG (update, UPDATE_IN)) + if ((ap_ret == BGP_ATTR_PARSE_WITHDRAW) || BGP_DEBUG (update, UPDATE_IN)) { ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); - int lvl = (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) - ? LOG_ERR : LOG_DEBUG; - - if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) + int lvl = (ap_ret == BGP_ATTR_PARSE_WITHDRAW) ? LOG_ERR : LOG_DEBUG ; + + if (ap_ret == BGP_ATTR_PARSE_WITHDRAW) zlog (peer->log, LOG_ERR, "%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", peer->host); @@ -1623,7 +1551,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s", peer->host, attrstr); } - + /* Network Layer Reachability Information. */ update_len = end - stream_pnt (s); @@ -1633,9 +1561,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len); if (ret < 0) { - bgp_attr_unintern_sub (&attr); - if (attr.extra) - bgp_attr_extra_free (&attr); + bgp_attr_unintern_sub (&attr, true) ; /* true => free extra */ return -1; } @@ -1661,9 +1587,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) ret = bgp_attr_check (peer, &attr); if (ret < 0) { - bgp_attr_unintern_sub (&attr); - if (attr.extra) - bgp_attr_extra_free (&attr); + bgp_attr_unintern_sub (&attr, true) ; /* true => free extra */ return -1; } @@ -1671,12 +1595,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) } if (mp_update.length - && mp_update.afi == AFI_IP + && 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.afi == AFI_IP && mp_withdraw.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); @@ -1691,19 +1615,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) 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", + zlog (peer->log, LOG_DEBUG, + "rcvd End-of-RIB for IPv4 Unicast from %s", peer->host); } } if (peer->afc[AFI_IP][SAFI_MULTICAST]) { if (mp_update.length - && mp_update.afi == AFI_IP + && 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.afi == AFI_IP && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); @@ -1721,19 +1646,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST); if (BGP_DEBUG (normal, NORMAL)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Multicast from %s", + zlog (peer->log, LOG_DEBUG, + "rcvd End-of-RIB for IPv4 Multicast from %s", peer->host); } } if (peer->afc[AFI_IP6][SAFI_UNICAST]) { - if (mp_update.length - && mp_update.afi == AFI_IP6 + 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 + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); @@ -1743,26 +1669,28 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) && mp_withdraw.length == 0) { /* End-of-RIB received */ - SET_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); /* 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", + 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 + 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 + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); @@ -1778,19 +1706,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) 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", + 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 + if (mp_update.length + && mp_update.afi == AFI_IP && mp_update.safi == BGP_SAFI_VPNV4) bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update); - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == BGP_SAFI_VPNV4) bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw); @@ -1802,32 +1731,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* End-of-RIB received */ if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s", + 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); - if (attr.extra) - bgp_attr_extra_free (&attr); - - /* If peering is stopped due to some reason, do not generate BGP - event. */ - if (peer->status != Established) - return 0; - - /* Increment packet counter. */ - peer->update_in++; - peer->update_time = bgp_clock (); - - /* Generate BGP event. */ - BGP_EVENT_ADD (peer, Receive_UPDATE_message); + bgp_attr_unintern_sub (&attr, true) ; /* true => free extra */ return 0; } +#if 0 /* Notify message treatment function. */ static void bgp_notify_receive (struct peer *peer, bgp_size_t size) @@ -1901,17 +1818,95 @@ bgp_notify_receive (struct peer *peer, bgp_size_t size) BGP_EVENT_ADD (peer, Receive_NOTIFICATION_message); } +#endif +#if 0 /* Keepalive treatment function -- get keepalive send keepalive */ static void bgp_keepalive_receive (struct peer *peer, bgp_size_t size) { - if (BGP_DEBUG (keepalive, KEEPALIVE)) - zlog_debug ("%s KEEPALIVE rcvd", peer->host); - + if (BGP_DEBUG (keepalive, KEEPALIVE)) + zlog_debug ("%s KEEPALIVE rcvd", peer->host); + BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message); } +#endif + +/* Process incoming route refresh */ +void +bgp_route_refresh_recv(bgp_peer peer, bgp_route_refresh rr) +{ + afi_t afi; + safi_t safi; + vector_index i; + char name[BUFSIZ]; + int ret; + + afi = rr->afi; + safi = rr->safi; + + /* Adjust safi code. */ + if (safi == BGP_SAFI_VPNV4) + safi = SAFI_MPLS_VPN; + + /* ORF prefix-list name */ + ret = snprintf (name, BUFSIZ, "%s.%d.%d", peer->host, afi, safi); + assert(ret < BUFSIZ); + + if (rr->entries.end > 0) + { + for (i = 0; i < rr->entries.end; ++i) + { + bgp_orf_entry orfep = vector_slot(&rr->entries, i); + + /* ignore unknown */ + if (orfep->unknown) + continue; + if (orfep->orf_type == BGP_ORF_T_PREFIX) + { + if (orfep->remove_all) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_debug ("%s rcvd Remove-All pfxlist ORF request", + peer->host); + prefix_bgp_orf_remove_all (name); + break; + } + + ret = prefix_bgp_orf_set (name, afi, &orfep->body.orf_prefix, + orfep->deny, orfep->remove); + + if (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); + break; + } + + peer->orf_plist[afi][safi] = + prefix_list_lookup (AFI_ORF_PREFIX, name); + } + } + + if (BGP_DEBUG (normal, NORMAL)) + zlog_debug ("%s rcvd Refresh %s ORF request", peer->host, + rr->defer ? "Defer" : "Immediate"); + if (rr->defer) + return; + } + + /* First update is deferred until ORF or ROUTE-REFRESH is received */ + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) + UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); + + /* Perform route refreshment to the peer */ + bgp_announce_route (peer, afi, safi); +} + +#if 0 /* Route refresh message is received. */ static void bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) @@ -1926,24 +1921,23 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) { plog_err (peer->log, "%s [Error] BGP route refresh is not enabled", peer->host); - bgp_notify_send (peer, - BGP_NOTIFY_HEADER_ERR, - BGP_NOTIFY_HEADER_BAD_MESTYPE); + bgp_peer_down_error (peer, BGP_NOTIFY_HEADER_ERR, + BGP_NOTIFY_HEADER_BAD_MESTYPE); return; } /* Status must be Established. */ - if (peer->status != Established) + if (peer->status != Established) { plog_err (peer->log, "%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); + bgp_peer_down_error (peer, BGP_NOTIFY_FSM_ERR, 0); return; } s = peer->ibuf; - + /* Parse packet. */ afi = stream_getw (s); reserved = stream_getc (s); @@ -1980,7 +1974,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5) { zlog_info ("%s ORF route refresh length error", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0); return; } @@ -1989,9 +1983,9 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) while ((stream_pnt (s) + 2) < end) { - orf_type = stream_getc (s); + orf_type = stream_getc (s); orf_len = stream_getw (s); - + /* orf_len in bounds? */ if ((stream_pnt (s) + orf_len) > end) break; /* XXX: Notify instead?? */ @@ -2018,8 +2012,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) * and 7 bytes of ORF Address-filter entry from the stream */ if (orf_len < 7) - break; - + break; + /* ORF prefix-list name */ sprintf (name, "%s.%d.%d", peer->host, afi, safi); @@ -2077,13 +2071,13 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d%s", peer->host, - (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"), + (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"), (common & ORF_COMMON_PART_DENY ? "deny" : "permit"), - orfp.seq, + orfp.seq, inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ), orfp.p.prefixlen, orfp.ge, orfp.le, ok ? "" : " MALFORMED"); - + if (ok) ret = prefix_bgp_orf_set (name, afi, &orfp, (common & ORF_COMMON_PART_DENY ? 0 : 1 ), @@ -2117,6 +2111,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) /* Perform route refreshment to the peer */ bgp_announce_route (peer, afi, safi); } +#endif static int bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) @@ -2133,24 +2128,26 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) end = pnt + length; while (pnt < end) - { + { /* We need at least action, capability code and capability length. */ if (pnt + 3 > end) { zlog_info ("%s Capability length error", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + /* TODO: Is this the right notification ?? */ + bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0); return -1; } action = *pnt; hdr = (struct capability_header *)(pnt + 1); - + /* Action value check. */ if (action != CAPABILITY_ACTION_SET && action != CAPABILITY_ACTION_UNSET) { zlog_info ("%s Capability Action Value error %d", peer->host, action); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + /* TODO: Is this the right notification ?? */ + bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0); return -1; } @@ -2162,7 +2159,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) if ((pnt + hdr->length + 3) > end) { zlog_info ("%s Capability length error", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + /* TODO: Is this the right notification ?? */ + bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0); return -1; } @@ -2178,7 +2176,7 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) /* Ignore capability when override-capability is set. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) continue; - + if (!bgp_afi_safi_valid_indices (afi, &safi)) { if (BGP_DEBUG (normal, NORMAL)) @@ -2186,15 +2184,15 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) "(%u/%u)", peer->host, afi, safi); continue; } - + /* Address family check. */ if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u", peer->host, - action == CAPABILITY_ACTION_SET + action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", ntohs(mpc.afi) , mpc.safi); - + if (action == CAPABILITY_ACTION_SET) { peer->afc_recv[afi][safi] = 1; @@ -2208,11 +2206,20 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) { peer->afc_recv[afi][safi] = 0; peer->afc_nego[afi][safi] = 0; + bool completed ; if (peer_active_nego (peer)) - bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL); + completed = bgp_clear_routes (peer, afi, safi, false); else + { + completed = true ; + /* TODO: only used for unit tests. Test will need fixing */ +#if 0 BGP_EVENT_ADD (peer, BGP_Stop); +#endif + } ; + /* if bgp_clear_routes does not complete. what do we do ? */ + passert(completed) ; } } else @@ -2225,10 +2232,10 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) return 0; } -/* Dynamic Capability is received. +/* Dynamic Capability is received. * * This is exported for unit-test purposes - */ + */ extern int bgp_capability_receive(struct peer*, bgp_size_t) ; int bgp_capability_receive (struct peer *peer, bgp_size_t size) { @@ -2245,25 +2252,26 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size) { plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled", peer->host); - bgp_notify_send (peer, - BGP_NOTIFY_HEADER_ERR, - BGP_NOTIFY_HEADER_BAD_MESTYPE); + bgp_peer_down_error (peer, BGP_NOTIFY_HEADER_ERR, + BGP_NOTIFY_HEADER_BAD_MESTYPE); return -1; } /* Status must be Established. */ - if (peer->status != Established) + if (peer->state != bgp_peer_pEstablished) { plog_err (peer->log, - "%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); + "%s [Error] Dynamic capability packet received under status %s", + peer->host, LOOKUP (bgp_status_msg, peer->state)); + bgp_peer_down_error (peer, BGP_NOTIFY_FSM_ERR, 0); return -1; } /* Parse packet. */ return bgp_capability_msg_parse (peer, pnt, size); } - + +#if 0 /* BGP read utility function. */ static int bgp_read_packet (struct peer *peer) @@ -2281,7 +2289,7 @@ bgp_read_packet (struct peer *peer) nbytes = stream_read_try (peer->ibuf, peer->fd, readsize); /* If read byte is smaller than zero then error occured. */ - if (nbytes < 0) + if (nbytes < 0) { /* Transient error should retry */ if (nbytes == -2) @@ -2290,7 +2298,7 @@ bgp_read_packet (struct peer *peer) plog_err (peer->log, "%s [Error] bgp_read_packet error: %s", peer->host, safe_strerror (errno)); - if (peer->status == Established) + if (peer->status == Established) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) { @@ -2303,16 +2311,16 @@ bgp_read_packet (struct peer *peer) BGP_EVENT_ADD (peer, TCP_fatal_error); return -1; - } + } /* When read byte is zero : clear bgp peer and return */ - if (nbytes == 0) + if (nbytes == 0) { if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] BGP connection closed fd %d", peer->host, peer->fd); - if (peer->status == Established) + if (peer->status == Established) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) { @@ -2333,7 +2341,9 @@ bgp_read_packet (struct peer *peer) return 0; } +#endif +#if 0 /* Marker check. */ static int bgp_marker_all_one (struct stream *s, int length) @@ -2346,7 +2356,9 @@ bgp_marker_all_one (struct stream *s, int length) return 1; } +#endif +#if 0 /* Starting point of packet process function. */ int bgp_read (struct thread *thread) @@ -2386,7 +2398,7 @@ bgp_read (struct thread *thread) ret = bgp_read_packet (peer); /* Header read error or partial read packet. */ - if (ret < 0) + if (ret < 0) goto done; /* Get size and type. */ @@ -2403,15 +2415,14 @@ bgp_read (struct thread *thread) if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE)) && ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE)) { - bgp_notify_send (peer, - BGP_NOTIFY_HEADER_ERR, - BGP_NOTIFY_HEADER_NOT_SYNC); + bgp_peer_down_error (peer, BGP_NOTIFY_HEADER_ERR, + BGP_NOTIFY_HEADER_NOT_SYNC); goto done; } /* BGP type check. */ - if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE - && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE + if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE + && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE && type != BGP_MSG_ROUTE_REFRESH_NEW && type != BGP_MSG_ROUTE_REFRESH_OLD && type != BGP_MSG_CAPABILITY) @@ -2440,7 +2451,7 @@ bgp_read (struct thread *thread) if (BGP_DEBUG (normal, NORMAL)) plog_debug (peer->log, "%s bad message length - %d for %s", - peer->host, size, + peer->host, size, type == 128 ? "ROUTE-REFRESH" : bgp_type_str[(int) type]); bgp_notify_send_with_data (peer, @@ -2455,7 +2466,7 @@ bgp_read (struct thread *thread) } ret = bgp_read_packet (peer); - if (ret < 0) + if (ret < 0) goto done; /* Get size and type again. */ @@ -2464,11 +2475,11 @@ bgp_read (struct thread *thread) /* BGP packet dump function. */ bgp_dump_packet (peer, type, peer->ibuf); - + size = (peer->packet_size - BGP_HEADER_SIZE); /* Read rest of the packet and call each sort of packet routine */ - switch (type) + switch (type) { case BGP_MSG_OPEN: peer->open_in++; @@ -2506,7 +2517,8 @@ bgp_read (struct thread *thread) { if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s [Event] Accepting BGP peer delete", peer->host); - peer_delete (peer); + bgp_peer_delete (peer); } return 0; } +#endif |