diff options
author | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2009-04-30 09:01:37 -0700 |
---|---|---|
committer | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2009-04-30 09:01:37 -0700 |
commit | 0cff24ed132df27397e7c40bee013204fb2a4f8a (patch) | |
tree | 6195bd43c8174554a29adf583b563d6d308e5e5a | |
parent | f8e014a9d8cada7754b3f562c32fc4992469daa7 (diff) | |
download | quagga-0cff24ed132df27397e7c40bee013204fb2a4f8a.tar.bz2 quagga-0cff24ed132df27397e7c40bee013204fb2a4f8a.tar.xz |
Expanding asn path buffer
Based on:
[bgpd] AS4 bugfix by Chris Caputo <ccaputo@alt.net>
* bgpd/bgp_aspath.c: (aspath_make_str_count) "assert (len < str_size)" was
getting hit under certain 4-byte ASN conditions. New realloc strategy.
-rw-r--r-- | bgpd/bgp_aspath.c | 80 |
1 files changed, 27 insertions, 53 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 242bd8ee..d6fa6af5 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -389,25 +389,6 @@ aspath_delimiter_char (u_char type, u_char which) return ' '; } -/* countup asns from this segment and index onward */ -static int -assegment_count_asns (struct assegment *seg, int from) -{ - int count = 0; - while (seg) - { - if (!from) - count += seg->length; - else - { - count += (seg->length - from); - from = 0; - } - seg = seg->next; - } - return count; -} - unsigned int aspath_count_confeds (struct aspath *aspath) { @@ -517,12 +498,26 @@ aspath_count_numas (struct aspath *aspath) return num; } +/* Expand aspath string */ +static char * +aspath_expand (char *buf, size_t *size, size_t len, size_t growth) +{ + len += growth + 1; /* space for null terminator */ + if (len <= *size) + return buf; + + while (len > *size) + *size += *size / 2; + + return XREALLOC(MTYPE_AS_STR, buf, *size); +} + /* Convert aspath structure to string expression. */ static char * aspath_make_str_count (struct aspath *as) { struct assegment *seg; - int str_size; + size_t str_size; int len = 0; char *str_buf; @@ -536,18 +531,7 @@ aspath_make_str_count (struct aspath *as) seg = as->segments; - /* ASN takes 5 chars at least, plus seperator, see below. - * If there is one differing segment type, we need an additional - * 2 chars for segment delimiters, and the final '\0'. - * Hopefully this is large enough to avoid hitting the realloc - * code below for most common sequences. - * - * With 32bit ASNs, this range will increase, but only worth changing - * once there are significant numbers of ASN >= 100000 - */ -#define ASN_STR_LEN (5 + 1) - str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1, - ASPATH_STR_DEFAULT_LEN); + str_size = ASPATH_STR_DEFAULT_LEN; str_buf = XMALLOC (MTYPE_AS_STR, str_size); while (seg) @@ -571,32 +555,22 @@ aspath_make_str_count (struct aspath *as) return NULL; } - /* We might need to increase str_buf, particularly if path has - * differing segments types, our initial guesstimate above will - * have been wrong. need 5 chars for ASN, a seperator each and - * potentially two segment delimiters, plus a space between each - * segment and trailing zero. - * - * This may need to revised if/when significant numbers of - * ASNs >= 100000 are assigned and in-use on the internet... - */ -#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1) - if ( (len + SEGMENT_STR_LEN(seg)) > str_size) - { - str_size = len + SEGMENT_STR_LEN(seg); - str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size); - } -#undef ASN_STR_LEN -#undef SEGMENT_STR_LEN - if (seg->type != AS_SEQUENCE) - len += snprintf (str_buf + len, str_size - len, - "%c", - aspath_delimiter_char (seg->type, AS_SEG_START)); + { + str_buf = aspath_expand(str_buf, &str_size, len, 1); + len += snprintf (str_buf + len, str_size - len, + "%c", + aspath_delimiter_char (seg->type, AS_SEG_START)); + } /* write out the ASNs, with their seperators, bar the last one*/ for (i = 0; i < seg->length; i++) { +#define APPROX_DIG_CNT(x) (x < 100000U ? 5 : 10) + /* %u + %c + %c + " " (last two are below loop) */ + str_buf = aspath_expand(str_buf, &str_size, len, + APPROX_DIG_CNT(seg->as[i]) + 3); + len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]); if (i < (seg->length - 1)) |