--- embedaddon/quagga/bgpd/bgp_aspath.c 2012/10/09 09:22:28 1.1.1.2 +++ embedaddon/quagga/bgpd/bgp_aspath.c 2016/11/02 10:09:10 1.1.1.4 @@ -29,12 +29,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330 #include "log.h" #include "stream.h" #include "jhash.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_attr.h" - + /* Attr. Flags and Attr. Type Code. */ #define AS_HEADER_SIZE 2 @@ -90,17 +91,18 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; - + +/* Callers are required to initialize the memory */ static as_t * assegment_data_new (int num) { - return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1))); + return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1))); } static void assegment_data_free (as_t *asdata) { - XFREE (MTYPE_AS_SEG_DATA,asdata); + XFREE (MTYPE_AS_SEG_DATA, asdata); } /* Get a new segment. Note that 0 is an allowed length, @@ -131,7 +133,7 @@ assegment_free (struct assegment *seg) return; if (seg->as) - XFREE (MTYPE_AS_SEG_DATA, seg->as); + assegment_data_free (seg->as); memset (seg, 0xfe, sizeof(struct assegment)); XFREE (MTYPE_AS_SEG, seg); @@ -191,6 +193,7 @@ static struct assegment * assegment_prepend_asns (struct assegment *seg, as_t asnum, int num) { as_t *newas; + int i; if (!num) return seg; @@ -198,23 +201,18 @@ assegment_prepend_asns (struct assegment *seg, as_t as if (num >= AS_SEGMENT_MAX) return seg; /* we don't do huge prepends */ - newas = assegment_data_new (seg->length + num); + if ((newas = assegment_data_new (seg->length + num)) == NULL) + return seg; - if (newas) - { - int i; - for (i = 0; i < num; i++) - newas[i] = asnum; - - memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); - XFREE (MTYPE_AS_SEG_DATA, seg->as); - seg->as = newas; - seg->length += num; - return seg; - } + for (i = 0; i < num; i++) + newas[i] = asnum; - assegment_free_all (seg); - return NULL; + memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); + assegment_data_free (seg->as); + seg->as = newas; + seg->length += num; + + return seg; } /* append given array of as numbers to the segment */ @@ -318,7 +316,7 @@ assegment_normalise (struct assegment *head) } return head; } - + static struct aspath * aspath_new (void) { @@ -486,6 +484,19 @@ aspath_highest (struct aspath *aspath) return highest; } +/* Return the left-most ASN in path */ +as_t +aspath_leftmost (struct aspath *aspath) +{ + struct assegment *seg = aspath->segments; + as_t leftmost = 0; + + if (seg && seg->length && seg->type == AS_SEQUENCE) + leftmost = seg->as[0]; + + return leftmost; +} + /* Return 1 if there are any 4-byte ASes in the path */ unsigned int aspath_has_as4 (struct aspath *aspath) @@ -504,7 +515,7 @@ aspath_has_as4 (struct aspath *aspath) } /* Convert aspath structure to string expression. */ -static char * +static void aspath_make_str_count (struct aspath *as) { struct assegment *seg; @@ -515,9 +526,10 @@ aspath_make_str_count (struct aspath *as) /* Empty aspath. */ if (!as->segments) { - str_buf = XMALLOC (MTYPE_AS_STR, 1); - str_buf[0] = '\0'; - return str_buf; + as->str = XMALLOC (MTYPE_AS_STR, 1); + as->str[0] = '\0'; + as->str_len = 0; + return; } seg = as->segments; @@ -554,7 +566,9 @@ aspath_make_str_count (struct aspath *as) break; default: XFREE (MTYPE_AS_STR, str_buf); - return NULL; + as->str = NULL; + as->str_len = 0; + return; } /* We might need to increase str_buf, particularly if path has @@ -601,8 +615,10 @@ aspath_make_str_count (struct aspath *as) assert (len < str_size); str_buf[len] = '\0'; + as->str = str_buf; + as->str_len = len; - return str_buf; + return; } static void @@ -610,7 +626,7 @@ aspath_str_update (struct aspath *as) { if (as->str) XFREE (MTYPE_AS_STR, as->str); - as->str = aspath_make_str_count (as); + aspath_make_str_count (as); } /* Intern allocated AS path. */ @@ -618,21 +634,19 @@ struct aspath * aspath_intern (struct aspath *aspath) { struct aspath *find; - - /* Assert this AS path structure is not interned. */ + + /* Assert this AS path structure is not interned and has the string + representation built. */ assert (aspath->refcnt == 0); + assert (aspath->str); /* Check AS path hash. */ find = hash_get (ashash, aspath, hash_alloc_intern); - if (find != aspath) aspath_free (aspath); find->refcnt++; - if (! find->str) - find->str = aspath_make_str_count (find); - return find; } @@ -641,36 +655,50 @@ aspath_intern (struct aspath *aspath) struct aspath * aspath_dup (struct aspath *aspath) { + unsigned short buflen = aspath->str_len + 1; struct aspath *new; new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); if (aspath->segments) new->segments = assegment_dup_all (aspath->segments); - else - new->segments = NULL; - new->str = aspath_make_str_count (aspath); + if (!aspath->str) + return new; + new->str = XMALLOC (MTYPE_AS_STR, buflen); + new->str_len = aspath->str_len; + + /* copy the string data */ + if (aspath->str_len > 0) + memcpy (new->str, aspath->str, buflen); + else + new->str[0] = '\0'; + return new; } static void * aspath_hash_alloc (void *arg) { - struct aspath *aspath; + const struct aspath *aspath = arg; + struct aspath *new; - /* New aspath structure is needed. */ - aspath = aspath_dup (arg); - /* Malformed AS path value. */ + assert (aspath->str); if (! aspath->str) - { - aspath_free (aspath); - return NULL; - } + return NULL; - return aspath; + /* New aspath structure is needed. */ + new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); + + /* Reuse segments and string representation */ + new->refcnt = 0; + new->segments = aspath->segments; + new->str = aspath->str; + new->str_len = aspath->str_len; + + return new; } /* parse as-segment byte stream in struct assegment */ @@ -794,19 +822,21 @@ aspath_parse (struct stream *s, size_t length, int use memset (&as, 0, sizeof (struct aspath)); if (assegments_parse (s, length, &as.segments, use32bit) < 0) return NULL; - + /* If already same aspath exist then return it. */ find = hash_get (ashash, &as, aspath_hash_alloc); - - /* aspath_hash_alloc dupes segments too. that probably could be - * optimised out. - */ - assegment_free_all (as.segments); - if (as.str) - XFREE (MTYPE_AS_STR, as.str); - - if (! find) - return NULL; + + /* bug! should not happen, let the daemon crash below */ + assert (find); + + /* if the aspath was already hashed free temporary memory. */ + if (find->refcnt) + { + assegment_free_all (as.segments); + /* aspath_key_make() always updates the string */ + XFREE (MTYPE_AS_STR, as.str); + } + find->refcnt++; return find; @@ -1353,46 +1383,50 @@ aspath_filter_exclude (struct aspath * source, struct /* Add specified AS to the leftmost of aspath. */ static struct aspath * -aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type) +aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num) { struct assegment *assegment = aspath->segments; + unsigned i; - /* In case of empty aspath. */ - if (assegment == NULL || assegment->length == 0) + if (assegment && assegment->type == type) { - aspath->segments = assegment_new (type, 1); - aspath->segments->as[0] = asno; - - if (assegment) - assegment_free (assegment); - - return aspath; + /* extend existing segment */ + aspath->segments = assegment_prepend_asns (aspath->segments, asno, num); } - - if (assegment->type == type) - aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1); else { - /* create new segment - * push it onto head of aspath's segment chain - */ - struct assegment *newsegment; - - newsegment = assegment_new (type, 1); - newsegment->as[0] = asno; - - newsegment->next = assegment; + /* prepend with new segment */ + struct assegment *newsegment = assegment_new (type, num); + for (i = 0; i < num; i++) + newsegment->as[i] = asno; + + /* insert potentially replacing empty segment */ + if (assegment && assegment->length == 0) + { + newsegment->next = assegment->next; + assegment_free (assegment); + } + else + newsegment->next = assegment; aspath->segments = newsegment; } + aspath_str_update (aspath); return aspath; } +/* Add specified AS to the leftmost of aspath num times. */ +struct aspath * +aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num) +{ + return aspath_add_asns (aspath, asno, AS_SEQUENCE, num); +} + /* Add specified AS to the leftmost of aspath. */ struct aspath * aspath_add_seq (struct aspath *aspath, as_t asno) { - return aspath_add_one_as (aspath, asno, AS_SEQUENCE); + return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1); } /* Compare leftmost AS value for MED check. If as1's leftmost AS and @@ -1400,8 +1434,8 @@ aspath_add_seq (struct aspath *aspath, as_t asno) int aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2) { - const struct assegment *seg1 = NULL; - const struct assegment *seg2 = NULL; + const struct assegment *seg1; + const struct assegment *seg2; if (!(aspath1 && aspath2)) return 0; @@ -1591,7 +1625,7 @@ aspath_delete_confed_seq (struct aspath *aspath) struct aspath* aspath_add_confed_seq (struct aspath *aspath, as_t asno) { - return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE); + return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1); } /* Add new as value to as path structure. */ @@ -1639,7 +1673,7 @@ aspath_empty_get (void) struct aspath *aspath; aspath = aspath_new (); - aspath->str = aspath_make_str_count (aspath); + aspath_make_str_count (aspath); return aspath; } @@ -1648,7 +1682,7 @@ aspath_count (void) { return ashash->count; } - + /* Theoretically, one as path can have: @@ -1798,23 +1832,23 @@ aspath_str2aspath (const char *str) } } - aspath->str = aspath_make_str_count (aspath); + aspath_make_str_count (aspath); return aspath; } - + /* Make hash value by raw aspath data. */ unsigned int aspath_key_make (void *p) { - struct aspath * aspath = (struct aspath *) p; + struct aspath *aspath = (struct aspath *) p; unsigned int key = 0; if (!aspath->str) aspath_str_update (aspath); - - key = jhash (aspath->str, strlen(aspath->str), 2334325); + key = jhash (aspath->str, aspath->str_len, 2334325); + return key; } @@ -1847,19 +1881,20 @@ aspath_cmp (const void *arg1, const void *arg2) void aspath_init (void) { - ashash = hash_create_size (32767, aspath_key_make, aspath_cmp); + ashash = hash_create_size (32768, aspath_key_make, aspath_cmp); } void aspath_finish (void) { + hash_clean (ashash, (void (*)(void *))aspath_free); hash_free (ashash); ashash = NULL; if (snmp_stream) stream_free (snmp_stream); } - + /* return and as path value */ const char * aspath_print (struct aspath *as) @@ -1876,7 +1911,7 @@ aspath_print_vty (struct vty *vty, const char *format, { assert (format); vty_out (vty, format, as->str); - if (strlen (as->str) && strlen (suffix)) + if (as->str_len && strlen (suffix)) vty_out (vty, "%s", suffix); } @@ -1887,7 +1922,7 @@ aspath_show_all_iterator (struct hash_backet *backet, as = (struct aspath *) backet->data; - vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt); + vty_out (vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt); vty_out (vty, "%s%s", as->str, VTY_NEWLINE); }