diff options
-rw-r--r-- | bgpd/bgp_advertise.c | 43 | ||||
-rw-r--r-- | bgpd/bgp_advertise.h | 2 | ||||
-rw-r--r-- | bgpd/bgp_aspath.c | 3 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 40 | ||||
-rw-r--r-- | bgpd/bgp_attr.h | 8 | ||||
-rw-r--r-- | bgpd/bgp_msg_write.c | 25 | ||||
-rw-r--r-- | bgpd/bgp_names.c | 13 | ||||
-rw-r--r-- | bgpd/bgp_names.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 583 | ||||
-rw-r--r-- | bgpd/bgp_peer.c | 28 | ||||
-rw-r--r-- | bgpd/bgp_peer.h | 10 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 3 | ||||
-rwxr-xr-x | configure.ac | 2 | ||||
-rw-r--r-- | lib/qpthreads.c | 81 | ||||
-rw-r--r-- | lib/qpthreads.h | 3 | ||||
-rw-r--r-- | lib/stream.h | 23 | ||||
-rw-r--r-- | vtysh/vtysh_config.c | 2 |
17 files changed, 695 insertions, 175 deletions
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 7246bab1..37fad456 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -101,24 +101,40 @@ bgp_advertise_free (struct bgp_advertise *adv) static void bgp_advertise_add (struct bgp_advertise_attr *baa, - struct bgp_advertise *adv) + bgp_advertise adv) { - adv->adv_next = baa->adv; - if (baa->adv) - baa->adv->adv_prev = adv; - baa->adv = adv; + bgp_advertise last ; + + if (baa->base.head == NULL) + { + last = NULL ; + baa->base.head = adv ; + } + else + { + last = baa->base.tail ; + last->adv_next = adv ; + } ; + + adv->adv_next = NULL ; + adv->adv_prev = last ; + + baa->base.tail = adv ; } static void bgp_advertise_delete (struct bgp_advertise_attr *baa, struct bgp_advertise *adv) { - if (adv->adv_next) + if (adv->adv_next != NULL) adv->adv_next->adv_prev = adv->adv_prev; - if (adv->adv_prev) + else + baa->base.tail = adv->adv_prev ; + + if (adv->adv_prev != NULL) adv->adv_prev->adv_next = adv->adv_next; else - baa->adv = adv->adv_next; + baa->base.head = adv->adv_next; } static struct bgp_advertise_attr * @@ -191,7 +207,7 @@ bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj, bgp_advertise_delete (baa, adv); /* Fetch next advertise candidate. */ - next = baa->adv; + next = baa->base.head ; /* Unintern BGP advertise attribute. */ bgp_advertise_unintern (peer->hash[afi][safi], baa); @@ -296,10 +312,10 @@ bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p, assert(rn == adj->rn) ; /* Clear up previous advertisement. */ - if (adj->adv) + if (adj->adv != NULL) bgp_advertise_clean (peer, adj, afi, safi); - if (adj->attr) + if (adj->attr != NULL) { /* We need advertisement structure. */ adj->adv = bgp_advertise_new (); @@ -310,8 +326,9 @@ bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p, /* Add to synchronization entry for withdraw announcement */ bgp_advertise_fifo_add(&peer->sync[afi][safi]->withdraw, adv); - /* Schedule packet write. */ - bgp_write(peer, NULL) ; + /* Schedule flush of withdraws + */ + bgp_withdraw_schedule(peer) ; } else bgp_adj_out_remove(rn, adj, peer, afi, safi) ; diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index afa812f6..6e974594 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -45,7 +45,7 @@ struct bgp_advertise_fifo_base struct bgp_advertise_attr { /* Head of advertisement pointer. */ - struct bgp_advertise *adv; + struct bgp_advertise_fifo_base base ; /* Reference counter. */ unsigned long refcnt; diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 6b7fedd5..5227a1a6 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -333,8 +333,7 @@ aspath_unintern (struct aspath **aspath) struct aspath *ret; struct aspath *asp = *aspath; - if (asp->refcnt) - asp->refcnt--; + asp->refcnt--; if (asp->refcnt == 0) { diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index c6c77f88..0cbf6b94 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -755,6 +755,8 @@ bgp_attr_unintern_sub (struct attr *attr, bool free_extra) * * Can do this to an attribute object which has not been interned, because its * reference count SHOULD be zero. + * + * Sets *attr = NULL iff the attributes are discarded. */ void bgp_attr_unintern (struct attr **attr) @@ -1664,7 +1666,7 @@ bgp_mp_reach_parse (bgp_attr_parser_args args) siptoa(AF_INET6, &attre->mp_nexthop_global).str, siptoa(AF_INET6, &attre->mp_nexthop_local).str) ; - attre->mp_nexthop_len = 16; + nexthop_len = 16; /* discard mp_nexthop_local */ } break; #endif /* HAVE_IPV6 */ @@ -2418,7 +2420,6 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change * all ASnums > 65535 to BGP_AS_TRANS */ - stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_AS_PATH); aspath_sizep = stream_get_endp (s); @@ -2635,6 +2636,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, if (p->family == AF_INET && safi == SAFI_MPLS_VPN) { unsigned long sizep; + uint tp ; stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_MP_REACH_NLRI); @@ -2653,7 +2655,11 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, /* Tag, RD, Prefix write. */ stream_putc (s, p->prefixlen + 88); - stream_put (s, tag, 3); + stream_put (s, tag, 3); /* zeros if tag == NULL */ + + tp = stream_get_endp (s) - 1 ; + stream_putc_at(s, tp, stream_getc_from(s, tp) | 1) ; + stream_put (s, prd->val, 8); stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); @@ -2785,9 +2791,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } bgp_size_t -bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, - afi_t afi, safi_t safi, struct prefix_rd *prd, - u_char *tag) +bgp_packet_withdraw (struct stream *s, struct prefix *p, + afi_t afi, safi_t safi, struct prefix_rd *prd) { unsigned long cp; unsigned long attrlen_pnt; @@ -2801,25 +2806,16 @@ bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, attrlen_pnt = stream_get_endp (s); stream_putc (s, 0); /* Length of this attribute. */ - stream_putw (s, family2afi (p->family)); + stream_putw (s, afi); if (safi == SAFI_MPLS_VPN) { - /* SAFI */ stream_putc (s, SAFI_MPLS_LABELED_VPN); - - /* prefix. */ - stream_putc (s, p->prefixlen + 88); - stream_put (s, tag, 3); - stream_put (s, prd->val, 8); - stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); + bgp_packet_withdraw_vpn_prefix (s, p, prd) ; } else { - /* SAFI */ stream_putc (s, safi); - - /* prefix */ stream_put_prefix (s, p); } @@ -2830,6 +2826,16 @@ bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, return stream_get_endp (s) - cp; } +void +bgp_packet_withdraw_vpn_prefix (struct stream *s, struct prefix *p, + struct prefix_rd *prd) +{ + stream_putc (s, p->prefixlen + (( 3 + 8) * 8)); + stream_put (s, "\x00\x00\x01", 3); + stream_put (s, prd->val, 8); + stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); +} + /* Initialization of attribute. */ void bgp_attr_init (void) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 553a91b5..748a5dc7 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -193,9 +193,11 @@ extern bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct prefix *, afi_t, safi_t, struct peer *, struct prefix_rd *, u_char *); -extern bgp_size_t bgp_packet_withdraw (struct peer *peer, struct stream *s, - struct prefix *p, afi_t, safi_t, - struct prefix_rd *, u_char *); +extern bgp_size_t bgp_packet_withdraw (struct stream *s, struct prefix *p, + afi_t, safi_t, struct prefix_rd *); +extern void bgp_packet_withdraw_vpn_prefix(struct stream *s, struct prefix *p, + struct prefix_rd *prd) ; + extern void bgp_dump_routes_attr (struct stream *, struct attr *, struct prefix *); extern int attrhash_cmp (const void *, const void *); diff --git a/bgpd/bgp_msg_write.c b/bgpd/bgp_msg_write.c index 3020ef7e..3e1ba205 100644 --- a/bgpd/bgp_msg_write.c +++ b/bgpd/bgp_msg_write.c @@ -81,6 +81,8 @@ * fail ! * * NB: requires the session LOCKED -- connection-wise + * + * NB: clamps the length of the data to fit in the maximum size BGP message. */ extern int bgp_msg_write_notification(bgp_connection connection, bgp_notify notification) @@ -109,8 +111,14 @@ bgp_msg_write_notification(bgp_connection connection, bgp_notify notification) if (length != 0) stream_put(s, bgp_notify_get_data(notification), length) ; - /* Set BGP packet length. + /* Set BGP packet length -- clamping to maximum (if required) */ + if (bgp_packet_check_size(s, connection->su_remote) == 0) + { + stream_set_endp(s, BGP_MSG_MAX_L) ; + stream_clear_overflow(s) ; + } ; + bgp_packet_set_size(s); /* Set flag so that write_action raises required event when buffer becomes @@ -151,7 +159,8 @@ bgp_msg_send_keepalive(bgp_connection connection, bool must_send) ++connection->session->stats.keepalive_out ; - /* Make KEEPALIVE message -- comprises header only */ + /* Make KEEPALIVE message -- comprises header only, so guaranteed to fit ! + */ bgp_packet_set_marker(s, BGP_MSG_KEEPALIVE); length = bgp_packet_set_size(s); @@ -218,6 +227,9 @@ bgp_msg_send_open(bgp_connection connection, bgp_open_state open_state) bgp_open_options(s, open_state, connection->cap_suppress) ; /* Set BGP message length. + * + * Cannot overflow the BGP Message size, and if it did, there is damn all + * we could do about it ! */ length = bgp_packet_set_size(s) ; @@ -517,11 +529,14 @@ bgp_msg_send_route_refresh(bgp_connection connection, bgp_route_refresh rr) stream_putc(s, 0); stream_putc(s, rr->safi); - /* Process as many (remaining) ORF entries as can into message */ + /* Process as many (remaining) ORF entries as can into message + */ if (!done) done = bgp_msg_orf_part(s, connection, rr) ; - /* Set BGP message length & dispatch. */ + /* Set BGP message length & dispatch -- noting that orf entry + * construction ensures that the length does not exceed the maximum. + */ length = bgp_packet_set_size(s) ; if (BGP_DEBUG (normal, NORMAL)) @@ -831,6 +846,8 @@ bgp_msg_send_end_of_rib(bgp_connection connection, iAFI_t afi, iSAFI_t safi) stream_putw_at(s, attrp-2, stream_get_endp(s) - attrp) ; } + /* Cannot overflow BGP Message + */ bgp_packet_set_size(s); if (BGP_DEBUG (normal, NORMAL)) diff --git a/bgpd/bgp_names.c b/bgpd/bgp_names.c index 89623246..b22b7d11 100644 --- a/bgpd/bgp_names.c +++ b/bgpd/bgp_names.c @@ -260,3 +260,16 @@ const char* bgp_afi_name_map_body[] = const map_direct_t bgp_afi_name_map = map_direct_s(bgp_afi_name_map_body, "unknown AFI(%u)") ; +/*------------------------------------------------------------------------------ + * SAFI names + */ +const char* bgp_safi_name_map_body[] = +{ + [SAFI_UNICAST] = "SAFI_UNICAST", + [SAFI_MULTICAST] = "SAFI_MULTICAST", + [SAFI_MPLS_VPN] = "SAFI_MPLS_VPN", +}; + +const map_direct_t bgp_safi_name_map = + map_direct_s(bgp_safi_name_map_body, "unknown SAFI(%u)") ; + diff --git a/bgpd/bgp_names.h b/bgpd/bgp_names.h index ab688575..e72cfaa7 100644 --- a/bgpd/bgp_names.h +++ b/bgpd/bgp_names.h @@ -43,5 +43,6 @@ extern const map_direct_t bgp_origin_short_map ; extern const map_direct_t bgp_origin_long_map ; extern const map_direct_t bgp_attr_name_map ; extern const map_direct_t bgp_afi_name_map ; +extern const map_direct_t bgp_safi_name_map ; #endif /* _QUAGGA_BGP_NAMES_H */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 74eed451..88254e5a 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -27,7 +27,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "log.h" #include "memory.h" -#include "sockunion.h" /* for inet_ntop () */ #include "linklist.h" #include "bgpd/bgpd.h" @@ -53,6 +52,312 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_names.h" #include "bgpd/bgp_msg_write.h" +/* Prototypes + */ +static bgp_advertise bgp_updated(bgp_peer peer, bgp_advertise adv, + afi_t afi, safi_t safi, qstring updates, + bool suppressed) ; + +/*------------------------------------------------------------------------------ + * Construct an update from the given bgp_advertise object. + * + * Generates complete BGP message in the peer->work stream structure. + * + * Returns: peer->work -- if have something to be written. + * NULL -- otherwise + * + * NB: if the attributes overflow the BGP message, suppresses the update and + * issues a withdraw for the affected prefixes if required. + */ +static struct stream * +bgp_update_packet (bgp_peer peer, bgp_advertise adv, afi_t afi, safi_t safi) +{ + struct stream *s; + struct bgp_node *rn ; + struct bgp_info *binfo ; + ulen attr_lp ; + ulen attr_len ; + struct prefix_rd *prd ; + u_char *tag ; + struct peer *from ; + qstring updates ; + uint count ; + bool ipv4_unicast ; + + qassert(adv != NULL) ; + + ipv4_unicast = (afi == AFI_IP) && (safi == SAFI_UNICAST) ; + + s = peer->work; + stream_reset (s); + + if (BGP_DEBUG (update, UPDATE_OUT)) + updates = qs_new(100) ; + else + updates = NULL ; + + count = 0 ; + + /* Generate the attributes part of the message. + * + * If is not AFI_IP/SAFI_UNICAST, includes the first prefix on the list. + * + * NB: this sends only one prefix per message if is not AFI_IP/SAFI_UNICAST. + */ + prd = NULL; + rn = adv->rn ; + assert(rn != NULL) ; + if (rn->prn != NULL) + prd = (struct prefix_rd *) &rn->prn->p ; + + tag = NULL; + from = NULL; + binfo = adv->binfo ; + if (binfo != NULL) + { + from = binfo->peer; + if (binfo->extra) + tag = binfo->extra->tag; + } ; + + bgp_packet_set_marker (s, BGP_MSG_UPDATE); + stream_putw (s, 0); /* No AFI_IP/SAFI_UNICAST withdrawn */ + + attr_lp = stream_get_endp (s); + qassert(attr_lp == (BGP_MH_HEAD_L + 2)) ; + + stream_putw (s, 0); /* Attributes length */ + + attr_len = bgp_packet_attribute (NULL, peer, s, + adv->baa->attr, + &rn->p, afi, safi, + from, prd, tag); + stream_putw_at (s, attr_lp, attr_len) ; + + /* For AFI_IP/SAFI_UNICAST, append the first prefix. + * + * Once we have done this, all AFI/SAFI are in the same state, we have + * the attributes and one prefix in the message. + */ + if (ipv4_unicast) + stream_put_prefix (s, &rn->p); + + /* If the attributes with at least one prefix have fitted, then all is well, + * and for AFI_IP/SAFI_UNICAST we can tack on other prefixes which share the + * current attributes. + * + * Otherwise, we have a problem, and we issue a route withdraw, instead. + * + * NB: we allocate BGP_STREAM_SIZE, which is larger than BGP_MSG_MAX_L, + * so that if the overflow is marginal, we can tell what it was. + */ + if (bgp_packet_check_size(s, peer->su_remote) > 0) + { + /* Eat the prefix we have already included in the message. + * + * Then for AFI_IP/SAFI_UNICAST, eat as many further prefixes as we can + * fit into the message. + */ + if (ipv4_unicast) + { + qassert(!stream_has_overflowed(s)) ; + + while (1) + { + ulen len_was ; + + adv = bgp_updated(peer, adv, afi, safi, updates, + false /* not suppressed */) ; + ++count ; + + if (adv == NULL) + break ; + + rn = adv->rn ; + assert(rn != NULL); + + len_was = stream_get_len(s) ; + stream_put_prefix (s, &rn->p) ; + + if (stream_has_written_beyond(s, BGP_MSG_MAX_L)) + { + stream_set_endp(s, len_was) ; + stream_clear_overflow(s) ; + break ; + } ; + } ; + } + else + { + bgp_updated(peer, adv, afi, safi, updates, + false /* not suppressed */) ; + ++count ; + } ; + + /* Report the update if required. + */ + if (updates != NULL) + { + zlog (peer->log, LOG_DEBUG, "%s send %u UPDATE(S) %s/%s:%s", + peer->host, count, + map_direct(bgp_afi_name_map, afi).str, + map_direct(bgp_safi_name_map, safi).str, + qs_string(updates)) ; + qs_free(updates) ; + } ; + } + else + { + /* Turn advertisement into withdraw of prefixes for which we are + * completely unable to generate an update message. + * + * NB: the result looks as though the prefixes *have* been advertised. + * + * This avoids trying to send the same set of attributes again... + * + * ...but is not a complete solution, yet. TODO + */ + uint withdrawn = 0 ; + + if (updates == NULL) + updates = qs_new(100) ; + + stream_set_endp(s, attr_lp) ; /* as you was */ + stream_clear_overflow(s) ; + + qassert(attr_lp == (BGP_MH_HEAD_L + 2)) ; + + if (ipv4_unicast) + { + /* Fill in withdrawn AFI_IP/SAFI_UNICAST + * + * We are guaranteed to be able to fit at least one withdraw ! + * Cope with running out of room in the message, though. + */ + ulen start ; + + qassert(!stream_has_overflowed(s)) ; + + start = attr_lp ; /* start of withdrawn nlri */ + + while(1) + { + if (adv->adj->attr != NULL) + { + stream_put_prefix (s, &rn->p); + + if (stream_has_written_beyond(s, BGP_MSG_MAX_L - 2)) + { + stream_set_endp(s, attr_lp) ; /* back one */ + stream_clear_overflow(s) ; + break ; + } ; + + ++withdrawn ; + } ; + + attr_lp = stream_get_endp(s) ; + + adv = bgp_updated(peer, adv, afi, safi, updates, + true /*suppressed */) ; + ++count ; + + if (adv == NULL) + break ; + + rn = adv->rn ; + assert(rn != NULL); + } ; + + stream_putw_at(s, start - 2, attr_lp - start) ; + stream_putw(s, 0) ; + } + else + { + if (adv->adj->attr != NULL) + { + stream_putw (s, 0); /* Attributes length */ + + attr_len = bgp_packet_withdraw (s, &rn->p, afi, safi, prd); + stream_putw_at (s, attr_lp, attr_len); + ++withdrawn ; + } ; + + bgp_updated(peer, adv, afi, safi, updates, true /*suppressed */) ; + ++count ; + } ; + + /* Now log the error + */ + zlog_err("%s FORCED %u/%u WITHDRAW(S) %s/%s:%s", + peer->host, withdrawn, count, + map_direct(bgp_afi_name_map, afi).str, + map_direct(bgp_safi_name_map, safi).str, + qs_string(updates)) ; + qs_free(updates) ; + + /* If we have no actual withdraws, exit now + */ + if (withdrawn == 0) + return NULL ; + } ; + + /* The message is complete -- and kept to size, above. + */ + bgp_packet_set_size (s) ; + + return s ; +} ; + +/*------------------------------------------------------------------------------ + * Have added the prefix for the given advertisement to the UPDATE message + * in construction. + * + * Update corresponding adjacency to reflect the attributes last sent for + * the prefix. This either replaces the existing attributes, or sets a new + * set. If setting a new set, we increment the count of prefixes sent. + * + * Then remove the bgp_advertise object from the lists it lives on, and + * return the next (which will have the same attributes), if any. + */ +static bgp_advertise +bgp_updated(bgp_peer peer, bgp_advertise adv, afi_t afi, safi_t safi, + qstring updates, bool suppressed) +{ + struct bgp_adj_out *adj; + + if (updates != NULL) + { + qs_append_str(updates, " ") ; + qs_append_str(updates, spfxtoa(&adv->rn->p).str) ; + } ; + + adj = adv->adj ; + + if (suppressed) + { + if (adj->attr != NULL) + { + bgp_attr_unintern (&adj->attr); + adj->attr = NULL ; + peer->scount[afi][safi]--; + } ; + } + else + { + if (adj->attr != NULL) + bgp_attr_unintern (&adj->attr); + else + peer->scount[afi][safi]++; + + adj->attr = bgp_attr_intern (adv->baa->attr); + } ; + + return bgp_advertise_clean (peer, adj, afi, safi) ; +} ; + +#if 0 // Replaced by the above + /*------------------------------------------------------------------------------ * Construct an update from head of peer->sync[afi][safi]->update. * @@ -146,6 +451,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) bgp_packet_set_size (s) ; return s ; } +#endif /*------------------------------------------------------------------------------ * Construct an End-of-RIB update message for given AFI/SAFI. @@ -164,7 +470,8 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) return NULL; if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi), peer->host); + zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi), + peer->host); s = peer->work; stream_reset (s); @@ -175,7 +482,7 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) /* Unfeasible Routes Length */ stream_putw (s, 0); - if (afi == AFI_IP && safi == SAFI_UNICAST) + if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { /* Total Path Attribute Length */ stream_putw (s, 0); @@ -191,6 +498,8 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) stream_putc (s, safi); } + /* Cannot exceed maximum message size ! + */ bgp_packet_set_size (s); return s ; } @@ -202,6 +511,8 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) * * Returns: peer->work -- if have something to be written. * NULL -- otherwise + * + * NB: returns NULL iff the peer's withdraw queue is empty. */ static struct stream * bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) @@ -210,73 +521,122 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) struct bgp_adj_out *adj; struct bgp_advertise *adv; struct bgp_node *rn; - unsigned long pos; - bgp_size_t unfeasible_len; - bgp_size_t total_attr_len; - char buf[BUFSIZ]; + uint withdrawn ; + qstring updates ; + bool ipv4_unicast ; + ulen len_p, len_ap, limit, end_p ; + + if (BGP_DEBUG (update, UPDATE_OUT)) + updates = qs_new(100) ; + else + updates = NULL ; + + ipv4_unicast = (afi == AFI_IP) && (safi == SAFI_UNICAST) ; s = peer->work; stream_reset (s); + bgp_packet_set_marker (s, BGP_MSG_UPDATE); + stream_putw (s, 0) ; /* Withdraw length */ + + if (ipv4_unicast) + { + len_p = stream_get_endp(s) ; + len_ap = 0 ; + limit = BGP_MSG_MAX_L - 2 ; + } + else + { + stream_putw(s, 0) ; /* Attributes length */ + + len_p = stream_get_endp(s) ; + + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN) ; + stream_putc(s, BGP_ATTR_MP_UNREACH_NLRI) ; + stream_putw(s, 0) ; + + len_ap = stream_get_endp(s) ; + limit = BGP_MSG_MAX_L ; + + stream_putw (s, afi); + + if (safi == SAFI_MPLS_VPN) + stream_putc (s, SAFI_MPLS_LABELED_VPN); + else + stream_putc (s, safi); + } ; + + withdrawn = 0 ; + end_p = stream_get_endp(s) ; + while ((adv = bgp_advertise_fifo_head(&peer->sync[afi][safi]->withdraw)) != NULL) { - assert (adv->rn); adj = adv->adj; - rn = adv->rn; + rn = adv->rn; + assert (rn != NULL); - if (STREAM_REMAIN (s) - < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) - break; - - if (stream_is_empty (s)) - { - bgp_packet_set_marker (s, BGP_MSG_UPDATE); - stream_putw (s, 0); - } + if (adj->attr != NULL) + { + if (safi != SAFI_MPLS_VPN) + stream_put_prefix(s, &rn->p); + else + bgp_packet_withdraw_vpn_prefix(s, &rn->p, + (struct prefix_rd *) &rn->prn->p) ; - if (afi == AFI_IP && safi == SAFI_UNICAST) - stream_put_prefix (s, &rn->p); - else - { - struct prefix_rd *prd = NULL; + if (stream_has_written_beyond(s, limit)) + { + stream_set_endp(s, end_p) ; /* as you was */ + stream_clear_overflow(s) ; - 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); + break ; + } ; - /* Set total path attribute length. */ - stream_putw_at (s, pos, total_attr_len); - } + end_p = stream_get_endp(s) ; - if (BGP_DEBUG (update, UPDATE_OUT)) - zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", - peer->host, - inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ), - rn->p.prefixlen); + peer->scount[afi][safi]--; + ++withdrawn ; - peer->scount[afi][safi]--; + if (updates != NULL) + { + qs_append_str(updates, " ") ; + qs_append_str(updates, spfxtoa(&rn->p).str) ; + } ; + } ; bgp_adj_out_remove (rn, adj, peer, afi, safi); - - if (! (afi == AFI_IP && safi == SAFI_UNICAST)) - break; } - if (stream_is_empty (s)) + if (withdrawn == 0) return NULL ; - if (afi == AFI_IP && safi == SAFI_UNICAST) + /* For ipv4_unicast: set Withdrawn Routes Length + * then set Total Path Attributes Length == 0 + * + * otherwise: set Total Path Attributes Length + * then set length of the MP_UNREACH attribute + */ + stream_putw_at(s, len_p - 2, end_p - len_p) ; + + if (ipv4_unicast) + stream_putw(s, 0) ; /* no attributes */ + else + stream_putw_at(s, len_ap - 2, end_p - len_ap) ; + + /* Debug logging as required + */ + if (updates != NULL) { - 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); + zlog (peer->log, LOG_DEBUG, "%s send %u WITHDRAW(S) %s/%s:%s", + peer->host, withdrawn, + map_direct(bgp_afi_name_map, afi).str, + map_direct(bgp_safi_name_map, safi).str, + qs_string(updates)) ; + qs_free(updates) ; } ; + /* Kept within maximum message length, above. + */ bgp_packet_set_size (s); return s ; } @@ -285,6 +645,17 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) * Construct an update for the default route, place it in the obuf queue * and kick write. * + * Note that this jumps all queues -- because the default route generated is + * special. Also, this is called (a) when a table is about to be announced, so + * this will be the first route sent and (b) when the configuration option + * is set, so the ordering wrt other routes and routeadv timer is moot. + * + * Note that this may also trigger the output of pending withdraws and updates. + * Tant pis. + * + * Note also that it is assumed that (a) the attributes are essentially + * trivial, and (b) that they are 99.9% likely to be unique. + * * Uses peer->work stream structure, but copies result to new stream, which is * pushed onto the obuf queue. */ @@ -321,25 +692,29 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, s = peer->work ; stream_reset (s); - /* Make BGP update packet. */ + /* Make BGP update packet and set empty withdrawn NLRI + */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); - - /* Unfeasible Routes Length. */ stream_putw (s, 0); - /* Make place for total attribute length. */ + /* Construct attribute -- including NLRI for not AFI_IP/SAFI_UNICAST + */ pos = stream_get_endp (s); stream_putw (s, 0); - total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL); - /* Set Total Path Attribute Length. */ + total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, + from, NULL, NULL); stream_putw_at (s, pos, total_attr_len); - /* NLRI set. */ + /* NLRI for AFI_IP/SAFI_UNICAST. + */ if (p.family == AF_INET && safi == SAFI_UNICAST) stream_put_prefix (s, &p); - /* Set size. */ + /* Set size -- note that it is essentially impossible that the message has + * overflowed, but if it has there is nothing we can do about it + * other than suppress and treat as error (the default action). + */ bgp_packet_set_size (s); /* Dump packet if debug option is set. */ @@ -355,6 +730,14 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, * Construct a withdraw update for the default route, place it in the obuf * queue and kick write. * + * Note that this jumps even the withdraw queue. This is called when the + * configuration option is unset, so the ordering wrt other routes and + * routeadv timer is moot. If there were other withdraws pending, they could + * be merged in -- but that seems like a lot of work for little benefit. + * + * Note that this may also trigger the output of pending withdraws and updates. + * Tant pis. + * * Uses peer->work stream structure, but copies result to new stream, which is * pushed onto the obuf queue. */ @@ -414,12 +797,14 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) { pos = stream_get_endp (s); stream_putw (s, 0); - total_attr_len = bgp_packet_withdraw (peer, s, &p, afi, safi, NULL, NULL); + total_attr_len = bgp_packet_withdraw (s, &p, afi, safi, NULL); /* Set total path attribute length. */ stream_putw_at (s, pos, total_attr_len); } + /* Impossible to overflow the BGP Message ! + */ bgp_packet_set_size (s); /* Add packet to the peer. */ @@ -439,54 +824,89 @@ bgp_write_packet (struct peer *peer) { afi_t afi; safi_t safi; - struct stream *s = NULL; + struct stream *s ; struct bgp_advertise *adv; + s = NULL ; /* nothing to send, yet */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { adv = bgp_advertise_fifo_head(&peer->sync[afi][safi]->withdraw); if (adv) { + /* Note that -- unlike bgp_update_packet() -- this guarantees to + * generate a packet, unless there is absolutely nothing to be + * withdrawn -- in which case ->withdraw *will* be empty. + */ s = bgp_withdraw_packet (peer, afi, safi); if (s) return s; - } - } + } ; + + qassert(bgp_advertise_fifo_head(&peer->sync[afi][safi]->withdraw) + == NULL) ; + } ; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - adv = bgp_advertise_fifo_head(&peer->sync[afi][safi]->update); - if (adv) + while (1) { - if (adv->binfo && adv->binfo->uptime < peer->synctime) - { - if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV) - && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV) - && ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE) - && safi != SAFI_MPLS_VPN) - { - if (CHECK_FLAG (adv->binfo->peer->af_sflags[afi][safi], - PEER_STATUS_EOR_RECEIVED)) - s = bgp_update_packet (peer, afi, safi); - } - else - s = bgp_update_packet (peer, afi, safi); - } + adv = bgp_advertise_fifo_head(&peer->sync[afi][safi]->update) ; + + if (adv == NULL) + break ; + + if (adv->binfo->uptime >= peer->synctime) + break ; /* leave for later */ + + /* This is waiting for EOR from the peer before sending updates, if + * we are both doing RESTART. + * + * TODO: Not sure why would want to send the earlier update if it + * is BGP_INFO_STALE or MPLS ? + */ + if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV) + && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV) + && ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE) + && safi != SAFI_MPLS_VPN) + { + if (!CHECK_FLAG (adv->binfo->peer->af_sflags[afi][safi], + PEER_STATUS_EOR_RECEIVED)) + break; + } - if (s) + /* We have an adv which want to send. + * + * bgp_update_packet() will always take the adv off the ->update + * list. + * + * Generally it will generate an update packet. However, if the + * attributes are impossible and it is not necessary to withdraw + * any previous announcements, then will return NULL -- and we can + * go on to the next advertisement. + */ + s = bgp_update_packet (peer, adv, afi, safi); + + if (s != NULL) return s; - } + } ; - if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV)) + /* If there is nothing left to advertise, then this is a good moment + * to send an EOR, if one is required. + */ + if ((adv == NULL) && CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV)) { if (peer->afc_nego[afi][safi] && peer->synctime && ! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND) && safi != SAFI_MPLS_VPN) { SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND); - return bgp_update_packet_eor (peer, afi, safi); + s = bgp_update_packet_eor (peer, afi, safi); + + if (s != NULL) + return s; } } } @@ -655,7 +1075,10 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, "Advertising" : "Removing", afi, safi); } - /* Set packet size. */ + /* Set packet size. + * + * Impossible to overflow the BGP Message buffer + */ length = bgp_packet_set_size (s); if (BGP_DEBUG (normal, NORMAL)) diff --git a/bgpd/bgp_peer.c b/bgpd/bgp_peer.c index 2cb58c34..a32f23bc 100644 --- a/bgpd/bgp_peer.c +++ b/bgpd/bgp_peer.c @@ -1756,6 +1756,34 @@ bgp_routeadv_timer (struct thread *thread) return 0; } +static int +bgp_withdraw_event (struct thread *thread) +{ + bgp_peer peer ; + + peer = THREAD_ARG (thread); + peer->t_withdraw = NULL; + + if (BGP_DEBUG (fsm, FSM)) + zlog (peer->log, LOG_DEBUG, + "%s [FSM] bgp_withdraw_event", + peer->host); + + bgp_write(peer, NULL); + return 0; +} + +extern void +bgp_withdraw_schedule(bgp_peer peer) +{ + if (peer->t_withdraw == NULL) + { + /* TODO: replace legacy event use + */ + peer->t_withdraw = thread_add_event(master, bgp_withdraw_event, peer, 0) ; + } ; +} ; + /*------------------------------------------------------------------------------ * BGP Peer Down Causes mapped to strings */ diff --git a/bgpd/bgp_peer.h b/bgpd/bgp_peer.h index 39cb54a5..c5155b3f 100644 --- a/bgpd/bgp_peer.h +++ b/bgpd/bgp_peer.h @@ -379,7 +379,7 @@ struct peer u_int32_t v_gr_restart; /* Threads. */ - struct thread *t_asorig; + struct thread *t_withdraw ; struct thread *t_routeadv; struct thread *t_pmax_restart; struct thread *t_gr_restart; @@ -393,6 +393,8 @@ struct peer struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX]; time_t synctime; + bool do_updates ; + /* Send prefix count. */ unsigned long scount[AFI_MAX][SAFI_MAX]; @@ -448,6 +450,7 @@ struct peer THREAD_TIMER_OFF(T); \ } while (0) +#if 0 #define BGP_EVENT_ADD(P,E) \ do { \ if ((P)->state != bgp_peer_pDeleting) \ @@ -467,8 +470,10 @@ extern int bgp_stop (struct peer *peer); extern void bgp_timer_set (struct peer *); #endif extern void bgp_fsm_change_status (struct peer *peer, int status); -extern const char *peer_down_str[]; +#endif + +extern const char *peer_down_str[]; /*============================================================================== * @@ -491,6 +496,7 @@ extern bgp_peer bgp_peer_unlock (bgp_peer peer) ; extern int bgp_peer_delete (bgp_peer peer); extern sockunion bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname, sa_family_t af) ; +extern void bgp_withdraw_schedule(bgp_peer peer) ; #endif /* _QUAGGA_BGP_PEER_H */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 0ef710c5..aa05c8ac 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1630,7 +1630,8 @@ DEFUN (neighbor_set_peer_group, if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) { - vty_out (vty, "%% Peer with AS %u cannot be in this peer-group, members must be all internal or all external%s", as, VTY_NEWLINE); + vty_out (vty, "%% Peer with AS %u cannot be in this peer-group, " + "members must be all internal or all external%s", as, VTY_NEWLINE); return CMD_WARNING; } diff --git a/configure.ac b/configure.ac index 45653375..48d1b0ca 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.20ex23b, [http://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.20ex24b, [http://bugzilla.quagga.net]) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) diff --git a/lib/qpthreads.c b/lib/qpthreads.c index ebaf6f19..4288b9ff 100644 --- a/lib/qpthreads.c +++ b/lib/qpthreads.c @@ -568,9 +568,8 @@ qpt_thread_create(void* (*start)(void*), void* arg, qpt_thread_attr_t* attr) { qstring qs ; - qs = qpt_thread_attr_form(&thread_attr, " ") ; - - fputs(qs_string(qs), stderr) ; + qs = qpt_thread_attr_form(&thread_attr) ; + zlog_info("Thread created: %s", qs_string(qs)) ; qs_free(qs) ; } @@ -1392,7 +1391,7 @@ qpt_data_delete(qpt_data data) * NB: it is the caller's responsibility to dispose of the qstring */ extern qstring -qpt_thread_attr_form(qpt_thread_attr_t* attr, const char *prefix) +qpt_thread_attr_form(qpt_thread_attr_t* attr) { int err, i ; qstring qs ; @@ -1402,131 +1401,117 @@ qpt_thread_attr_form(qpt_thread_attr_t* attr, const char *prefix) qs = qs_new(500) ; - /* 12345678901234567890 */ - qs_printf_a(qs, "%sDetach state ", prefix) ; err = pthread_attr_getdetachstate(attr, &i); if (err != 0) - qs_printf_a(qs, " *error* %s\n", errtoa(err, 0).str) ; + qs_printf_a(qs, "[getdetachstate *error* %s]", errtoa(err, 0).str) ; else { switch(i) { case PTHREAD_CREATE_DETACHED: - qs_printf_a(qs, "= %s\n", "PTHREAD_CREATE_DETACHED") ; + qs_printf_a(qs, "Detached") ; break ; case PTHREAD_CREATE_JOINABLE: - qs_printf_a(qs, "= %s\n", "PTHREAD_CREATE_JOINABLE") ; + qs_printf_a(qs, "Joinable") ; break ; default: - qs_printf_a(qs, "= *UNKNOWN* %d\n", i) ; + qs_printf_a(qs, "[getdetachstate *unknown* %d]", i) ; break ; } ; } ; - /* 12345678901234567890 */ - qs_printf_a(qs, "%sScope ", prefix) ; - err = pthread_attr_getscope(attr, &i); + err = pthread_attr_getinheritsched(attr, &i); if (err != 0) - qs_printf_a(qs, " *error* %s\n", errtoa(err, 0).str) ; + qs_printf_a(qs, " [getinheritsched *error* %s]", errtoa(err, 0).str) ; else { switch(i) { - case PTHREAD_SCOPE_SYSTEM: - qs_printf_a(qs, "= %s\n", "PTHREAD_SCOPE_SYSTEM") ; + case PTHREAD_INHERIT_SCHED: + qs_printf_a(qs, " Inherit-Sched") ; break ; - case PTHREAD_SCOPE_PROCESS: - qs_printf_a(qs, "= %s\n", "PTHREAD_SCOPE_PROCESS") ; + case PTHREAD_EXPLICIT_SCHED: + qs_printf_a(qs, " Explicit-Sched") ; break ; default: - qs_printf_a(qs, "= *UNKNOWN* %d\n", i) ; + qs_printf_a(qs, " [getinheritsched *unknown* %d]", i) ; break ; } ; } ; - /* 12345678901234567890 */ - qs_printf_a(qs, "%sInherit scheduler ", prefix) ; - err = pthread_attr_getinheritsched(attr, &i); + err = pthread_attr_getscope(attr, &i); if (err != 0) - qs_printf_a(qs, " *error* %s\n", errtoa(err, 0).str) ; + qs_printf_a(qs, " [getscope *error* %s]", errtoa(err, 0).str) ; else { switch(i) { - case PTHREAD_INHERIT_SCHED: - qs_printf_a(qs, "= %s\n", "PTHREAD_INHERIT_SCHED") ; + case PTHREAD_SCOPE_SYSTEM: + qs_printf_a(qs, " System-Scope") ; break ; - case PTHREAD_EXPLICIT_SCHED: - qs_printf_a(qs, "= %s\n", "PTHREAD_EXPLICIT_SCHED") ; + case PTHREAD_SCOPE_PROCESS: + qs_printf_a(qs, " Process-Scope") ; break ; default: - qs_printf_a(qs, "= *UNKNOWN* %d\n", i) ; + qs_printf_a(qs, " [getscope *unknown* %d]", i) ; break ; } ; } ; - /* 12345678901234567890 */ - qs_printf_a(qs, "%sScheduling policy ", prefix) ; err = pthread_attr_getschedpolicy(attr, &i); if (err != 0) - qs_printf_a(qs, " *error* %s\n", errtoa(err, 0).str) ; + qs_printf_a(qs, " [getschedpolicy *error* %s]", errtoa(err, 0).str) ; else { switch(i) { case SCHED_OTHER: - qs_printf_a(qs, "= %s\n", "SCHED_OTHER") ; + qs_printf_a(qs, " SCHED_OTHER") ; break ; case SCHED_FIFO: - qs_printf_a(qs, "= %s\n", "SCHED_FIFO") ; + qs_printf_a(qs, " SCHED_FIFO") ; break ; case SCHED_RR: - qs_printf_a(qs, "= %s\n", "SCHED_RR") ; + qs_printf_a(qs, " SCHED_RR") ; break ; #ifdef SCHED_SPORADIC case SCHED_SPORADIC: - qs_printf_a(qs, "= %s\n", "SCHED_SPORADIC") ; + qs_printf_a(qs, " SCHED_SPORADIC") ; break ; #endif default: - qs_printf_a(qs, "= *UNKNOWN* %d\n", i) ; + qs_printf_a(qs, " SCHED_UNKNOWN=%d", i) ; break ; } ; } ; - /* 12345678901234567890 */ - qs_printf_a(qs, "%sScheduling priority ", prefix) ; err = pthread_attr_getschedparam(attr, sp); if (err != 0) - qs_printf_a(qs, " *error* %s\n", errtoa(err, 0).str) ; + qs_printf_a(qs, " [getschedparam *error* %s]", errtoa(err, 0).str) ; else - qs_printf_a(qs, "= %d\n", sp->sched_priority) ; + qs_printf_a(qs, " Priority=%d", sp->sched_priority) ; - /* 12345678901234567890 */ - qs_printf_a(qs, "%sGuard size ", prefix) ; err = pthread_attr_getguardsize(attr, &v); if (err != 0) - qs_printf_a(qs, " *error* %s\n", errtoa(err, 0).str) ; + qs_printf_a(qs, " [getguardsize *error* %s]", errtoa(err, 0).str) ; else - qs_printf_a(qs, "= %u\n", (uint)v) ; + qs_printf_a(qs, " Guard-Size=%u", (uint)v) ; - /* 12345678901234567890 */ - qs_printf_a(qs, "%sStack address/size ", prefix) ; err = pthread_attr_getstack(attr, &stkaddr, &v) ; if (err != 0) - qs_printf_a(qs, " *error* %s\n", errtoa(err, 0).str) ; + qs_printf_a(qs, " [getstack *error* %s]", errtoa(err, 0).str) ; else - qs_printf_a(qs, "= %p/%u\n", stkaddr, (uint)v) ; + qs_printf_a(qs, " Stack=%p/%u", stkaddr, (uint)v) ; return qs ; } ; diff --git a/lib/qpthreads.h b/lib/qpthreads.h index 363fbead..78c39a6e 100644 --- a/lib/qpthreads.h +++ b/lib/qpthreads.h @@ -194,8 +194,7 @@ qpt_thread_join(qpt_thread_t thread_id) ; extern clockid_t qpt_get_cpu_clock(qpt_thread_t thread_id) ; extern qtime_t qpt_cpu_time(clockid_t clock_id) ; -extern qstring qpt_thread_attr_form(qpt_thread_attr_t* attr, - const char *prefix) ; +extern qstring qpt_thread_attr_form(qpt_thread_attr_t* attr) ; /*============================================================================== * Signal Handling. diff --git a/lib/stream.h b/lib/stream.h index b4d981b1..a7906573 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -177,6 +177,8 @@ Inline bool stream_has_overflowed(struct stream* s) ; Inline void stream_clear_overrun(struct stream* s) ; Inline void stream_clear_overflow(struct stream* s) ; +Inline bool stream_has_written_beyond(struct stream* s, size_t limit) ; + Inline void stream_set_getp(struct stream *, size_t); Inline void stream_set_endp(struct stream *, size_t); Inline void stream_set_startp(struct stream* s, size_t) ; @@ -503,6 +505,27 @@ stream_clear_overflow(struct stream* s) } /*------------------------------------------------------------------------------ + * Test if the endp is beyond the given limit + * + * A stream may be set up to be longer than some actual limit, so that the + * extent of overflowing beyond that limit can be measured. This test can + * then be used to see if the endp is *currently* within the given limit. + * + * Returns: true <=> endp is *beyond* the given limit. + * + * NB: the limit MUST be less than the size -- for if not, this is *always* + * going to return false, because the s->endp is *always* <= s->size ! + */ +Inline bool +stream_has_written_beyond(struct stream* s, size_t limit) +{ + qassert_stream(s) ; + qassert(limit < s->size) ; + + return (s->endp > limit) ; +} ; + +/*------------------------------------------------------------------------------ * Set s->getp to given value. * * If value > s->endp will force to s->endp and set s->overrun. diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 75e2337e..2dde3065 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -1807,7 +1807,7 @@ vtysh_config_get_name(config_collection collection, config_item parent, break ; default: - qassert(false) ; + assert(false) ; } ; tokens = cmd_tokens_concat(collection->parsed, ti, tn - ti) ; |