diff options
Diffstat (limited to 'bgpd/bgp_aspath.c')
| -rw-r--r-- | bgpd/bgp_aspath.c | 3336 |
1 files changed, 1608 insertions, 1728 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 47bbfd466a..4e55c5f264 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -58,8 +58,8 @@ */ /* Calculated size in bytes of ASN segment data to hold N ASN's */ -#define ASSEGMENT_DATA_SIZE(N,S) \ - ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) ) +#define ASSEGMENT_DATA_SIZE(N, S) \ + ((N) * ((S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE)) /* Calculated size of segment struct to hold N ASN's */ #define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S)) @@ -69,21 +69,19 @@ /* AS_SEQUENCE segments can be packed together */ /* Can the types of X and Y be considered for packing? */ -#define ASSEGMENT_TYPES_PACKABLE(X,Y) \ - ( ((X)->type == (Y)->type) \ - && ((X)->type == AS_SEQUENCE)) +#define ASSEGMENT_TYPES_PACKABLE(X, Y) \ + (((X)->type == (Y)->type) && ((X)->type == AS_SEQUENCE)) /* Types and length of X,Y suitable for packing? */ -#define ASSEGMENTS_PACKABLE(X,Y) \ - ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \ - && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) ) +#define ASSEGMENTS_PACKABLE(X, Y) \ + (ASSEGMENT_TYPES_PACKABLE((X), (Y)) \ + && (((X)->length + (Y)->length) <= AS_SEGMENT_MAX)) -/* As segment header - the on-wire representation +/* As segment header - the on-wire representation * NOT the internal representation! */ -struct assegment_header -{ - u_char type; - u_char length; +struct assegment_header { + u_char type; + u_char length; }; /* Hash for aspath. This is the top level structure of AS path. */ @@ -93,165 +91,147 @@ static struct hash *ashash; static struct stream *snmp_stream; /* Callers are required to initialize the memory */ -static as_t * -assegment_data_new (int num) +static as_t *assegment_data_new(int num) { - return (XMALLOC (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) +static void assegment_data_free(as_t *asdata) { - XFREE (MTYPE_AS_SEG_DATA, asdata); + XFREE(MTYPE_AS_SEG_DATA, asdata); } -const char *aspath_segment_type_str[] = { - "as-invalid", - "as-set", - "as-sequence", - "as-confed-sequence", - "as-confed-set" -}; +const char *aspath_segment_type_str[] = {"as-invalid", "as-set", "as-sequence", + "as-confed-sequence", "as-confed-set"}; /* Get a new segment. Note that 0 is an allowed length, * and will result in a segment with no allocated data segment. * the caller should immediately assign data to the segment, as the segment * otherwise is not generally valid */ -static struct assegment * -assegment_new (u_char type, u_short length) -{ - struct assegment *new; - - new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment)); - - if (length) - new->as = assegment_data_new (length); - - new->length = length; - new->type = type; - - return new; -} - -static void -assegment_free (struct assegment *seg) -{ - if (!seg) - return; - - if (seg->as) - assegment_data_free (seg->as); - memset (seg, 0xfe, sizeof(struct assegment)); - XFREE (MTYPE_AS_SEG, seg); - - return; +static struct assegment *assegment_new(u_char type, u_short length) +{ + struct assegment *new; + + new = XCALLOC(MTYPE_AS_SEG, sizeof(struct assegment)); + + if (length) + new->as = assegment_data_new(length); + + new->length = length; + new->type = type; + + return new; +} + +static void assegment_free(struct assegment *seg) +{ + if (!seg) + return; + + if (seg->as) + assegment_data_free(seg->as); + memset(seg, 0xfe, sizeof(struct assegment)); + XFREE(MTYPE_AS_SEG, seg); + + return; } /* free entire chain of segments */ -static void -assegment_free_all (struct assegment *seg) +static void assegment_free_all(struct assegment *seg) { - struct assegment *prev; - - while (seg) - { - prev = seg; - seg = seg->next; - assegment_free (prev); - } + struct assegment *prev; + + while (seg) { + prev = seg; + seg = seg->next; + assegment_free(prev); + } } /* Duplicate just the given assegment and its data */ -static struct assegment * -assegment_dup (struct assegment *seg) +static struct assegment *assegment_dup(struct assegment *seg) { - struct assegment *new; - - new = assegment_new (seg->type, seg->length); - memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) ); - - return new; + struct assegment *new; + + new = assegment_new(seg->type, seg->length); + memcpy(new->as, seg->as, ASSEGMENT_DATA_SIZE(new->length, 1)); + + return new; } /* Duplicate entire chain of assegments, return the head */ -static struct assegment * -assegment_dup_all (struct assegment *seg) -{ - struct assegment *new = NULL; - struct assegment *head = NULL; - - while (seg) - { - if (head) - { - new->next = assegment_dup (seg); - new = new->next; - } - else - head = new = assegment_dup (seg); - - seg = seg->next; - } - return head; +static struct assegment *assegment_dup_all(struct assegment *seg) +{ + struct assegment *new = NULL; + struct assegment *head = NULL; + + while (seg) { + if (head) { + new->next = assegment_dup(seg); + new = new->next; + } else + head = new = assegment_dup(seg); + + seg = seg->next; + } + return head; } /* prepend the as number to given segment, given num of times */ -static struct assegment * -assegment_prepend_asns (struct assegment *seg, as_t asnum, int num) +static struct assegment *assegment_prepend_asns(struct assegment *seg, + as_t asnum, int num) { - as_t *newas; - int i; - - if (!num) - return seg; - - if (num >= AS_SEGMENT_MAX) - return seg; /* we don't do huge prepends */ - - if ((newas = assegment_data_new (seg->length + num)) == NULL) - return seg; + as_t *newas; + int i; - for (i = 0; i < num; i++) - newas[i] = asnum; + if (!num) + return seg; - memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); - assegment_data_free (seg->as); - seg->as = newas; - seg->length += num; + if (num >= AS_SEGMENT_MAX) + return seg; /* we don't do huge prepends */ - return seg; + if ((newas = assegment_data_new(seg->length + num)) == NULL) + return seg; + + for (i = 0; i < num; i++) + newas[i] = asnum; + + 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 */ -static struct assegment * -assegment_append_asns (struct assegment *seg, as_t *asnos, int num) +static struct assegment *assegment_append_asns(struct assegment *seg, + as_t *asnos, int num) { - as_t *newas; - - newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as, - ASSEGMENT_DATA_SIZE (seg->length + num, 1)); + as_t *newas; - if (newas) - { - seg->as = newas; - memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1)); - seg->length += num; - return seg; - } + newas = XREALLOC(MTYPE_AS_SEG_DATA, seg->as, + ASSEGMENT_DATA_SIZE(seg->length + num, 1)); + + if (newas) { + seg->as = newas; + memcpy(seg->as + seg->length, asnos, + ASSEGMENT_DATA_SIZE(num, 1)); + seg->length += num; + return seg; + } - assegment_free_all (seg); - return NULL; + assegment_free_all(seg); + return NULL; } -static int -int_cmp (const void *p1, const void *p2) +static int int_cmp(const void *p1, const void *p2) { - const as_t *as1 = p1; - const as_t *as2 = p2; - - return (*as1 == *as2) - ? 0 : ( (*as1 > *as2) ? 1 : -1); + const as_t *as1 = p1; + const as_t *as2 = p2; + + return (*as1 == *as2) ? 0 : ((*as1 > *as2) ? 1 : -1); } /* normalise the segment. @@ -260,203 +240,180 @@ int_cmp (const void *p1, const void *p2) * we want each distinct AS_PATHs to have the exact same internal * representation - eg, so that our hashing actually works.. */ -static struct assegment * -assegment_normalise (struct assegment *head) -{ - struct assegment *seg = head, *pin; - struct assegment *tmp; - - if (!head) - return head; - - while (seg) - { - pin = seg; - - /* Sort values SET segments, for determinism in paths to aid - * creation of hash values / path comparisons - * and because it helps other lesser implementations ;) - */ - if (seg->type == AS_SET || seg->type == AS_CONFED_SET) - { - int tail = 0; - int i; - - qsort (seg->as, seg->length, sizeof(as_t), int_cmp); - - /* weed out dupes */ - for (i=1; i < seg->length; i++) - { - if (seg->as[tail] == seg->as[i]) - continue; - - tail++; - if (tail < i) - seg->as[tail] = seg->as[i]; - } - /* seg->length can be 0.. */ - if (seg->length) - seg->length = tail + 1; +static struct assegment *assegment_normalise(struct assegment *head) +{ + struct assegment *seg = head, *pin; + struct assegment *tmp; + + if (!head) + return head; + + while (seg) { + pin = seg; + + /* Sort values SET segments, for determinism in paths to aid + * creation of hash values / path comparisons + * and because it helps other lesser implementations ;) + */ + if (seg->type == AS_SET || seg->type == AS_CONFED_SET) { + int tail = 0; + int i; + + qsort(seg->as, seg->length, sizeof(as_t), int_cmp); + + /* weed out dupes */ + for (i = 1; i < seg->length; i++) { + if (seg->as[tail] == seg->as[i]) + continue; + + tail++; + if (tail < i) + seg->as[tail] = seg->as[i]; + } + /* seg->length can be 0.. */ + if (seg->length) + seg->length = tail + 1; + } + + /* read ahead from the current, pinned segment while the + * segments + * are packable/mergeable. Append all following packable + * segments + * to the segment we have pinned and remove these appended + * segments. + */ + while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next)) { + tmp = pin->next; + seg = pin->next; + + /* append the next sequence to the pinned sequence */ + pin = assegment_append_asns(pin, seg->as, seg->length); + + /* bypass the next sequence */ + pin->next = seg->next; + + /* get rid of the now referenceless segment */ + assegment_free(tmp); + } + + seg = pin->next; } - - /* read ahead from the current, pinned segment while the segments - * are packable/mergeable. Append all following packable segments - * to the segment we have pinned and remove these appended - * segments. - */ - while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next)) - { - tmp = pin->next; - seg = pin->next; - - /* append the next sequence to the pinned sequence */ - pin = assegment_append_asns (pin, seg->as, seg->length); - - /* bypass the next sequence */ - pin->next = seg->next; - - /* get rid of the now referenceless segment */ - assegment_free (tmp); - - } - - seg = pin->next; - } - return head; -} - -static struct aspath * -aspath_new (void) -{ - return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); + return head; } -/* Free AS path structure. */ -void -aspath_free (struct aspath *aspath) +static struct aspath *aspath_new(void) { - if (!aspath) - return; - if (aspath->segments) - assegment_free_all (aspath->segments); - if (aspath->str) - XFREE (MTYPE_AS_STR, aspath->str); + return XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath)); +} - if (aspath->json) - { - json_object_free(aspath->json); - aspath->json = NULL; - } +/* Free AS path structure. */ +void aspath_free(struct aspath *aspath) +{ + if (!aspath) + return; + if (aspath->segments) + assegment_free_all(aspath->segments); + if (aspath->str) + XFREE(MTYPE_AS_STR, aspath->str); + + if (aspath->json) { + json_object_free(aspath->json); + aspath->json = NULL; + } - XFREE (MTYPE_AS_PATH, aspath); + XFREE(MTYPE_AS_PATH, aspath); } /* Unintern aspath from AS path bucket. */ -void -aspath_unintern (struct aspath **aspath) +void aspath_unintern(struct aspath **aspath) { - struct aspath *ret; - struct aspath *asp = *aspath; - - if (asp->refcnt) - asp->refcnt--; + struct aspath *ret; + struct aspath *asp = *aspath; + + if (asp->refcnt) + asp->refcnt--; - if (asp->refcnt == 0) - { - /* This aspath must exist in aspath hash table. */ - ret = hash_release (ashash, asp); - assert (ret != NULL); - aspath_free (asp); - *aspath = NULL; - } + if (asp->refcnt == 0) { + /* This aspath must exist in aspath hash table. */ + ret = hash_release(ashash, asp); + assert(ret != NULL); + aspath_free(asp); + *aspath = NULL; + } } /* Return the start or end delimiters for a particular Segment type */ #define AS_SEG_START 0 #define AS_SEG_END 1 -static char -aspath_delimiter_char (u_char type, u_char which) -{ - int i; - struct - { - int type; - char start; - char end; - } aspath_delim_char [] = - { - { AS_SET, '{', '}' }, - { AS_CONFED_SET, '[', ']' }, - { AS_CONFED_SEQUENCE, '(', ')' }, - { 0 } - }; - - for (i = 0; aspath_delim_char[i].type != 0; i++) - { - if (aspath_delim_char[i].type == type) - { - if (which == AS_SEG_START) - return aspath_delim_char[i].start; - else if (which == AS_SEG_END) - return aspath_delim_char[i].end; +static char aspath_delimiter_char(u_char type, u_char which) +{ + int i; + struct { + int type; + char start; + char end; + } aspath_delim_char[] = {{AS_SET, '{', '}'}, + {AS_CONFED_SET, '[', ']'}, + {AS_CONFED_SEQUENCE, '(', ')'}, + {0}}; + + for (i = 0; aspath_delim_char[i].type != 0; i++) { + if (aspath_delim_char[i].type == type) { + if (which == AS_SEG_START) + return aspath_delim_char[i].start; + else if (which == AS_SEG_END) + return aspath_delim_char[i].end; + } } - } - return ' '; + 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) -{ - int count = 0; - struct assegment *seg = aspath->segments; - - while (seg) - { - if (seg->type == AS_CONFED_SEQUENCE) - count += seg->length; - else if (seg->type == AS_CONFED_SET) - count++; - - seg = seg->next; - } - return count; -} - -unsigned int -aspath_count_hops (const struct aspath *aspath) -{ - int count = 0; - struct assegment *seg = aspath->segments; - - while (seg) - { - if (seg->type == AS_SEQUENCE) - count += seg->length; - else if (seg->type == AS_SET) - count++; - - seg = seg->next; - } - return count; +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) +{ + int count = 0; + struct assegment *seg = aspath->segments; + + while (seg) { + if (seg->type == AS_CONFED_SEQUENCE) + count += seg->length; + else if (seg->type == AS_CONFED_SET) + count++; + + seg = seg->next; + } + return count; +} + +unsigned int aspath_count_hops(const struct aspath *aspath) +{ + int count = 0; + struct assegment *seg = aspath->segments; + + while (seg) { + if (seg->type == AS_SEQUENCE) + count += seg->length; + else if (seg->type == AS_SET) + count++; + + seg = seg->next; + } + return count; } /* Estimate size aspath /might/ take if encoded into an @@ -465,1074 +422,1025 @@ aspath_count_hops (const struct aspath *aspath) * This is a quick estimate, not definitive! aspath_put() * may return a different number!! */ -unsigned int -aspath_size (struct aspath *aspath) +unsigned int aspath_size(struct aspath *aspath) { - int size = 0; - struct assegment *seg = aspath->segments; - - while (seg) - { - size += ASSEGMENT_SIZE(seg->length, 1); - seg = seg->next; - } - return size; + int size = 0; + struct assegment *seg = aspath->segments; + + while (seg) { + size += ASSEGMENT_SIZE(seg->length, 1); + seg = seg->next; + } + return size; } /* Return highest public ASN in path */ -as_t -aspath_highest (struct aspath *aspath) -{ - struct assegment *seg = aspath->segments; - as_t highest = 0; - unsigned int i; - - while (seg) - { - for (i = 0; i < seg->length; i++) - if (seg->as[i] > highest && !BGP_AS_IS_PRIVATE(seg->as[i])) - highest = seg->as[i]; - seg = seg->next; - } - return highest; +as_t aspath_highest(struct aspath *aspath) +{ + struct assegment *seg = aspath->segments; + as_t highest = 0; + unsigned int i; + + while (seg) { + for (i = 0; i < seg->length; i++) + if (seg->as[i] > highest + && !BGP_AS_IS_PRIVATE(seg->as[i])) + highest = seg->as[i]; + seg = seg->next; + } + return highest; } /* Return the left-most ASN in path */ -as_t -aspath_leftmost (struct aspath *aspath) +as_t aspath_leftmost(struct aspath *aspath) { - struct assegment *seg = aspath->segments; - as_t leftmost = 0; + struct assegment *seg = aspath->segments; + as_t leftmost = 0; - if (seg && seg->length && seg->type == AS_SEQUENCE) - leftmost = seg->as[0]; + if (seg && seg->length && seg->type == AS_SEQUENCE) + leftmost = seg->as[0]; - return leftmost; + return leftmost; } /* Return 1 if there are any 4-byte ASes in the path */ -unsigned int -aspath_has_as4 (struct aspath *aspath) -{ - struct assegment *seg = aspath->segments; - unsigned int i; - - while (seg) - { - for (i = 0; i < seg->length; i++) - if (seg->as[i] > BGP_AS_MAX) - return 1; - seg = seg->next; - } - return 0; +unsigned int aspath_has_as4(struct aspath *aspath) +{ + struct assegment *seg = aspath->segments; + unsigned int i; + + while (seg) { + for (i = 0; i < seg->length; i++) + if (seg->as[i] > BGP_AS_MAX) + return 1; + seg = seg->next; + } + return 0; } /* Convert aspath structure to string expression. */ -static void -aspath_make_str_count (struct aspath *as) -{ - struct assegment *seg; - int str_size; - int len = 0; - char *str_buf; - json_object *jaspath_segments = NULL; - json_object *jseg = NULL; - json_object *jseg_list = NULL; - - as->json = json_object_new_object(); - jaspath_segments = json_object_new_array(); - - /* Empty aspath. */ - if (!as->segments) - { - json_object_string_add(as->json, "string", "Local"); - json_object_object_add(as->json, "segments", jaspath_segments); - json_object_int_add(as->json, "length", 0); - as->str = XMALLOC (MTYPE_AS_STR, 1); - as->str[0] = '\0'; - as->str_len = 0; - return; - } - - seg = as->segments; - - /* ASN takes 5 to 10 chars 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. - * - * This was changed to 10 after the well-known BGP assertion, which - * had hit some parts of the Internet in May of 2009. - */ +static void aspath_make_str_count(struct aspath *as) +{ + struct assegment *seg; + int str_size; + int len = 0; + char *str_buf; + json_object *jaspath_segments = NULL; + json_object *jseg = NULL; + json_object *jseg_list = NULL; + + as->json = json_object_new_object(); + jaspath_segments = json_object_new_array(); + + /* Empty aspath. */ + if (!as->segments) { + json_object_string_add(as->json, "string", "Local"); + json_object_object_add(as->json, "segments", jaspath_segments); + json_object_int_add(as->json, "length", 0); + as->str = XMALLOC(MTYPE_AS_STR, 1); + as->str[0] = '\0'; + as->str_len = 0; + return; + } + + seg = as->segments; + +/* ASN takes 5 to 10 chars 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. + * + * This was changed to 10 after the well-known BGP assertion, which + * had hit some parts of the Internet in May of 2009. + */ #define ASN_STR_LEN (10 + 1) - str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1, - ASPATH_STR_DEFAULT_LEN); - str_buf = XMALLOC (MTYPE_AS_STR, str_size); - - while (seg) - { - int i; - char seperator; - - /* Check AS type validity. Set seperator for segment */ - switch (seg->type) - { - case AS_SET: - case AS_CONFED_SET: - seperator = ','; - break; - case AS_SEQUENCE: - case AS_CONFED_SEQUENCE: - seperator = ' '; - break; - default: - XFREE (MTYPE_AS_STR, str_buf); - as->str = NULL; - as->str_len = 0; - json_object_free(as->json); - as->json = NULL; - return; - } - - /* We might need to increase str_buf, particularly if path has - * differing segments types, our initial guesstimate above will - * have been wrong. Need 10 chars for ASN, a seperator each and - * potentially two segment delimiters, plus a space between each - * segment and trailing zero. - * - * This definitely didn't work with the value of 5 bytes and - * 32-bit ASNs. - */ + str_size = MAX(assegment_count_asns(seg, 0) * ASN_STR_LEN + 2 + 1, + ASPATH_STR_DEFAULT_LEN); + str_buf = XMALLOC(MTYPE_AS_STR, str_size); + + while (seg) { + int i; + char seperator; + + /* Check AS type validity. Set seperator for segment */ + switch (seg->type) { + case AS_SET: + case AS_CONFED_SET: + seperator = ','; + break; + case AS_SEQUENCE: + case AS_CONFED_SEQUENCE: + seperator = ' '; + break; + default: + XFREE(MTYPE_AS_STR, str_buf); + as->str = NULL; + as->str_len = 0; + json_object_free(as->json); + as->json = NULL; + return; + } + +/* We might need to increase str_buf, particularly if path has + * differing segments types, our initial guesstimate above will + * have been wrong. Need 10 chars for ASN, a seperator each and + * potentially two segment delimiters, plus a space between each + * segment and trailing zero. + * + * This definitely didn't work with the value of 5 bytes and + * 32-bit ASNs. + */ #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); - } + 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)); - - jseg_list = json_object_new_array(); - - /* write out the ASNs, with their seperators, bar the last one*/ - for (i = 0; i < seg->length; i++) - { - json_object_array_add(jseg_list, json_object_new_int(seg->as[i])); - - len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]); - - if (i < (seg->length - 1)) - len += snprintf (str_buf + len, str_size - len, "%c", seperator); - } - - jseg = json_object_new_object(); - json_object_string_add(jseg, "type", aspath_segment_type_str[seg->type]); - json_object_object_add(jseg, "list", jseg_list); - json_object_array_add(jaspath_segments, jseg); - - if (seg->type != AS_SEQUENCE) - len += snprintf (str_buf + len, str_size - len, "%c", - aspath_delimiter_char (seg->type, AS_SEG_END)); - if (seg->next) - len += snprintf (str_buf + len, str_size - len, " "); - - seg = seg->next; - } - - assert (len < str_size); - - str_buf[len] = '\0'; - as->str = str_buf; - as->str_len = len; - - json_object_string_add(as->json, "string", str_buf); - json_object_object_add(as->json, "segments", jaspath_segments); - json_object_int_add(as->json, "length", aspath_count_hops (as)); - return; -} - -static void -aspath_str_update (struct aspath *as) -{ - if (as->str) - XFREE (MTYPE_AS_STR, as->str); - - if (as->json) - { - json_object_free(as->json); - as->json = NULL; - } - - aspath_make_str_count (as); + + if (seg->type != AS_SEQUENCE) + len += snprintf( + str_buf + len, str_size - len, "%c", + aspath_delimiter_char(seg->type, AS_SEG_START)); + + jseg_list = json_object_new_array(); + + /* write out the ASNs, with their seperators, bar the last one*/ + for (i = 0; i < seg->length; i++) { + json_object_array_add(jseg_list, + json_object_new_int(seg->as[i])); + + len += snprintf(str_buf + len, str_size - len, "%u", + seg->as[i]); + + if (i < (seg->length - 1)) + len += snprintf(str_buf + len, str_size - len, + "%c", seperator); + } + + jseg = json_object_new_object(); + json_object_string_add(jseg, "type", + aspath_segment_type_str[seg->type]); + json_object_object_add(jseg, "list", jseg_list); + json_object_array_add(jaspath_segments, jseg); + + if (seg->type != AS_SEQUENCE) + len += snprintf( + str_buf + len, str_size - len, "%c", + aspath_delimiter_char(seg->type, AS_SEG_END)); + if (seg->next) + len += snprintf(str_buf + len, str_size - len, " "); + + seg = seg->next; + } + + assert(len < str_size); + + str_buf[len] = '\0'; + as->str = str_buf; + as->str_len = len; + + json_object_string_add(as->json, "string", str_buf); + json_object_object_add(as->json, "segments", jaspath_segments); + json_object_int_add(as->json, "length", aspath_count_hops(as)); + return; +} + +static void aspath_str_update(struct aspath *as) +{ + if (as->str) + XFREE(MTYPE_AS_STR, as->str); + + if (as->json) { + json_object_free(as->json); + as->json = NULL; + } + + aspath_make_str_count(as); } /* Intern allocated AS path. */ -struct aspath * -aspath_intern (struct aspath *aspath) +struct aspath *aspath_intern(struct aspath *aspath) { - struct aspath *find; + struct aspath *find; - /* Assert this AS path structure is not interned and has the string - representation built. */ - assert (aspath->refcnt == 0); - assert (aspath->str); + /* 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); + /* Check AS path hash. */ + find = hash_get(ashash, aspath, hash_alloc_intern); + if (find != aspath) + aspath_free(aspath); - find->refcnt++; + find->refcnt++; - return find; + return find; } /* Duplicate aspath structure. Created same aspath structure but reference count and AS path string is cleared. */ -struct aspath * -aspath_dup (struct aspath *aspath) +struct aspath *aspath_dup(struct aspath *aspath) { - unsigned short buflen = aspath->str_len + 1; - struct aspath *new; + unsigned short buflen = aspath->str_len + 1; + struct aspath *new; - new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); - new->json = NULL; + new = XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath)); + new->json = NULL; - if (aspath->segments) - new->segments = assegment_dup_all (aspath->segments); + if (aspath->segments) + new->segments = assegment_dup_all(aspath->segments); - if (!aspath->str) - return new; + if (!aspath->str) + return new; - new->str = XMALLOC (MTYPE_AS_STR, buflen); - new->str_len = aspath->str_len; + 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'; + /* copy the string data */ + if (aspath->str_len > 0) + memcpy(new->str, aspath->str, buflen); + else + new->str[0] = '\0'; - return new; + return new; } -static void * -aspath_hash_alloc (void *arg) +static void *aspath_hash_alloc(void *arg) { - const struct aspath *aspath = arg; - struct aspath *new; + const struct aspath *aspath = arg; + struct aspath *new; - /* Malformed AS path value. */ - assert (aspath->str); + /* Malformed AS path value. */ + assert(aspath->str); - /* New aspath structure is needed. */ - new = XMALLOC (MTYPE_AS_PATH, sizeof (struct 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; - new->json = aspath->json; + /* Reuse segments and string representation */ + new->refcnt = 0; + new->segments = aspath->segments; + new->str = aspath->str; + new->str_len = aspath->str_len; + new->json = aspath->json; - return new; + return new; } /* parse as-segment byte stream in struct assegment */ -static int -assegments_parse (struct stream *s, size_t length, - struct assegment **result, int use32bit) -{ - struct assegment_header segh; - struct assegment *seg, *prev = NULL, *head = NULL; - size_t bytes = 0; - - /* empty aspath (ie iBGP or somesuch) */ - if (length == 0) - return 0; - - if (BGP_DEBUG (as4, AS4_SEGMENT)) - zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu", - (unsigned long) length); - /* basic checks */ - if ((STREAM_READABLE(s) < length) - || (STREAM_READABLE(s) < AS_HEADER_SIZE) - || (length % AS16_VALUE_SIZE )) - return -1; - - while (bytes < length) - { - int i; - size_t seg_size; - - if ((length - bytes) <= AS_HEADER_SIZE) - { - if (head) - assegment_free_all (head); - return -1; - } - - /* softly softly, get the header first on its own */ - segh.type = stream_getc (s); - segh.length = stream_getc (s); - - seg_size = ASSEGMENT_SIZE(segh.length, use32bit); - - if (BGP_DEBUG (as4, AS4_SEGMENT)) - zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d", - segh.type, segh.length); - - /* check it.. */ - if ( ((bytes + seg_size) > length) - /* 1771bis 4.3b: seg length contains one or more */ - || (segh.length == 0) - /* Paranoia in case someone changes type of segment length. - * Shift both values by 0x10 to make the comparison operate - * on more, than 8 bits (otherwise it's a warning, bug #564). - */ - || ((sizeof segh.length > 1) - && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX))) - { - if (head) - assegment_free_all (head); - return -1; - } - - switch (segh.type) - { - case AS_SEQUENCE: - case AS_SET: - case AS_CONFED_SEQUENCE: - case AS_CONFED_SET: - break; - default: - if (head) - assegment_free_all (head); - return -1; - } - - /* now its safe to trust lengths */ - seg = assegment_new (segh.type, segh.length); - - if (head) - prev->next = seg; - else /* it's the first segment */ - head = prev = seg; - - for (i = 0; i < segh.length; i++) - seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s); - - bytes += seg_size; - - if (BGP_DEBUG (as4, AS4_SEGMENT)) - zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu", - (unsigned long) bytes); - - prev = seg; - } - - *result = assegment_normalise (head); - return 0; +static int assegments_parse(struct stream *s, size_t length, + struct assegment **result, int use32bit) +{ + struct assegment_header segh; + struct assegment *seg, *prev = NULL, *head = NULL; + size_t bytes = 0; + + /* empty aspath (ie iBGP or somesuch) */ + if (length == 0) + return 0; + + if (BGP_DEBUG(as4, AS4_SEGMENT)) + zlog_debug( + "[AS4SEG] Parse aspath segment: got total byte length %lu", + (unsigned long)length); + /* basic checks */ + if ((STREAM_READABLE(s) < length) + || (STREAM_READABLE(s) < AS_HEADER_SIZE) + || (length % AS16_VALUE_SIZE)) + return -1; + + while (bytes < length) { + int i; + size_t seg_size; + + if ((length - bytes) <= AS_HEADER_SIZE) { + if (head) + assegment_free_all(head); + return -1; + } + + /* softly softly, get the header first on its own */ + segh.type = stream_getc(s); + segh.length = stream_getc(s); + + seg_size = ASSEGMENT_SIZE(segh.length, use32bit); + + if (BGP_DEBUG(as4, AS4_SEGMENT)) + zlog_debug( + "[AS4SEG] Parse aspath segment: got type %d, length %d", + segh.type, segh.length); + + /* check it.. */ + if (((bytes + seg_size) > length) + /* 1771bis 4.3b: seg length contains one or more */ + || (segh.length == 0) + /* Paranoia in case someone changes type of segment length. + * Shift both values by 0x10 to make the comparison operate + * on more, than 8 bits (otherwise it's a warning, bug + * #564). + */ + || ((sizeof segh.length > 1) + && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX))) { + if (head) + assegment_free_all(head); + return -1; + } + + switch (segh.type) { + case AS_SEQUENCE: + case AS_SET: + case AS_CONFED_SEQUENCE: + case AS_CONFED_SET: + break; + default: + if (head) + assegment_free_all(head); + return -1; + } + + /* now its safe to trust lengths */ + seg = assegment_new(segh.type, segh.length); + + if (head) + prev->next = seg; + else /* it's the first segment */ + head = prev = seg; + + for (i = 0; i < segh.length; i++) + seg->as[i] = + (use32bit) ? stream_getl(s) : stream_getw(s); + + bytes += seg_size; + + if (BGP_DEBUG(as4, AS4_SEGMENT)) + zlog_debug( + "[AS4SEG] Parse aspath segment: Bytes now: %lu", + (unsigned long)bytes); + + prev = seg; + } + + *result = assegment_normalise(head); + return 0; } /* AS path parse function. pnt is a pointer to byte stream and length is length of byte stream. If there is same AS path in the the AS - path hash then return it else make new AS path structure. - + path hash then return it else make new AS path structure. + On error NULL is returned. */ -struct aspath * -aspath_parse (struct stream *s, size_t length, int use32bit) -{ - struct aspath as; - struct aspath *find; - - /* If length is odd it's malformed AS path. */ - /* Nit-picking: if (use32bit == 0) it is malformed if odd, - * otherwise its malformed when length is larger than 2 and (length-2) - * is not dividable by 4. - * But... this time we're lazy - */ - if (length % AS16_VALUE_SIZE ) - return NULL; - - 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); - - /* 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); - if (as.json) - { - json_object_free(as.json); - as.json = NULL; +struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit) +{ + struct aspath as; + struct aspath *find; + + /* If length is odd it's malformed AS path. */ + /* Nit-picking: if (use32bit == 0) it is malformed if odd, + * otherwise its malformed when length is larger than 2 and (length-2) + * is not dividable by 4. + * But... this time we're lazy + */ + if (length % AS16_VALUE_SIZE) + return NULL; + + 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); + + /* 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); + if (as.json) { + json_object_free(as.json); + as.json = NULL; + } } - } - find->refcnt++; + find->refcnt++; - return find; + return find; } -static void -assegment_data_put (struct stream *s, as_t *as, int num, int use32bit) +static void assegment_data_put(struct stream *s, as_t *as, int num, + int use32bit) { - int i; - assert (num <= AS_SEGMENT_MAX); - - for (i = 0; i < num; i++) - if ( use32bit ) - stream_putl (s, as[i]); - else - { - if ( as[i] <= BGP_AS_MAX ) - stream_putw(s, as[i]); - else - stream_putw(s, BGP_AS_TRANS); - } + int i; + assert(num <= AS_SEGMENT_MAX); + + for (i = 0; i < num; i++) + if (use32bit) + stream_putl(s, as[i]); + else { + if (as[i] <= BGP_AS_MAX) + stream_putw(s, as[i]); + else + stream_putw(s, BGP_AS_TRANS); + } } -static size_t -assegment_header_put (struct stream *s, u_char type, int length) +static size_t assegment_header_put(struct stream *s, u_char type, int length) { - size_t lenp; - assert (length <= AS_SEGMENT_MAX); - stream_putc (s, type); - lenp = stream_get_endp (s); - stream_putc (s, length); - return lenp; + size_t lenp; + assert(length <= AS_SEGMENT_MAX); + stream_putc(s, type); + lenp = stream_get_endp(s); + stream_putc(s, length); + return lenp; } /* write aspath data to stream */ -size_t -aspath_put (struct stream *s, struct aspath *as, int use32bit ) -{ - struct assegment *seg = as->segments; - size_t bytes = 0; - - if (!seg || seg->length == 0) - return 0; - - if (seg) - { - /* - * Hey, what do we do when we have > STREAM_WRITABLE(s) here? - * At the moment, we would write out a partial aspath, and our peer - * will complain and drop the session :-/ - * - * The general assumption here is that many things tested will - * never happen. And, in real live, up to now, they have not. - */ - while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s))) - { - struct assegment *next = seg->next; - int written = 0; - int asns_packed = 0; - size_t lenp; - - /* Overlength segments have to be split up */ - while ( (seg->length - written) > AS_SEGMENT_MAX) - { - assegment_header_put (s, seg->type, AS_SEGMENT_MAX); - assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit); - written += AS_SEGMENT_MAX; - bytes += ASSEGMENT_SIZE (written, use32bit); - } - - /* write the final segment, probably is also the first */ - lenp = assegment_header_put (s, seg->type, seg->length - written); - assegment_data_put (s, (seg->as + written), seg->length - written, - use32bit); - - /* Sequence-type segments can be 'packed' together - * Case of a segment which was overlength and split up - * will be missed here, but that doesn't matter. - */ - while (next && ASSEGMENTS_PACKABLE (seg, next)) - { - /* NB: We should never normally get here given we - * normalise aspath data when parse them. However, better - * safe than sorry. We potentially could call - * assegment_normalise here instead, but it's cheaper and - * easier to do it on the fly here rather than go through - * the segment list twice every time we write out - * aspath's. - */ - - /* Next segment's data can fit in this one */ - assegment_data_put (s, next->as, next->length, use32bit); - - /* update the length of the segment header */ - stream_putc_at (s, lenp, seg->length - written + next->length); - asns_packed += next->length; - - next = next->next; - } - - bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed, - use32bit); - seg = next; - } - } - return bytes; +size_t aspath_put(struct stream *s, struct aspath *as, int use32bit) +{ + struct assegment *seg = as->segments; + size_t bytes = 0; + + if (!seg || seg->length == 0) + return 0; + + if (seg) { + /* + * Hey, what do we do when we have > STREAM_WRITABLE(s) here? + * At the moment, we would write out a partial aspath, and our + * peer + * will complain and drop the session :-/ + * + * The general assumption here is that many things tested will + * never happen. And, in real live, up to now, they have not. + */ + while (seg && (ASSEGMENT_LEN(seg, use32bit) + <= STREAM_WRITEABLE(s))) { + struct assegment *next = seg->next; + int written = 0; + int asns_packed = 0; + size_t lenp; + + /* Overlength segments have to be split up */ + while ((seg->length - written) > AS_SEGMENT_MAX) { + assegment_header_put(s, seg->type, + AS_SEGMENT_MAX); + assegment_data_put(s, seg->as, AS_SEGMENT_MAX, + use32bit); + written += AS_SEGMENT_MAX; + bytes += ASSEGMENT_SIZE(written, use32bit); + } + + /* write the final segment, probably is also the first + */ + lenp = assegment_header_put(s, seg->type, + seg->length - written); + assegment_data_put(s, (seg->as + written), + seg->length - written, use32bit); + + /* Sequence-type segments can be 'packed' together + * Case of a segment which was overlength and split up + * will be missed here, but that doesn't matter. + */ + while (next && ASSEGMENTS_PACKABLE(seg, next)) { + /* NB: We should never normally get here given + * we + * normalise aspath data when parse them. + * However, better + * safe than sorry. We potentially could call + * assegment_normalise here instead, but it's + * cheaper and + * easier to do it on the fly here rather than + * go through + * the segment list twice every time we write + * out + * aspath's. + */ + + /* Next segment's data can fit in this one */ + assegment_data_put(s, next->as, next->length, + use32bit); + + /* update the length of the segment header */ + stream_putc_at(s, lenp, + seg->length - written + + next->length); + asns_packed += next->length; + + next = next->next; + } + + bytes += ASSEGMENT_SIZE( + seg->length - written + asns_packed, use32bit); + seg = next; + } + } + return bytes; } /* This is for SNMP BGP4PATHATTRASPATHSEGMENT * We have no way to manage the storage, so we use a static stream * wrapper around aspath_put. */ -u_char * -aspath_snmp_pathseg (struct aspath *as, size_t *varlen) +u_char *aspath_snmp_pathseg(struct aspath *as, size_t *varlen) { #define SNMP_PATHSEG_MAX 1024 - if (!snmp_stream) - snmp_stream = stream_new (SNMP_PATHSEG_MAX); - else - stream_reset (snmp_stream); - - if (!as) - { - *varlen = 0; - return NULL; - } - aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */ - - *varlen = stream_get_endp (snmp_stream); - return stream_pnt(snmp_stream); -} - + if (!snmp_stream) + snmp_stream = stream_new(SNMP_PATHSEG_MAX); + else + stream_reset(snmp_stream); + + if (!as) { + *varlen = 0; + return NULL; + } + aspath_put(snmp_stream, as, 0); /* use 16 bit for now here */ + + *varlen = stream_get_endp(snmp_stream); + return stream_pnt(snmp_stream); +} + #define min(A,B) ((A) < (B) ? (A) : (B)) -static struct assegment * -aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset, - as_t as) -{ - int i; - - /* If this is first AS set member, create new as-set segment. */ - if (asset == NULL) - { - asset = assegment_new (AS_SET, 1); - if (! aspath->segments) - aspath->segments = asset; - else - { - struct assegment *seg = aspath->segments; - while (seg->next) - seg = seg->next; - seg->next = asset; - } - asset->type = AS_SET; - asset->length = 1; - asset->as[0] = as; - } - else - { - /* Check this AS value already exists or not. */ - for (i = 0; i < asset->length; i++) - if (asset->as[i] == as) - return asset; - - asset->length++; - asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as, - asset->length * AS_VALUE_SIZE); - asset->as[asset->length - 1] = as; - } - - - return asset; +static struct assegment *aspath_aggregate_as_set_add(struct aspath *aspath, + struct assegment *asset, + as_t as) +{ + int i; + + /* If this is first AS set member, create new as-set segment. */ + if (asset == NULL) { + asset = assegment_new(AS_SET, 1); + if (!aspath->segments) + aspath->segments = asset; + else { + struct assegment *seg = aspath->segments; + while (seg->next) + seg = seg->next; + seg->next = asset; + } + asset->type = AS_SET; + asset->length = 1; + asset->as[0] = as; + } else { + /* Check this AS value already exists or not. */ + for (i = 0; i < asset->length; i++) + if (asset->as[i] == as) + return asset; + + asset->length++; + asset->as = XREALLOC(MTYPE_AS_SEG_DATA, asset->as, + asset->length * AS_VALUE_SIZE); + asset->as[asset->length - 1] = as; + } + + + return asset; } /* Modify as1 using as2 for aggregation. */ -struct aspath * -aspath_aggregate (struct aspath *as1, struct aspath *as2) -{ - int i; - int minlen = 0; - int match = 0; - int from; - struct assegment *seg1 = as1->segments; - struct assegment *seg2 = as2->segments; - struct aspath *aspath = NULL; - struct assegment *asset = NULL; - struct assegment *prevseg = NULL; - - /* First of all check common leading sequence. */ - while (seg1 && seg2) - { - /* Check segment type. */ - if (seg1->type != seg2->type) - break; - - /* Minimum segment length. */ - minlen = min (seg1->length, seg2->length); - - for (match = 0; match < minlen; match++) - if (seg1->as[match] != seg2->as[match]) - break; - - if (match) - { - struct assegment *seg = assegment_new (seg1->type, 0); - - seg = assegment_append_asns (seg, seg1->as, match); - - if (! aspath) - { - aspath = aspath_new (); - aspath->segments = seg; - } - else - prevseg->next = seg; - - prevseg = seg; +struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2) +{ + int i; + int minlen = 0; + int match = 0; + int from; + struct assegment *seg1 = as1->segments; + struct assegment *seg2 = as2->segments; + struct aspath *aspath = NULL; + struct assegment *asset = NULL; + struct assegment *prevseg = NULL; + + /* First of all check common leading sequence. */ + while (seg1 && seg2) { + /* Check segment type. */ + if (seg1->type != seg2->type) + break; + + /* Minimum segment length. */ + minlen = min(seg1->length, seg2->length); + + for (match = 0; match < minlen; match++) + if (seg1->as[match] != seg2->as[match]) + break; + + if (match) { + struct assegment *seg = assegment_new(seg1->type, 0); + + seg = assegment_append_asns(seg, seg1->as, match); + + if (!aspath) { + aspath = aspath_new(); + aspath->segments = seg; + } else + prevseg->next = seg; + + prevseg = seg; + } + + if (match != minlen || match != seg1->length + || seg1->length != seg2->length) + break; + /* We are moving on to the next segment to reset match */ + else + match = 0; + + seg1 = seg1->next; + seg2 = seg2->next; + } + + if (!aspath) + aspath = aspath_new(); + + /* Make as-set using rest of all information. */ + from = match; + while (seg1) { + for (i = from; i < seg1->length; i++) + asset = aspath_aggregate_as_set_add(aspath, asset, + seg1->as[i]); + + from = 0; + seg1 = seg1->next; } - if (match != minlen || match != seg1->length - || seg1->length != seg2->length) - break; - /* We are moving on to the next segment to reset match */ - else - match = 0; - - seg1 = seg1->next; - seg2 = seg2->next; - } - - if (! aspath) - aspath = aspath_new(); - - /* Make as-set using rest of all information. */ - from = match; - while (seg1) - { - for (i = from; i < seg1->length; i++) - asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]); - - from = 0; - seg1 = seg1->next; - } - - from = match; - while (seg2) - { - for (i = from; i < seg2->length; i++) - asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]); - - from = 0; - seg2 = seg2->next; - } - - assegment_normalise (aspath->segments); - aspath_str_update (aspath); - return aspath; + from = match; + while (seg2) { + for (i = from; i < seg2->length; i++) + asset = aspath_aggregate_as_set_add(aspath, asset, + seg2->as[i]); + + from = 0; + seg2 = seg2->next; + } + + assegment_normalise(aspath->segments); + aspath_str_update(aspath); + return aspath; } /* When a BGP router receives an UPDATE with an MP_REACH_NLRI attribute, check the leftmost AS number in the AS_PATH attribute is - or not the peer's AS number. */ -int -aspath_firstas_check (struct aspath *aspath, as_t asno) + or not the peer's AS number. */ +int aspath_firstas_check(struct aspath *aspath, as_t asno) { - if ( (aspath == NULL) || (aspath->segments == NULL) ) - return 0; - - if (aspath->segments - && (aspath->segments->type == AS_SEQUENCE) - && (aspath->segments->as[0] == asno )) - return 1; + if ((aspath == NULL) || (aspath->segments == NULL)) + return 0; + + if (aspath->segments && (aspath->segments->type == AS_SEQUENCE) + && (aspath->segments->as[0] == asno)) + return 1; - return 0; + return 0; } -unsigned int -aspath_get_first_as (struct aspath *aspath) +unsigned int aspath_get_first_as(struct aspath *aspath) { - if (aspath == NULL || aspath->segments == NULL) - return 0; + if (aspath == NULL || aspath->segments == NULL) + return 0; - return aspath->segments->as[0]; + return aspath->segments->as[0]; } -unsigned int -aspath_get_last_as (struct aspath *aspath) +unsigned int aspath_get_last_as(struct aspath *aspath) { - int i; - unsigned int last_as = 0; - const struct assegment *seg; + int i; + unsigned int last_as = 0; + const struct assegment *seg; - if (aspath == NULL || aspath->segments == NULL) - return last_as; + if (aspath == NULL || aspath->segments == NULL) + return last_as; - seg = aspath->segments; + seg = aspath->segments; - while (seg) - { - if (seg->type == AS_SEQUENCE || seg->type == AS_CONFED_SEQUENCE) - for (i = 0; i < seg->length; i++) - last_as = seg->as[i]; - seg = seg->next; - } + while (seg) { + if (seg->type == AS_SEQUENCE || seg->type == AS_CONFED_SEQUENCE) + for (i = 0; i < seg->length; i++) + last_as = seg->as[i]; + seg = seg->next; + } - return last_as; + return last_as; } /* AS path loop check. If aspath contains asno then return >= 1. */ -int -aspath_loop_check (struct aspath *aspath, as_t asno) -{ - struct assegment *seg; - int count = 0; - - if ( (aspath == NULL) || (aspath->segments == NULL) ) - return 0; - - seg = aspath->segments; - - while (seg) - { - int i; - - for (i = 0; i < seg->length; i++) - if (seg->as[i] == asno) - count++; - - seg = seg->next; - } - return count; +int aspath_loop_check(struct aspath *aspath, as_t asno) +{ + struct assegment *seg; + int count = 0; + + if ((aspath == NULL) || (aspath->segments == NULL)) + return 0; + + seg = aspath->segments; + + while (seg) { + int i; + + for (i = 0; i < seg->length; i++) + if (seg->as[i] == asno) + count++; + + seg = seg->next; + } + return count; } /* When all of AS path is private AS return 1. */ -int -aspath_private_as_check (struct aspath *aspath) +int aspath_private_as_check(struct aspath *aspath) { - struct assegment *seg; + struct assegment *seg; - if ( !(aspath && aspath->segments) ) - return 0; + if (!(aspath && aspath->segments)) + return 0; - seg = aspath->segments; + seg = aspath->segments; - while (seg) - { - int i; + while (seg) { + int i; - for (i = 0; i < seg->length; i++) - { - if (!BGP_AS_IS_PRIVATE(seg->as[i])) - return 0; + for (i = 0; i < seg->length; i++) { + if (!BGP_AS_IS_PRIVATE(seg->as[i])) + return 0; + } + seg = seg->next; } - seg = seg->next; - } - return 1; + return 1; } /* Return True if the entire ASPATH consist of the specified ASN */ -int -aspath_single_asn_check (struct aspath *aspath, as_t asn) +int aspath_single_asn_check(struct aspath *aspath, as_t asn) { - struct assegment *seg; + struct assegment *seg; - if ( !(aspath && aspath->segments) ) - return 0; + if (!(aspath && aspath->segments)) + return 0; - seg = aspath->segments; + seg = aspath->segments; - while (seg) - { - int i; + while (seg) { + int i; - for (i = 0; i < seg->length; i++) - { - if (seg->as[i] != asn) - return 0; + for (i = 0; i < seg->length; i++) { + if (seg->as[i] != asn) + return 0; + } + seg = seg->next; } - seg = seg->next; - } - return 1; + return 1; } /* Replace all instances of the target ASN with our own ASN */ -struct aspath * -aspath_replace_specific_asn (struct aspath *aspath, as_t target_asn, - as_t our_asn) +struct aspath *aspath_replace_specific_asn(struct aspath *aspath, + as_t target_asn, as_t our_asn) { - struct aspath *new; - struct assegment *seg; + struct aspath *new; + struct assegment *seg; - new = aspath_dup(aspath); - seg = new->segments; + new = aspath_dup(aspath); + seg = new->segments; - while (seg) - { - int i; + while (seg) { + int i; - for (i = 0; i < seg->length; i++) - { - if (seg->as[i] == target_asn) - seg->as[i] = our_asn; + for (i = 0; i < seg->length; i++) { + if (seg->as[i] == target_asn) + seg->as[i] = our_asn; + } + seg = seg->next; } - seg = seg->next; - } - aspath_str_update(new); - return new; + aspath_str_update(new); + return new; } /* Replace all private ASNs with our own ASN */ -struct aspath * -aspath_replace_private_asns (struct aspath *aspath, as_t asn) +struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn) { - struct aspath *new; - struct assegment *seg; + struct aspath *new; + struct assegment *seg; - new = aspath_dup(aspath); - seg = new->segments; + new = aspath_dup(aspath); + seg = new->segments; - while (seg) - { - int i; + while (seg) { + int i; - for (i = 0; i < seg->length; i++) - { - if (BGP_AS_IS_PRIVATE(seg->as[i])) - seg->as[i] = asn; + for (i = 0; i < seg->length; i++) { + if (BGP_AS_IS_PRIVATE(seg->as[i])) + seg->as[i] = asn; + } + seg = seg->next; } - seg = seg->next; - } - aspath_str_update(new); - return new; + aspath_str_update(new); + return new; } /* Remove all private ASNs */ -struct aspath * -aspath_remove_private_asns (struct aspath *aspath) -{ - struct aspath *new; - struct assegment *seg; - struct assegment *new_seg; - struct assegment *last_new_seg; - int i; - int j; - int public = 0; - - new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); - - new->json = NULL; - new_seg = NULL; - last_new_seg = NULL; - seg = aspath->segments; - while (seg) - { - public = 0; - for (i = 0; i < seg->length; i++) - { - // ASN is public - if (!BGP_AS_IS_PRIVATE(seg->as[i])) - { - public++; - } - } - - // The entire segment is private so skip it - if (!public) - { - seg = seg->next; - continue; - } - - // The entire segment is public so copy it - else if (public == seg->length) - { - new_seg = assegment_dup (seg); - } - - // The segment is a mix of public and private ASNs. Copy as many spots as - // there are public ASNs then come back and fill in only the public ASNs. - else - { - new_seg = assegment_new (seg->type, public); - j = 0; - for (i = 0; i < seg->length; i++) - { - // ASN is public - if (!BGP_AS_IS_PRIVATE(seg->as[i])) - { - new_seg->as[j] = seg->as[i]; - j++; - } - } - } - - // This is the first segment so set the aspath segments pointer to this one - if (!last_new_seg) - new->segments = new_seg; - else - last_new_seg->next = new_seg; - - last_new_seg = new_seg; - seg = seg->next; - } - - aspath_str_update(new); - return new; -} - -/* AS path confed check. If aspath contains confed set or sequence then return 1. */ -int -aspath_confed_check (struct aspath *aspath) -{ - struct assegment *seg; - - if ( !(aspath && aspath->segments) ) - return 0; - - seg = aspath->segments; - - while (seg) - { - if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE) - return 1; - seg = seg->next; - } - return 0; +struct aspath *aspath_remove_private_asns(struct aspath *aspath) +{ + struct aspath *new; + struct assegment *seg; + struct assegment *new_seg; + struct assegment *last_new_seg; + int i; + int j; + int public = 0; + + new = XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath)); + + new->json = NULL; + new_seg = NULL; + last_new_seg = NULL; + seg = aspath->segments; + while (seg) { + public + = 0; + for (i = 0; i < seg->length; i++) { + // ASN is public + if (!BGP_AS_IS_PRIVATE(seg->as[i])) { + public + ++; + } + } + + // The entire segment is private so skip it + if (!public) { + seg = seg->next; + continue; + } + + // The entire segment is public so copy it + else if (public == seg->length) { + new_seg = assegment_dup(seg); + } + + // The segment is a mix of public and private ASNs. Copy as many + // spots as + // there are public ASNs then come back and fill in only the + // public ASNs. + else { + new_seg = assegment_new(seg->type, public); + j = 0; + for (i = 0; i < seg->length; i++) { + // ASN is public + if (!BGP_AS_IS_PRIVATE(seg->as[i])) { + new_seg->as[j] = seg->as[i]; + j++; + } + } + } + + // This is the first segment so set the aspath segments pointer + // to this one + if (!last_new_seg) + new->segments = new_seg; + else + last_new_seg->next = new_seg; + + last_new_seg = new_seg; + seg = seg->next; + } + + aspath_str_update(new); + return new; +} + +/* AS path confed check. If aspath contains confed set or sequence then return + * 1. */ +int aspath_confed_check(struct aspath *aspath) +{ + struct assegment *seg; + + if (!(aspath && aspath->segments)) + return 0; + + seg = aspath->segments; + + while (seg) { + if (seg->type == AS_CONFED_SET + || seg->type == AS_CONFED_SEQUENCE) + return 1; + seg = seg->next; + } + return 0; } /* Leftmost AS path segment confed check. If leftmost AS segment is of type AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */ -int -aspath_left_confed_check (struct aspath *aspath) +int aspath_left_confed_check(struct aspath *aspath) { - if ( !(aspath && aspath->segments) ) - return 0; + if (!(aspath && aspath->segments)) + return 0; - if ( (aspath->segments->type == AS_CONFED_SEQUENCE) - || (aspath->segments->type == AS_CONFED_SET) ) - return 1; + if ((aspath->segments->type == AS_CONFED_SEQUENCE) + || (aspath->segments->type == AS_CONFED_SET)) + return 1; - return 0; + return 0; } /* Merge as1 to as2. as2 should be uninterned aspath. */ -static struct aspath * -aspath_merge (struct aspath *as1, struct aspath *as2) +static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2) { - struct assegment *last, *new; + struct assegment *last, *new; - if (! as1 || ! as2) - return NULL; + if (!as1 || !as2) + return NULL; - last = new = assegment_dup_all (as1->segments); - - /* find the last valid segment */ - while (last && last->next) - last = last->next; - - last->next = as2->segments; - as2->segments = new; - aspath_str_update (as2); - return as2; + last = new = assegment_dup_all(as1->segments); + + /* find the last valid segment */ + while (last && last->next) + last = last->next; + + last->next = as2->segments; + as2->segments = new; + aspath_str_update(as2); + return as2; } /* Prepend as1 to as2. as2 should be uninterned aspath. */ -struct aspath * -aspath_prepend (struct aspath *as1, struct aspath *as2) -{ - struct assegment *seg1; - struct assegment *seg2; - - if (! as1 || ! as2) - return NULL; - - seg1 = as1->segments; - seg2 = as2->segments; - - /* If as2 is empty, only need to dupe as1's chain onto as2 */ - if (seg2 == NULL) - { - as2->segments = assegment_dup_all (as1->segments); - aspath_str_update (as2); - return as2; - } - - /* If as1 is empty AS, no prepending to do. */ - if (seg1 == NULL) - return as2; - - /* find the tail as1's segment chain. */ - while (seg1 && seg1->next) - seg1 = seg1->next; - - /* Delete any AS_CONFED_SEQUENCE segment from as2. */ - if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE) - as2 = aspath_delete_confed_seq (as2); - - /* Compare last segment type of as1 and first segment type of as2. */ - if (seg1->type != seg2->type) - return aspath_merge (as1, as2); - - if (seg1->type == AS_SEQUENCE) - { - /* We have two chains of segments, as1->segments and seg2, - * and we have to attach them together, merging the attaching - * segments together into one. - * - * 1. dupe as1->segments onto head of as2 - * 2. merge seg2's asns onto last segment of this new chain - * 3. attach chain after seg2 - */ - - /* dupe as1 onto as2's head */ - seg1 = as2->segments = assegment_dup_all (as1->segments); - - /* refind the tail of as2, reusing seg1 */ - while (seg1 && seg1->next) - seg1 = seg1->next; - - /* merge the old head, seg2, into tail, seg1 */ - seg1 = assegment_append_asns (seg1, seg2->as, seg2->length); - - /* bypass the merged seg2, and attach any chain after it to - * chain descending from as2's head - */ - seg1->next = seg2->next; - - /* seg2 is now referenceless and useless*/ - assegment_free (seg2); - - /* we've now prepended as1's segment chain to as2, merging - * the inbetween AS_SEQUENCE of seg2 in the process - */ - aspath_str_update (as2); - return as2; - } - else - { - /* AS_SET merge code is needed at here. */ - return aspath_merge (as1, as2); - } - /* XXX: Ermmm, what if as1 has multiple segments?? */ - - /* Not reached */ +struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) +{ + struct assegment *seg1; + struct assegment *seg2; + + if (!as1 || !as2) + return NULL; + + seg1 = as1->segments; + seg2 = as2->segments; + + /* If as2 is empty, only need to dupe as1's chain onto as2 */ + if (seg2 == NULL) { + as2->segments = assegment_dup_all(as1->segments); + aspath_str_update(as2); + return as2; + } + + /* If as1 is empty AS, no prepending to do. */ + if (seg1 == NULL) + return as2; + + /* find the tail as1's segment chain. */ + while (seg1 && seg1->next) + seg1 = seg1->next; + + /* Delete any AS_CONFED_SEQUENCE segment from as2. */ + if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE) + as2 = aspath_delete_confed_seq(as2); + + /* Compare last segment type of as1 and first segment type of as2. */ + if (seg1->type != seg2->type) + return aspath_merge(as1, as2); + + if (seg1->type == AS_SEQUENCE) { + /* We have two chains of segments, as1->segments and seg2, + * and we have to attach them together, merging the attaching + * segments together into one. + * + * 1. dupe as1->segments onto head of as2 + * 2. merge seg2's asns onto last segment of this new chain + * 3. attach chain after seg2 + */ + + /* dupe as1 onto as2's head */ + seg1 = as2->segments = assegment_dup_all(as1->segments); + + /* refind the tail of as2, reusing seg1 */ + while (seg1 && seg1->next) + seg1 = seg1->next; + + /* merge the old head, seg2, into tail, seg1 */ + seg1 = assegment_append_asns(seg1, seg2->as, seg2->length); + + /* bypass the merged seg2, and attach any chain after it to + * chain descending from as2's head + */ + seg1->next = seg2->next; + + /* seg2 is now referenceless and useless*/ + assegment_free(seg2); + + /* we've now prepended as1's segment chain to as2, merging + * the inbetween AS_SEQUENCE of seg2 in the process + */ + aspath_str_update(as2); + return as2; + } else { + /* AS_SET merge code is needed at here. */ + return aspath_merge(as1, as2); + } + /* XXX: Ermmm, what if as1 has multiple segments?? */ + + /* Not reached */ } /* Iterate over AS_PATH segments and wipe all occurences of the @@ -1541,159 +1449,158 @@ aspath_prepend (struct aspath *as1, struct aspath *as2) * version of aspath_dup(), which allocates memory to hold the new * data, not the original. The new AS path is returned. */ -struct aspath * -aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list) -{ - struct assegment * srcseg, * exclseg, * lastseg; - struct aspath * newpath; - - newpath = aspath_new(); - lastseg = NULL; - - for (srcseg = source->segments; srcseg; srcseg = srcseg->next) - { - unsigned i, y, newlen = 0, done = 0, skip_as; - struct assegment * newseg; - - /* Find out, how much ASns are we going to pick from this segment. - * We can't perform filtering right inline, because the size of - * the new segment isn't known at the moment yet. - */ - for (i = 0; i < srcseg->length; i++) - { - skip_as = 0; - for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next) - for (y = 0; y < exclseg->length; y++) - if (srcseg->as[i] == exclseg->as[y]) - { - skip_as = 1; - // There's no sense in testing the rest of exclusion list, bail out. - break; - } - if (!skip_as) - newlen++; - } - /* newlen is now the number of ASns to copy */ - if (!newlen) - continue; - - /* Actual copying. Allocate memory and iterate once more, performing filtering. */ - newseg = assegment_new (srcseg->type, newlen); - for (i = 0; i < srcseg->length; i++) - { - skip_as = 0; - for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next) - for (y = 0; y < exclseg->length; y++) - if (srcseg->as[i] == exclseg->as[y]) - { - skip_as = 1; - break; - } - if (skip_as) - continue; - newseg->as[done++] = srcseg->as[i]; - } - /* At his point newlen must be equal to done, and both must be positive. Append - * the filtered segment to the gross result. */ - if (!lastseg) - newpath->segments = newseg; - else - lastseg->next = newseg; - lastseg = newseg; - } - aspath_str_update (newpath); - /* We are happy returning even an empty AS_PATH, because the administrator - * might expect this very behaviour. There's a mean to avoid this, if necessary, - * by having a match rule against certain AS_PATH regexps in the route-map index. - */ - aspath_free (source); - return newpath; +struct aspath *aspath_filter_exclude(struct aspath *source, + struct aspath *exclude_list) +{ + struct assegment *srcseg, *exclseg, *lastseg; + struct aspath *newpath; + + newpath = aspath_new(); + lastseg = NULL; + + for (srcseg = source->segments; srcseg; srcseg = srcseg->next) { + unsigned i, y, newlen = 0, done = 0, skip_as; + struct assegment *newseg; + + /* Find out, how much ASns are we going to pick from this + * segment. + * We can't perform filtering right inline, because the size of + * the new segment isn't known at the moment yet. + */ + for (i = 0; i < srcseg->length; i++) { + skip_as = 0; + for (exclseg = exclude_list->segments; + exclseg && !skip_as; exclseg = exclseg->next) + for (y = 0; y < exclseg->length; y++) + if (srcseg->as[i] == exclseg->as[y]) { + skip_as = 1; + // There's no sense in testing + // the rest of exclusion list, + // bail out. + break; + } + if (!skip_as) + newlen++; + } + /* newlen is now the number of ASns to copy */ + if (!newlen) + continue; + + /* Actual copying. Allocate memory and iterate once more, + * performing filtering. */ + newseg = assegment_new(srcseg->type, newlen); + for (i = 0; i < srcseg->length; i++) { + skip_as = 0; + for (exclseg = exclude_list->segments; + exclseg && !skip_as; exclseg = exclseg->next) + for (y = 0; y < exclseg->length; y++) + if (srcseg->as[i] == exclseg->as[y]) { + skip_as = 1; + break; + } + if (skip_as) + continue; + newseg->as[done++] = srcseg->as[i]; + } + /* At his point newlen must be equal to done, and both must be + * positive. Append + * the filtered segment to the gross result. */ + if (!lastseg) + newpath->segments = newseg; + else + lastseg->next = newseg; + lastseg = newseg; + } + aspath_str_update(newpath); + /* We are happy returning even an empty AS_PATH, because the + * administrator + * might expect this very behaviour. There's a mean to avoid this, if + * necessary, + * by having a match rule against certain AS_PATH regexps in the + * route-map index. + */ + aspath_free(source); + return newpath; } /* Add specified AS to the leftmost of aspath. */ -static struct aspath * -aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num) -{ - struct assegment *assegment = aspath->segments; - unsigned i; - - if (assegment && assegment->type == type) - { - /* extend existing segment */ - aspath->segments = assegment_prepend_asns (aspath->segments, asno, num); - } - else - { - /* 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); +static struct aspath *aspath_add_asns(struct aspath *aspath, as_t asno, + u_char type, unsigned num) +{ + struct assegment *assegment = aspath->segments; + unsigned i; + + if (assegment && assegment->type == type) { + /* extend existing segment */ + aspath->segments = + assegment_prepend_asns(aspath->segments, asno, num); + } else { + /* 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; } - else - newsegment->next = assegment; - aspath->segments = newsegment; - } - aspath_str_update (aspath); - return aspath; + 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) +struct aspath *aspath_add_seq_n(struct aspath *aspath, as_t asno, unsigned num) { - return aspath_add_asns (aspath, asno, AS_SEQUENCE, 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) +struct aspath *aspath_add_seq(struct aspath *aspath, as_t asno) { - return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1); + return aspath_add_asns(aspath, asno, AS_SEQUENCE, 1); } /* Compare leftmost AS value for MED check. If as1's leftmost AS and as2's leftmost AS is same return 1. */ -int -aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2) +int aspath_cmp_left(const struct aspath *aspath1, const struct aspath *aspath2) { - const struct assegment *seg1; - const struct assegment *seg2; + const struct assegment *seg1; + const struct assegment *seg2; + + if (!(aspath1 && aspath2)) + return 0; - if (!(aspath1 && aspath2)) - return 0; + seg1 = aspath1->segments; + seg2 = aspath2->segments; - seg1 = aspath1->segments; - seg2 = aspath2->segments; + /* If both paths are originated in this AS then we do want to compare + * MED */ + if (!seg1 && !seg2) + return 1; - /* If both paths are originated in this AS then we do want to compare MED */ - if (!seg1 && !seg2) - return 1; + /* find first non-confed segments for each */ + while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE) + || (seg1->type == AS_CONFED_SET))) + seg1 = seg1->next; - /* find first non-confed segments for each */ - while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE) - || (seg1->type == AS_CONFED_SET))) - seg1 = seg1->next; + while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE) + || (seg2->type == AS_CONFED_SET))) + seg2 = seg2->next; - while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE) - || (seg2->type == AS_CONFED_SET))) - seg2 = seg2->next; + /* Check as1's */ + if (!(seg1 && seg2 && (seg1->type == AS_SEQUENCE) + && (seg2->type == AS_SEQUENCE))) + return 0; - /* Check as1's */ - if (!(seg1 && seg2 - && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE))) - return 0; - - if (seg1->as[0] == seg2->as[0]) - return 1; + if (seg1->as[0] == seg2->as[0]) + return 1; - return 0; + return 0; } /* Truncate an aspath after a number of hops, and put the hops remaining @@ -1702,127 +1609,127 @@ aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2) * Returned aspath is a /new/ aspath, which should either by free'd or * interned by the caller, as desired. */ -struct aspath * -aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path) -{ - struct assegment *seg, *newseg, *prevseg = NULL; - struct aspath *newpath = NULL, *mergedpath; - int hops, cpasns = 0; - - if (!aspath) - return NULL; - - seg = aspath->segments; - - /* CONFEDs should get reconciled too.. */ - hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath)) - - aspath_count_hops (as4path); - - if (hops < 0) - { - if (BGP_DEBUG (as4, AS4)) - zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH"); - /* Something's gone wrong. The RFC says we should now ignore AS4_PATH, - * which is daft behaviour - it contains vital loop-detection - * information which must have been removed from AS_PATH. - */ - hops = aspath_count_hops (aspath); - } - - if (!hops) - { - newpath = aspath_dup (as4path); - aspath_str_update(newpath); - return newpath; - } - - if ( BGP_DEBUG(as4, AS4)) - zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now", - aspath->str, as4path->str); - - while (seg && hops > 0) - { - switch (seg->type) - { - case AS_SET: - case AS_CONFED_SET: - hops--; - cpasns = seg->length; - break; - case AS_CONFED_SEQUENCE: - /* Should never split a confed-sequence, if hop-count - * suggests we must then something's gone wrong somewhere. - * - * Most important goal is to preserve AS_PATHs prime function - * as loop-detector, so we fudge the numbers so that the entire - * confed-sequence is merged in. - */ - if (hops < seg->length) - { - if (BGP_DEBUG (as4, AS4)) - zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls" - " across 2/4 ASN boundary somewhere, broken.."); - hops = seg->length; - } - /* fallthru */ - case AS_SEQUENCE: - cpasns = MIN(seg->length, hops); - hops -= seg->length; +struct aspath *aspath_reconcile_as4(struct aspath *aspath, + struct aspath *as4path) +{ + struct assegment *seg, *newseg, *prevseg = NULL; + struct aspath *newpath = NULL, *mergedpath; + int hops, cpasns = 0; + + if (!aspath) + return NULL; + + seg = aspath->segments; + + /* CONFEDs should get reconciled too.. */ + hops = (aspath_count_hops(aspath) + aspath_count_confeds(aspath)) + - aspath_count_hops(as4path); + + if (hops < 0) { + if (BGP_DEBUG(as4, AS4)) + zlog_warn( + "[AS4] Fewer hops in AS_PATH than NEW_AS_PATH"); + /* Something's gone wrong. The RFC says we should now ignore + * AS4_PATH, + * which is daft behaviour - it contains vital loop-detection + * information which must have been removed from AS_PATH. + */ + hops = aspath_count_hops(aspath); + } + + if (!hops) { + newpath = aspath_dup(as4path); + aspath_str_update(newpath); + return newpath; } - - assert (cpasns <= seg->length); - - newseg = assegment_new (seg->type, 0); - newseg = assegment_append_asns (newseg, seg->as, cpasns); - - if (!newpath) - { - newpath = aspath_new (); - newpath->segments = newseg; - } - else - prevseg->next = newseg; - - prevseg = newseg; - seg = seg->next; - } - - /* We may be able to join some segments here, and we must - * do this because... we want normalised aspaths in out hash - * and we do not want to stumble in aspath_put. - */ - mergedpath = aspath_merge (newpath, aspath_dup(as4path)); - aspath_free (newpath); - mergedpath->segments = assegment_normalise (mergedpath->segments); - aspath_str_update (mergedpath); - - if ( BGP_DEBUG(as4, AS4)) - zlog_debug ("[AS4] result of synthesizing is %s", - mergedpath->str); - - return mergedpath; + + if (BGP_DEBUG(as4, AS4)) + zlog_debug( + "[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now", + aspath->str, as4path->str); + + while (seg && hops > 0) { + switch (seg->type) { + case AS_SET: + case AS_CONFED_SET: + hops--; + cpasns = seg->length; + break; + case AS_CONFED_SEQUENCE: + /* Should never split a confed-sequence, if hop-count + * suggests we must then something's gone wrong + * somewhere. + * + * Most important goal is to preserve AS_PATHs prime + * function + * as loop-detector, so we fudge the numbers so that the + * entire + * confed-sequence is merged in. + */ + if (hops < seg->length) { + if (BGP_DEBUG(as4, AS4)) + zlog_debug( + "[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls" + " across 2/4 ASN boundary somewhere, broken.."); + hops = seg->length; + } + /* fallthru */ + case AS_SEQUENCE: + cpasns = MIN(seg->length, hops); + hops -= seg->length; + } + + assert(cpasns <= seg->length); + + newseg = assegment_new(seg->type, 0); + newseg = assegment_append_asns(newseg, seg->as, cpasns); + + if (!newpath) { + newpath = aspath_new(); + newpath->segments = newseg; + } else + prevseg->next = newseg; + + prevseg = newseg; + seg = seg->next; + } + + /* We may be able to join some segments here, and we must + * do this because... we want normalised aspaths in out hash + * and we do not want to stumble in aspath_put. + */ + mergedpath = aspath_merge(newpath, aspath_dup(as4path)); + aspath_free(newpath); + mergedpath->segments = assegment_normalise(mergedpath->segments); + aspath_str_update(mergedpath); + + if (BGP_DEBUG(as4, AS4)) + zlog_debug("[AS4] result of synthesizing is %s", + mergedpath->str); + + return mergedpath; } /* Compare leftmost AS value for MED check. If as1's leftmost AS and as2's leftmost AS is same return 1. (confederation as-path only). */ -int -aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2) +int aspath_cmp_left_confed(const struct aspath *aspath1, + const struct aspath *aspath2) { - if (! (aspath1 && aspath2) ) - return 0; - - if ( !(aspath1->segments && aspath2->segments) ) - return 0; - - if ( (aspath1->segments->type != AS_CONFED_SEQUENCE) - || (aspath2->segments->type != AS_CONFED_SEQUENCE) ) - return 0; - - if (aspath1->segments->as[0] == aspath2->segments->as[0]) - return 1; + if (!(aspath1 && aspath2)) + return 0; - return 0; + if (!(aspath1->segments && aspath2->segments)) + return 0; + + if ((aspath1->segments->type != AS_CONFED_SEQUENCE) + || (aspath2->segments->type != AS_CONFED_SEQUENCE)) + return 0; + + if (aspath1->segments->as[0] == aspath2->segments->as[0]) + return 1; + + return 0; } /* Delete all AS_CONFED_SEQUENCE/SET segments from aspath. @@ -1833,111 +1740,100 @@ aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspat * removed from the AS_PATH attribute, leaving the sanitized * AS_PATH attribute to be operated on by steps 2, 3 or 4. */ -struct aspath * -aspath_delete_confed_seq (struct aspath *aspath) +struct aspath *aspath_delete_confed_seq(struct aspath *aspath) { - struct assegment *seg, *prev, *next; - char removed_confed_segment; + struct assegment *seg, *prev, *next; + char removed_confed_segment; + + if (!(aspath && aspath->segments)) + return aspath; - if (!(aspath && aspath->segments)) - return aspath; + seg = aspath->segments; + removed_confed_segment = 0; + next = NULL; + prev = NULL; - seg = aspath->segments; - removed_confed_segment = 0; - next = NULL; - prev = NULL; - - while (seg) - { - next = seg->next; + while (seg) { + next = seg->next; - if (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET) - { - /* This is the first segment in the aspath */ - if (aspath->segments == seg) - aspath->segments = seg->next; - else - prev->next = seg->next; + if (seg->type == AS_CONFED_SEQUENCE + || seg->type == AS_CONFED_SET) { + /* This is the first segment in the aspath */ + if (aspath->segments == seg) + aspath->segments = seg->next; + else + prev->next = seg->next; - assegment_free (seg); - removed_confed_segment = 1; - } - else - prev = seg; + assegment_free(seg); + removed_confed_segment = 1; + } else + prev = seg; - seg = next; - } + seg = next; + } - if (removed_confed_segment) - aspath_str_update (aspath); + if (removed_confed_segment) + aspath_str_update(aspath); - return aspath; + return aspath; } /* Add new AS number to the leftmost part of the aspath as AS_CONFED_SEQUENCE. */ -struct aspath* -aspath_add_confed_seq (struct aspath *aspath, as_t asno) +struct aspath *aspath_add_confed_seq(struct aspath *aspath, as_t asno) { - return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1); + return aspath_add_asns(aspath, asno, AS_CONFED_SEQUENCE, 1); } /* Add new as value to as path structure. */ -static void -aspath_as_add (struct aspath *as, as_t asno) +static void aspath_as_add(struct aspath *as, as_t asno) { - struct assegment *seg = as->segments; + struct assegment *seg = as->segments; + + if (!seg) + return; - if (!seg) - return; - - /* Last segment search procedure. */ - while (seg->next) - seg = seg->next; + /* Last segment search procedure. */ + while (seg->next) + seg = seg->next; - assegment_append_asns (seg, &asno, 1); + assegment_append_asns(seg, &asno, 1); } /* Add new as segment to the as path. */ -static void -aspath_segment_add (struct aspath *as, int type) +static void aspath_segment_add(struct aspath *as, int type) { - struct assegment *seg = as->segments; - struct assegment *new = assegment_new (type, 0); + struct assegment *seg = as->segments; + struct assegment *new = assegment_new(type, 0); - if (seg) - { - while (seg->next) - seg = seg->next; - seg->next = new; - } - else - as->segments = new; + if (seg) { + while (seg->next) + seg = seg->next; + seg->next = new; + } else + as->segments = new; } -struct aspath * -aspath_empty (void) +struct aspath *aspath_empty(void) { - return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */ + return aspath_parse(NULL, 0, 1); /* 32Bit ;-) */ } -struct aspath * -aspath_empty_get (void) +struct aspath *aspath_empty_get(void) { - struct aspath *aspath; + struct aspath *aspath; - aspath = aspath_new (); - aspath_make_str_count (aspath); - return aspath; + aspath = aspath_new(); + aspath_make_str_count(aspath); + return aspath; } -unsigned long -aspath_count (void) +unsigned long aspath_count(void) { - return ashash->count; -} + return ashash->count; +} -/* +/* Theoretically, one as path can have: One BGP packet size should be less than 4096. @@ -1947,246 +1843,230 @@ aspath_count (void) */ /* AS path string lexical token enum. */ -enum as_token -{ - as_token_asval, - as_token_set_start, - as_token_set_end, - as_token_confed_seq_start, - as_token_confed_seq_end, - as_token_confed_set_start, - as_token_confed_set_end, - as_token_unknown +enum as_token { + as_token_asval, + as_token_set_start, + as_token_set_end, + as_token_confed_seq_start, + as_token_confed_seq_end, + as_token_confed_set_start, + as_token_confed_set_end, + as_token_unknown }; /* Return next token and point for string parse. */ -static const char * -aspath_gettoken (const char *buf, enum as_token *token, u_long *asno) -{ - const char *p = buf; - - /* Skip seperators (space for sequences, ',' for sets). */ - while (isspace ((int) *p) || *p == ',') - p++; - - /* Check the end of the string and type specify characters - (e.g. {}()). */ - switch (*p) - { - case '\0': - return NULL; - case '{': - *token = as_token_set_start; - p++; - return p; - case '}': - *token = as_token_set_end; - p++; - return p; - case '(': - *token = as_token_confed_seq_start; - p++; - return p; - case ')': - *token = as_token_confed_seq_end; - p++; - return p; - case '[': - *token = as_token_confed_set_start; - p++; - return p; - case ']': - *token = as_token_confed_set_end; - p++; - return p; - } - - /* Check actual AS value. */ - if (isdigit ((int) *p)) - { - as_t asval; - - *token = as_token_asval; - asval = (*p - '0'); - p++; - - while (isdigit ((int) *p)) - { - asval *= 10; - asval += (*p - '0'); - p++; - } - *asno = asval; - return p; - } - - /* There is no match then return unknown token. */ - *token = as_token_unknown; - return p++; -} - -struct aspath * -aspath_str2aspath (const char *str) -{ - enum as_token token = as_token_unknown; - u_short as_type; - u_long asno = 0; - struct aspath *aspath; - int needtype; - - aspath = aspath_new (); - - /* We start default type as AS_SEQUENCE. */ - as_type = AS_SEQUENCE; - needtype = 1; - - while ((str = aspath_gettoken (str, &token, &asno)) != NULL) - { - switch (token) - { - case as_token_asval: - if (needtype) - { - aspath_segment_add (aspath, as_type); - needtype = 0; - } - aspath_as_add (aspath, asno); - break; - case as_token_set_start: - as_type = AS_SET; - aspath_segment_add (aspath, as_type); - needtype = 0; - break; - case as_token_set_end: - as_type = AS_SEQUENCE; - needtype = 1; - break; - case as_token_confed_seq_start: - as_type = AS_CONFED_SEQUENCE; - aspath_segment_add (aspath, as_type); - needtype = 0; - break; - case as_token_confed_seq_end: - as_type = AS_SEQUENCE; - needtype = 1; - break; - case as_token_confed_set_start: - as_type = AS_CONFED_SET; - aspath_segment_add (aspath, as_type); - needtype = 0; - break; - case as_token_confed_set_end: - as_type = AS_SEQUENCE; - needtype = 1; - break; - case as_token_unknown: - default: - aspath_free (aspath); - return NULL; +static const char *aspath_gettoken(const char *buf, enum as_token *token, + u_long *asno) +{ + const char *p = buf; + + /* Skip seperators (space for sequences, ',' for sets). */ + while (isspace((int)*p) || *p == ',') + p++; + + /* Check the end of the string and type specify characters + (e.g. {}()). */ + switch (*p) { + case '\0': + return NULL; + case '{': + *token = as_token_set_start; + p++; + return p; + case '}': + *token = as_token_set_end; + p++; + return p; + case '(': + *token = as_token_confed_seq_start; + p++; + return p; + case ')': + *token = as_token_confed_seq_end; + p++; + return p; + case '[': + *token = as_token_confed_set_start; + p++; + return p; + case ']': + *token = as_token_confed_set_end; + p++; + return p; + } + + /* Check actual AS value. */ + if (isdigit((int)*p)) { + as_t asval; + + *token = as_token_asval; + asval = (*p - '0'); + p++; + + while (isdigit((int)*p)) { + asval *= 10; + asval += (*p - '0'); + p++; + } + *asno = asval; + return p; } - } - aspath_make_str_count (aspath); + /* There is no match then return unknown token. */ + *token = as_token_unknown; + return p++; +} + +struct aspath *aspath_str2aspath(const char *str) +{ + enum as_token token = as_token_unknown; + u_short as_type; + u_long asno = 0; + struct aspath *aspath; + int needtype; + + aspath = aspath_new(); + + /* We start default type as AS_SEQUENCE. */ + as_type = AS_SEQUENCE; + needtype = 1; + + while ((str = aspath_gettoken(str, &token, &asno)) != NULL) { + switch (token) { + case as_token_asval: + if (needtype) { + aspath_segment_add(aspath, as_type); + needtype = 0; + } + aspath_as_add(aspath, asno); + break; + case as_token_set_start: + as_type = AS_SET; + aspath_segment_add(aspath, as_type); + needtype = 0; + break; + case as_token_set_end: + as_type = AS_SEQUENCE; + needtype = 1; + break; + case as_token_confed_seq_start: + as_type = AS_CONFED_SEQUENCE; + aspath_segment_add(aspath, as_type); + needtype = 0; + break; + case as_token_confed_seq_end: + as_type = AS_SEQUENCE; + needtype = 1; + break; + case as_token_confed_set_start: + as_type = AS_CONFED_SET; + aspath_segment_add(aspath, as_type); + needtype = 0; + break; + case as_token_confed_set_end: + as_type = AS_SEQUENCE; + needtype = 1; + break; + case as_token_unknown: + default: + aspath_free(aspath); + return NULL; + } + } + + aspath_make_str_count(aspath); - return aspath; + return aspath; } /* Make hash value by raw aspath data. */ -unsigned int -aspath_key_make (void *p) +unsigned int aspath_key_make(void *p) { - struct aspath *aspath = (struct aspath *) p; - unsigned int key = 0; + struct aspath *aspath = (struct aspath *)p; + unsigned int key = 0; - if (!aspath->str) - aspath_str_update (aspath); + if (!aspath->str) + aspath_str_update(aspath); - key = jhash (aspath->str, aspath->str_len, 2334325); + key = jhash(aspath->str, aspath->str_len, 2334325); - return key; + return key; } /* If two aspath have same value then return 1 else return 0 */ -int -aspath_cmp (const void *arg1, const void *arg2) -{ - const struct assegment *seg1 = ((const struct aspath *)arg1)->segments; - const struct assegment *seg2 = ((const struct aspath *)arg2)->segments; - - while (seg1 || seg2) - { - int i; - if ((!seg1 && seg2) || (seg1 && !seg2)) - return 0; - if (seg1->type != seg2->type) - return 0; - if (seg1->length != seg2->length) - return 0; - for (i = 0; i < seg1->length; i++) - if (seg1->as[i] != seg2->as[i]) - return 0; - seg1 = seg1->next; - seg2 = seg2->next; - } - return 1; +int aspath_cmp(const void *arg1, const void *arg2) +{ + const struct assegment *seg1 = ((const struct aspath *)arg1)->segments; + const struct assegment *seg2 = ((const struct aspath *)arg2)->segments; + + while (seg1 || seg2) { + int i; + if ((!seg1 && seg2) || (seg1 && !seg2)) + return 0; + if (seg1->type != seg2->type) + return 0; + if (seg1->length != seg2->length) + return 0; + for (i = 0; i < seg1->length; i++) + if (seg1->as[i] != seg2->as[i]) + return 0; + seg1 = seg1->next; + seg2 = seg2->next; + } + return 1; } /* AS path hash initialize. */ -void -aspath_init (void) +void aspath_init(void) { - ashash = hash_create_size (32768, aspath_key_make, aspath_cmp, NULL); + ashash = hash_create_size(32768, aspath_key_make, aspath_cmp, NULL); } -void -aspath_finish (void) +void aspath_finish(void) { - hash_clean (ashash, (void (*)(void *))aspath_free); - hash_free (ashash); - ashash = NULL; - - if (snmp_stream) - stream_free (snmp_stream); + 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) +const char *aspath_print(struct aspath *as) { - return (as ? as->str : NULL); + return (as ? as->str : NULL); } /* Printing functions */ /* Feed the AS_PATH to the vty; the suffix string follows it only in case * AS_PATH wasn't empty. */ -void -aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix) +void aspath_print_vty(struct vty *vty, const char *format, struct aspath *as, + const char *suffix) { - assert (format); - vty_out (vty, format, as->str); - if (as->str_len && strlen (suffix)) - vty_out (vty, "%s", suffix); + assert(format); + vty_out(vty, format, as->str); + if (as->str_len && strlen(suffix)) + vty_out(vty, "%s", suffix); } -static void -aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty) +static void aspath_show_all_iterator(struct hash_backet *backet, + struct vty *vty) { - struct aspath *as; + struct aspath *as; - as = (struct aspath *) backet->data; + as = (struct aspath *)backet->data; - vty_out (vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt); - vty_out (vty, "%s\n", as->str); + vty_out(vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt); + vty_out(vty, "%s\n", as->str); } /* Print all aspath and hash information. This function is used from `show [ip] bgp paths' command. */ -void -aspath_print_all_vty (struct vty *vty) +void aspath_print_all_vty(struct vty *vty) { - hash_iterate (ashash, - (void (*) (struct hash_backet *, void *)) - aspath_show_all_iterator, - vty); + hash_iterate(ashash, (void (*)(struct hash_backet *, + void *))aspath_show_all_iterator, + vty); } |
