summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_aspath.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_aspath.c')
-rw-r--r--bgpd/bgp_aspath.c509
1 files changed, 262 insertions, 247 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index ba4f5b48..dc6ed166 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -34,9 +34,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#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
+#define AS_HEADER_SIZE 2
/* Now FOUR octets are used for AS value. */
#define AS_VALUE_SIZE sizeof (as_t)
@@ -44,7 +44,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define AS16_VALUE_SIZE sizeof (as16_t)
/* Maximum protocol segment length value */
-#define AS_SEGMENT_MAX 255
+#define AS_SEGMENT_MAX 255
+#define AS_SEGMENT_MIN 1
/* The following length and size macros relate specifically to Quagga's
* internal representation of AS-Segments, not per se to the on-wire
@@ -76,7 +77,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
( 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
@@ -90,7 +91,7 @@ static struct hash *ashash;
/* Stream for SNMP. See aspath_snmp_pathseg */
static struct stream *snmp_stream;
-
+
static inline as_t *
assegment_data_new (int num)
{
@@ -112,15 +113,15 @@ 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;
}
@@ -129,12 +130,12 @@ assegment_free (struct assegment *seg)
{
if (!seg)
return;
-
+
if (seg->as)
XFREE (MTYPE_AS_SEG_DATA, seg->as);
memset (seg, 0xfe, sizeof(struct assegment));
XFREE (MTYPE_AS_SEG, seg);
-
+
return;
}
@@ -143,7 +144,7 @@ static void
assegment_free_all (struct assegment *seg)
{
struct assegment *prev;
-
+
while (seg)
{
prev = seg;
@@ -157,10 +158,10 @@ 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;
}
@@ -170,7 +171,7 @@ assegment_dup_all (struct assegment *seg)
{
struct assegment *new = NULL;
struct assegment *head = NULL;
-
+
while (seg)
{
if (head)
@@ -180,7 +181,7 @@ assegment_dup_all (struct assegment *seg)
}
else
head = new = assegment_dup (seg);
-
+
seg = seg->next;
}
return head;
@@ -191,24 +192,24 @@ static struct assegment *
assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
{
as_t *newas;
-
+
if (!num)
return seg;
-
+
if (num >= AS_SEGMENT_MAX)
return seg; /* we don't do huge prepends */
-
+
newas = assegment_data_new (seg->length + num);
-
+
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->as = newas;
seg->length += num;
return seg;
}
@@ -222,7 +223,7 @@ 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));
@@ -243,8 +244,8 @@ int_cmp (const void *p1, const void *p2)
{
const as_t *as1 = p1;
const as_t *as2 = p2;
-
- return (*as1 == *as2)
+
+ return (*as1 == *as2)
? 0 : ( (*as1 > *as2) ? 1 : -1);
}
@@ -259,14 +260,14 @@ 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 ;)
@@ -275,15 +276,15 @@ assegment_normalise (struct assegment *head)
{
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];
@@ -297,28 +298,28 @@ assegment_normalise (struct assegment *head)
* 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)
{
@@ -344,7 +345,7 @@ aspath_unintern (struct aspath **aspath)
{
struct aspath *ret;
struct aspath *asp = *aspath;
-
+
if (asp->refcnt)
asp->refcnt--;
@@ -415,14 +416,14 @@ 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;
@@ -433,14 +434,14 @@ aspath_count_hops (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;
@@ -457,7 +458,7 @@ aspath_size (struct aspath *aspath)
{
int size = 0;
struct assegment *seg = aspath->segments;
-
+
while (seg)
{
size += ASSEGMENT_SIZE(seg->length, 1);
@@ -473,7 +474,7 @@ 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++)
@@ -492,7 +493,7 @@ aspath_has_as4 (struct aspath *aspath)
{
struct assegment *seg = aspath->segments;
unsigned int i;
-
+
while (seg)
{
for (i = 0; i < seg->length; i++)
@@ -519,9 +520,9 @@ aspath_make_str_count (struct aspath *as)
str_buf[0] = '\0';
return str_buf;
}
-
+
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'.
@@ -540,7 +541,7 @@ aspath_make_str_count (struct aspath *as)
{
int i;
char seperator;
-
+
/* Check AS type validity. Set seperator for segment */
switch (seg->type)
{
@@ -556,7 +557,7 @@ aspath_make_str_count (struct aspath *as)
XFREE (MTYPE_AS_STR, str_buf);
return NULL;
}
-
+
/* We might need to increase str_buf, particularly if path has
* differing segments types, our initial guesstimate above will
* have been wrong. Need 10 chars for ASN, a seperator each and
@@ -574,32 +575,32 @@ aspath_make_str_count (struct aspath *as)
}
#undef ASN_STR_LEN
#undef SEGMENT_STR_LEN
-
+
if (seg->type != AS_SEQUENCE)
- len += snprintf (str_buf + len, str_size - len,
- "%c",
+ len += snprintf (str_buf + len, str_size - len,
+ "%c",
aspath_delimiter_char (seg->type, AS_SEG_START));
-
+
/* write out the ASNs, with their seperators, bar the last one*/
for (i = 0; i < seg->length; i++)
{
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);
}
-
+
if (seg->type != AS_SEQUENCE)
- len += snprintf (str_buf + len, str_size - len, "%c",
+ 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';
return str_buf;
@@ -618,7 +619,7 @@ struct aspath *
aspath_intern (struct aspath *aspath)
{
struct aspath *find;
-
+
/* Assert this AS path structure is not interned. */
assert (aspath->refcnt == 0);
@@ -662,7 +663,7 @@ aspath_hash_alloc (void *arg)
/* New aspath structure is needed. */
aspath = aspath_dup (arg);
-
+
/* Malformed AS path value. */
if (! aspath->str)
{
@@ -673,151 +674,162 @@ aspath_hash_alloc (void *arg)
return aspath;
}
-/* parse as-segment byte stream in struct assegment */
-static int
-assegments_parse (struct stream *s, size_t length,
- struct assegment **result, int use32bit)
+/* parse *not-empty* as-segment byte stream in struct assegment
+ *
+ * Requires stream to be positioned immediately after the length field of the
+ * atttribute red-tape, and for the length != 0.
+ *
+ * Returns NULL if the AS_PATH or AS4_PATH is not valid.
+ */
+static struct assegment *
+assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path)
{
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;
-
+
+ assert (length > 0); /* does not expect empty AS_PATH or AS4_PATH */
+
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)
+
+ /* double check that length does not exceed stream */
+ if (STREAM_READABLE(s) < length)
+ return NULL;
+
+ /* deal with each segment in turn */
+ while (length > 0)
{
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)))
+ /* softly softly, get the header first on its own */
+ if (length >= AS_HEADER_SIZE)
{
- if (head)
- assegment_free_all (head);
- return -1;
+ segh.type = stream_getc (s);
+ segh.length = stream_getc (s);
+ confirm((sizeof(segh.length) == 1) && (AS_SEGMENT_MIN == 1)
+ && (AS_SEGMENT_MAX == 255)) ;
+ /* 1..255 is valid */
+
+ seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
+ /* includes the segment type and length red tape */
+
+ if (BGP_DEBUG (as4, AS4_SEGMENT))
+ zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
+ segh.type, segh.length);
+
+ /* Check that the segment type is valid */
+ switch (segh.type)
+ {
+ case AS_SEQUENCE:
+ case AS_SET:
+ break ;
+
+ case AS_CONFED_SEQUENCE:
+ case AS_CONFED_SET:
+ if (!as4_path)
+ break ;
+ /* RFC4893 3: "invalid for the AS4_PATH attribute" */
+ /* fall through */
+
+ default: /* reject unknown or invalid AS_PATH segment types */
+ seg_size = 0 ;
+ } ;
}
-
- switch (segh.type)
+ else
+ seg_size = 0 ;
+
+ /* Stop now if segment is not valid (discarding anything collected to date)
+ *
+ * RFC4271 4.3, Path Attributes, b) AS_PATH:
+ *
+ * "path segment value field contains one or more AS numbers"
+ */
+ if ((seg_size == 0) || (seg_size > length)
+ || (segh.length < AS_SEGMENT_MIN))
{
- case AS_SEQUENCE:
- case AS_SET:
- case AS_CONFED_SEQUENCE:
- case AS_CONFED_SET:
- break;
- default:
- if (head)
- assegment_free_all (head);
- return -1;
- }
-
+ assegment_free_all (head);
+ return NULL;
+ } ;
+
+ length -= seg_size ;
+
/* 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);
-
+ zlog_debug ("[AS4SEG] Parse aspath segment: length left: %lu",
+ (unsigned long) length);
+
prev = seg;
}
-
- *result = assegment_normalise (head);
- return 0;
+
+ return assegment_normalise (head);
}
-/* 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.
-
- On error NULL is returned.
+/* AS path parse function -- parses AS_PATH and AS4_PATH attributes
+ *
+ * Requires: s -- stream, currently positioned before first segment
+ * of AS_PATH or AS4_PATH (ie after attribute header)
+ * length -- length of the value of the AS_PATH or AS4_PATH
+ * use32bit -- true <=> 4Byte ASN, otherwise 2Byte ASN
+ * as4_path -- true <=> AS4_PATH, otherwise AS_PATH
+ *
+ * Returns: if valid: address of struct aspath in the hash of known aspaths,
+ * with reference count incremented.
+ * else: NULL
+ *
+ * NB: empty AS path (length == 0) is valid. The returned struct aspath will
+ * have segments == NULL and str == zero length string (unique).
*/
struct aspath *
-aspath_parse (struct stream *s, size_t length, int use32bit)
+aspath_parse (struct stream *s, size_t length, bool use32bit, bool as4_path)
{
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;
-
+ /* Parse each segment and construct normalised list of struct assegment */
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. */
+ if (length != 0)
+ {
+ as.segments = assegments_parse (s, length, use32bit, as4_path);
+
+ if (as.segments == NULL)
+ return NULL ; /* Invalid AS_PATH or AS4_PATH */
+ } ;
+
+ /* If already same aspath exist then return it. */
find = hash_get (ashash, &as, aspath_hash_alloc);
-
+
+ assert(find) ; /* valid aspath, so must find or create */
+
/* 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;
+
find->refcnt++;
return find;
-}
+} ;
static inline 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]);
@@ -847,10 +859,10 @@ 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)
{
/*
@@ -867,7 +879,7 @@ aspath_put (struct stream *s, struct aspath *as, int use32bit )
int written = 0;
int asns_packed = 0;
size_t lenp;
-
+
/* Overlength segments have to be split up */
while ( (seg->length - written) > AS_SEGMENT_MAX)
{
@@ -876,12 +888,12 @@ aspath_put (struct stream *s, struct aspath *as, int 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,
+ 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.
@@ -896,18 +908,18 @@ aspath_put (struct stream *s, struct aspath *as, int use32bit )
* 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,
+
+ bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
use32bit);
seg = next;
}
@@ -928,18 +940,18 @@ aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
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 *
@@ -971,13 +983,13 @@ aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
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->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
asset->length * AS_VALUE_SIZE);
asset->as[asset->length - 1] = as;
}
-
+
return asset;
}
@@ -1003,7 +1015,7 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)
/* First of all check common leading sequence. */
while (seg1 && seg2)
- {
+ {
/* Check segment type. */
if (seg1->type != seg2->type)
break;
@@ -1018,7 +1030,7 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)
if (match)
{
struct assegment *seg = assegment_new (seg1->type, 0);
-
+
seg = assegment_append_asns (seg, seg1->as, match);
if (! aspath)
@@ -1028,14 +1040,14 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)
}
else
prevseg->next = seg;
-
+
prevseg = seg;
}
- if (match != minlen || match != seg1->length
+ if (match != minlen || match != seg1->length
|| seg1->length != seg2->length)
break;
-
+
seg1 = seg1->next;
seg2 = seg2->next;
}
@@ -1049,7 +1061,7 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)
{
for (i = from; i < seg1->length; i++)
asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
-
+
from = 0;
seg1 = seg1->next;
}
@@ -1063,7 +1075,7 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)
from = 0;
seg2 = seg2->next;
}
-
+
assegment_normalise (aspath->segments);
aspath_str_update (aspath);
return aspath;
@@ -1071,13 +1083,13 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)
/* 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. */
+ 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 ))
@@ -1095,17 +1107,17 @@ aspath_loop_check (struct aspath *aspath, as_t asno)
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;
@@ -1116,16 +1128,16 @@ int
aspath_private_as_check (struct aspath *aspath)
{
struct assegment *seg;
-
+
if ( !(aspath && aspath->segments) )
return 0;
-
+
seg = aspath->segments;
while (seg)
{
int i;
-
+
for (i = 0; i < seg->length; i++)
{
if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
@@ -1183,11 +1195,11 @@ aspath_merge (struct aspath *as1, struct aspath *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);
@@ -1203,10 +1215,10 @@ aspath_prepend (struct aspath *as1, struct aspath *as2)
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)
{
@@ -1214,11 +1226,11 @@ aspath_prepend (struct aspath *as1, struct aspath *as2)
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;
@@ -1233,35 +1245,35 @@ aspath_prepend (struct aspath *as1, struct aspath *as2)
if (seg1->type == AS_SEQUENCE)
{
- /* We have two chains of segments, as1->segments and seg2,
+ /* 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
+ * the inbetween AS_SEQUENCE of seg2 in the process
*/
aspath_str_update (as2);
return as2;
@@ -1272,7 +1284,7 @@ aspath_prepend (struct aspath *as1, struct aspath *as2)
return aspath_merge (as1, as2);
}
/* XXX: Ermmm, what if as1 has multiple segments?? */
-
+
/* Not reached */
}
@@ -1362,7 +1374,7 @@ aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
{
aspath->segments = assegment_new (type, 1);
aspath->segments->as[0] = asno;
-
+
if (assegment)
assegment_free (assegment);
@@ -1371,16 +1383,16 @@ aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
if (assegment->type == type)
aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
- else
+ else
{
/* create new segment
- * push it onto head of aspath's segment chain
+ * push it onto head of aspath's segment chain
*/
struct assegment *newsegment;
-
+
newsegment = assegment_new (type, 1);
newsegment->as[0] = asno;
-
+
newsegment->next = assegment;
aspath->segments = newsegment;
}
@@ -1422,7 +1434,7 @@ aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
if (!(seg1 && seg2
&& (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
return 0;
-
+
if (seg1->as[0] == seg2->as[0])
return 1;
@@ -1441,16 +1453,16 @@ 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))
@@ -1461,10 +1473,10 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
*/
hops = aspath_count_hops (aspath);
}
-
+
if (!hops)
return aspath_dup (as4path);
-
+
if ( BGP_DEBUG(as4, AS4))
zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
aspath->str, as4path->str);
@@ -1497,9 +1509,9 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
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);
@@ -1514,7 +1526,7 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
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.
@@ -1523,11 +1535,11 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *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;
}
@@ -1539,14 +1551,14 @@ aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspat
{
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;
@@ -1564,18 +1576,18 @@ aspath_delete_confed_seq (struct aspath *aspath)
return aspath;
seg = aspath->segments;
-
- /* "if the first path segment of the AS_PATH is
+
+ /* "if the first path segment of the AS_PATH is
* of type AS_CONFED_SEQUENCE,"
*/
if (aspath->segments->type != AS_CONFED_SEQUENCE)
return aspath;
- /* "... that segment and any immediately following segments
- * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
+ /* "... that segment and any immediately following segments
+ * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
* from the AS_PATH attribute,"
*/
- while (seg &&
+ while (seg &&
(seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
{
aspath->segments = seg->next;
@@ -1602,7 +1614,7 @@ aspath_as_add (struct aspath *as, as_t asno)
if (!seg)
return;
-
+
/* Last segment search procedure. */
while (seg->next)
seg = seg->next;
@@ -1627,10 +1639,13 @@ aspath_segment_add (struct aspath *as, int type)
as->segments = new;
}
+/*------------------------------------------------------------------------------
+ * Construct an interned empty AS Path
+ */
struct aspath *
aspath_empty (void)
{
- return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
+ return aspath_parse (NULL, 0, true, false); /* 32Bit ;-) not AS4_PATH */
}
struct aspath *
@@ -1647,9 +1662,9 @@ unsigned long
aspath_count (void)
{
return ashash->count;
-}
-
-/*
+}
+
+/*
Theoretically, one as path can have:
One BGP packet size should be less than 4096.
@@ -1714,15 +1729,15 @@ aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
}
/* Check actual AS value. */
- if (isdigit ((int) *p))
+ if (isdigit ((int) *p))
{
as_t asval;
-
+
*token = as_token_asval;
asval = (*p - '0');
p++;
-
- while (isdigit ((int) *p))
+
+ while (isdigit ((int) *p))
{
asval *= 10;
asval += (*p - '0');
@@ -1731,7 +1746,7 @@ aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
*asno = asval;
return p;
}
-
+
/* There is no match then return unknown token. */
*token = as_token_unknown;
return p++;
@@ -1802,7 +1817,7 @@ aspath_str2aspath (const char *str)
return aspath;
}
-
+
/* Make hash value by raw aspath data. */
unsigned int
aspath_key_make (void *p)
@@ -1812,7 +1827,7 @@ aspath_key_make (void *p)
if (!aspath->str)
aspath_str_update (aspath);
-
+
key = jhash (aspath->str, strlen(aspath->str), 2334325);
return key;
@@ -1824,14 +1839,14 @@ 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;
+ return 0;
if (seg1->length != seg2->length)
return 0;
for (i = 0; i < seg1->length; i++)
@@ -1855,11 +1870,11 @@ aspath_finish (void)
{
hash_free (ashash);
ashash = NULL;
-
+
if (snmp_stream)
stream_free (snmp_stream);
}
-
+
/* return and as path value */
const char *
aspath_print (struct aspath *as)
@@ -1896,7 +1911,7 @@ aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
void
aspath_print_all_vty (struct vty *vty)
{
- hash_iterate (ashash,
+ hash_iterate (ashash,
(void (*) (struct hash_backet *, void *))
aspath_show_all_iterator,
vty);