1 /* AS path management routines.
2 Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
3 Copyright (C) 2005 Sun Microsystems, Inc.
5 This file is part of GNU Zebra.
7 GNU Zebra is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 GNU Zebra is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Zebra; see the file COPYING. If not, write to the Free
19 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
34 #include "bgpd/bgpd.h"
35 #include "bgpd/bgp_aspath.h"
36 #include "bgpd/bgp_debug.h"
37 #include "bgpd/bgp_attr.h"
39 /* Attr. Flags and Attr. Type Code. */
40 #define AS_HEADER_SIZE 2
42 /* Now FOUR octets are used for AS value. */
43 #define AS_VALUE_SIZE sizeof (as_t)
44 /* This is the old one */
45 #define AS16_VALUE_SIZE sizeof (as16_t)
47 /* Maximum protocol segment length value */
48 #define AS_SEGMENT_MAX 255
50 /* The following length and size macros relate specifically to Quagga's
51 * internal representation of AS-Segments, not per se to the on-wire
52 * sizes and lengths. At present (200508) they sort of match, however
53 * the ONLY functions which should now about the on-wire syntax are
54 * aspath_put, assegment_put and assegment_parse.
56 * aspath_put returns bytes written, the only definitive record of
57 * size of wire-format attribute..
60 /* Calculated size in bytes of ASN segment data to hold N ASN's */
61 #define ASSEGMENT_DATA_SIZE(N,S) \
62 ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )
64 /* Calculated size of segment struct to hold N ASN's */
65 #define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
67 /* AS segment octet length. */
68 #define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
70 /* AS_SEQUENCE segments can be packed together */
71 /* Can the types of X and Y be considered for packing? */
72 #define ASSEGMENT_TYPES_PACKABLE(X,Y) \
73 ( ((X)->type == (Y)->type) \
74 && ((X)->type == AS_SEQUENCE))
75 /* Types and length of X,Y suitable for packing? */
76 #define ASSEGMENTS_PACKABLE(X,Y) \
77 ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \
78 && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) )
80 /* As segment header - the on-wire representation
81 * NOT the internal representation!
83 struct assegment_header
89 /* Hash for aspath. This is the top level structure of AS path. */
90 static struct hash *ashash;
92 /* Stream for SNMP. See aspath_snmp_pathseg */
93 static struct stream *snmp_stream;
95 /* Callers are required to initialize the memory */
97 assegment_data_new (int num)
99 return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
103 assegment_data_free (as_t *asdata)
105 XFREE (MTYPE_AS_SEG_DATA, asdata);
108 /* Get a new segment. Note that 0 is an allowed length,
109 * and will result in a segment with no allocated data segment.
110 * the caller should immediately assign data to the segment, as the segment
111 * otherwise is not generally valid
113 static struct assegment *
114 assegment_new (u_char type, u_short length)
116 struct assegment *new;
118 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
121 new->as = assegment_data_new (length);
123 new->length = length;
130 assegment_free (struct assegment *seg)
136 assegment_data_free (seg->as);
137 memset (seg, 0xfe, sizeof(struct assegment));
138 XFREE (MTYPE_AS_SEG, seg);
143 /* free entire chain of segments */
145 assegment_free_all (struct assegment *seg)
147 struct assegment *prev;
153 assegment_free (prev);
157 /* Duplicate just the given assegment and its data */
158 static struct assegment *
159 assegment_dup (struct assegment *seg)
161 struct assegment *new;
163 new = assegment_new (seg->type, seg->length);
164 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );
169 /* Duplicate entire chain of assegments, return the head */
170 static struct assegment *
171 assegment_dup_all (struct assegment *seg)
173 struct assegment *new = NULL;
174 struct assegment *head = NULL;
180 new->next = assegment_dup (seg);
184 head = new = assegment_dup (seg);
191 /* prepend the as number to given segment, given num of times */
192 static struct assegment *
193 assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
201 if (num >= AS_SEGMENT_MAX)
202 return seg; /* we don't do huge prepends */
204 if ((newas = assegment_data_new (seg->length + num)) == NULL)
207 for (i = 0; i < num; i++)
210 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
211 assegment_data_free (seg->as);
218 /* append given array of as numbers to the segment */
219 static struct assegment *
220 assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
224 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
225 ASSEGMENT_DATA_SIZE (seg->length + num, 1));
230 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));
235 assegment_free_all (seg);
240 int_cmp (const void *p1, const void *p2)
242 const as_t *as1 = p1;
243 const as_t *as2 = p2;
245 return (*as1 == *as2)
246 ? 0 : ( (*as1 > *as2) ? 1 : -1);
249 /* normalise the segment.
250 * In particular, merge runs of AS_SEQUENCEs into one segment
251 * Internally, we do not care about the wire segment length limit, and
252 * we want each distinct AS_PATHs to have the exact same internal
253 * representation - eg, so that our hashing actually works..
255 static struct assegment *
256 assegment_normalise (struct assegment *head)
258 struct assegment *seg = head, *pin;
259 struct assegment *tmp;
268 /* Sort values SET segments, for determinism in paths to aid
269 * creation of hash values / path comparisons
270 * and because it helps other lesser implementations ;)
272 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
277 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
280 for (i=1; i < seg->length; i++)
282 if (seg->as[tail] == seg->as[i])
287 seg->as[tail] = seg->as[i];
289 /* seg->length can be 0.. */
291 seg->length = tail + 1;
294 /* read ahead from the current, pinned segment while the segments
295 * are packable/mergeable. Append all following packable segments
296 * to the segment we have pinned and remove these appended
299 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
304 /* append the next sequence to the pinned sequence */
305 pin = assegment_append_asns (pin, seg->as, seg->length);
307 /* bypass the next sequence */
308 pin->next = seg->next;
310 /* get rid of the now referenceless segment */
311 assegment_free (tmp);
320 static struct aspath *
323 return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
326 /* Free AS path structure. */
328 aspath_free (struct aspath *aspath)
332 if (aspath->segments)
333 assegment_free_all (aspath->segments);
335 XFREE (MTYPE_AS_STR, aspath->str);
336 XFREE (MTYPE_AS_PATH, aspath);
339 /* Unintern aspath from AS path bucket. */
341 aspath_unintern (struct aspath **aspath)
344 struct aspath *asp = *aspath;
349 if (asp->refcnt == 0)
351 /* This aspath must exist in aspath hash table. */
352 ret = hash_release (ashash, asp);
353 assert (ret != NULL);
359 /* Return the start or end delimiters for a particular Segment type */
360 #define AS_SEG_START 0
363 aspath_delimiter_char (u_char type, u_char which)
371 } aspath_delim_char [] =
373 { AS_SET, '{', '}' },
374 { AS_CONFED_SET, '[', ']' },
375 { AS_CONFED_SEQUENCE, '(', ')' },
379 for (i = 0; aspath_delim_char[i].type != 0; i++)
381 if (aspath_delim_char[i].type == type)
383 if (which == AS_SEG_START)
384 return aspath_delim_char[i].start;
385 else if (which == AS_SEG_END)
386 return aspath_delim_char[i].end;
392 /* countup asns from this segment and index onward */
394 assegment_count_asns (struct assegment *seg, int from)
400 count += seg->length;
403 count += (seg->length - from);
412 aspath_count_confeds (struct aspath *aspath)
415 struct assegment *seg = aspath->segments;
419 if (seg->type == AS_CONFED_SEQUENCE)
420 count += seg->length;
421 else if (seg->type == AS_CONFED_SET)
430 aspath_count_hops (const struct aspath *aspath)
433 struct assegment *seg = aspath->segments;
437 if (seg->type == AS_SEQUENCE)
438 count += seg->length;
439 else if (seg->type == AS_SET)
447 /* Estimate size aspath /might/ take if encoded into an
450 * This is a quick estimate, not definitive! aspath_put()
451 * may return a different number!!
454 aspath_size (struct aspath *aspath)
457 struct assegment *seg = aspath->segments;
461 size += ASSEGMENT_SIZE(seg->length, 1);
467 /* Return highest public ASN in path */
469 aspath_highest (struct aspath *aspath)
471 struct assegment *seg = aspath->segments;
477 for (i = 0; i < seg->length; i++)
478 if (seg->as[i] > highest
479 && !BGP_AS_IS_PRIVATE(seg->as[i]))
480 highest = seg->as[i];
486 /* Return the left-most ASN in path */
488 aspath_leftmost (struct aspath *aspath)
490 struct assegment *seg = aspath->segments;
493 if (seg && seg->length && seg->type == AS_SEQUENCE)
494 leftmost = seg->as[0];
499 /* Return 1 if there are any 4-byte ASes in the path */
501 aspath_has_as4 (struct aspath *aspath)
503 struct assegment *seg = aspath->segments;
508 for (i = 0; i < seg->length; i++)
509 if (seg->as[i] > BGP_AS_MAX)
516 /* Convert aspath structure to string expression. */
518 aspath_make_str_count (struct aspath *as)
520 struct assegment *seg;
528 as->str = XMALLOC (MTYPE_AS_STR, 1);
536 /* ASN takes 5 to 10 chars plus seperator, see below.
537 * If there is one differing segment type, we need an additional
538 * 2 chars for segment delimiters, and the final '\0'.
539 * Hopefully this is large enough to avoid hitting the realloc
540 * code below for most common sequences.
542 * This was changed to 10 after the well-known BGP assertion, which
543 * had hit some parts of the Internet in May of 2009.
545 #define ASN_STR_LEN (10 + 1)
546 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
547 ASPATH_STR_DEFAULT_LEN);
548 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
555 /* Check AS type validity. Set seperator for segment */
563 case AS_CONFED_SEQUENCE:
567 XFREE (MTYPE_AS_STR, str_buf);
573 /* We might need to increase str_buf, particularly if path has
574 * differing segments types, our initial guesstimate above will
575 * have been wrong. Need 10 chars for ASN, a seperator each and
576 * potentially two segment delimiters, plus a space between each
577 * segment and trailing zero.
579 * This definitely didn't work with the value of 5 bytes and
582 #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
583 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
585 str_size = len + SEGMENT_STR_LEN(seg);
586 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
589 #undef SEGMENT_STR_LEN
591 if (seg->type != AS_SEQUENCE)
592 len += snprintf (str_buf + len, str_size - len,
594 aspath_delimiter_char (seg->type, AS_SEG_START));
596 /* write out the ASNs, with their seperators, bar the last one*/
597 for (i = 0; i < seg->length; i++)
599 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
601 if (i < (seg->length - 1))
602 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
605 if (seg->type != AS_SEQUENCE)
606 len += snprintf (str_buf + len, str_size - len, "%c",
607 aspath_delimiter_char (seg->type, AS_SEG_END));
609 len += snprintf (str_buf + len, str_size - len, " ");
614 assert (len < str_size);
624 aspath_str_update (struct aspath *as)
627 XFREE (MTYPE_AS_STR, as->str);
628 aspath_make_str_count (as);
631 /* Intern allocated AS path. */
633 aspath_intern (struct aspath *aspath)
637 /* Assert this AS path structure is not interned and has the string
638 representation built. */
639 assert (aspath->refcnt == 0);
640 assert (aspath->str);
642 /* Check AS path hash. */
643 find = hash_get (ashash, aspath, hash_alloc_intern);
645 aspath_free (aspath);
652 /* Duplicate aspath structure. Created same aspath structure but
653 reference count and AS path string is cleared. */
655 aspath_dup (struct aspath *aspath)
657 unsigned short buflen = aspath->str_len + 1;
660 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
662 if (aspath->segments)
663 new->segments = assegment_dup_all (aspath->segments);
668 new->str = XMALLOC (MTYPE_AS_STR, buflen);
669 new->str_len = aspath->str_len;
671 /* copy the string data */
672 if (aspath->str_len > 0)
673 memcpy (new->str, aspath->str, buflen);
681 aspath_hash_alloc (void *arg)
683 const struct aspath *aspath = arg;
686 /* Malformed AS path value. */
687 assert (aspath->str);
691 /* New aspath structure is needed. */
692 new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
694 /* Reuse segments and string representation */
696 new->segments = aspath->segments;
697 new->str = aspath->str;
698 new->str_len = aspath->str_len;
703 /* parse as-segment byte stream in struct assegment */
705 assegments_parse (struct stream *s, size_t length,
706 struct assegment **result, int use32bit)
708 struct assegment_header segh;
709 struct assegment *seg, *prev = NULL, *head = NULL;
712 /* empty aspath (ie iBGP or somesuch) */
716 if (BGP_DEBUG (as4, AS4_SEGMENT))
717 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
718 (unsigned long) length);
720 if ((STREAM_READABLE(s) < length)
721 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
722 || (length % AS16_VALUE_SIZE ))
725 while (bytes < length)
730 if ((length - bytes) <= AS_HEADER_SIZE)
733 assegment_free_all (head);
737 /* softly softly, get the header first on its own */
738 segh.type = stream_getc (s);
739 segh.length = stream_getc (s);
741 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
743 if (BGP_DEBUG (as4, AS4_SEGMENT))
744 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
745 segh.type, segh.length);
748 if ( ((bytes + seg_size) > length)
749 /* 1771bis 4.3b: seg length contains one or more */
750 || (segh.length == 0)
751 /* Paranoia in case someone changes type of segment length.
752 * Shift both values by 0x10 to make the comparison operate
753 * on more, than 8 bits (otherwise it's a warning, bug #564).
755 || ((sizeof segh.length > 1)
756 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
759 assegment_free_all (head);
767 case AS_CONFED_SEQUENCE:
772 assegment_free_all (head);
776 /* now its safe to trust lengths */
777 seg = assegment_new (segh.type, segh.length);
781 else /* it's the first segment */
784 for (i = 0; i < segh.length; i++)
785 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
789 if (BGP_DEBUG (as4, AS4_SEGMENT))
790 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
791 (unsigned long) bytes);
796 *result = assegment_normalise (head);
800 /* AS path parse function. pnt is a pointer to byte stream and length
801 is length of byte stream. If there is same AS path in the the AS
802 path hash then return it else make new AS path structure.
804 On error NULL is returned.
807 aspath_parse (struct stream *s, size_t length, int use32bit)
812 /* If length is odd it's malformed AS path. */
813 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
814 * otherwise its malformed when length is larger than 2 and (length-2)
815 * is not dividable by 4.
816 * But... this time we're lazy
818 if (length % AS16_VALUE_SIZE )
821 memset (&as, 0, sizeof (struct aspath));
822 if (assegments_parse (s, length, &as.segments, use32bit) < 0)
825 /* If already same aspath exist then return it. */
826 find = hash_get (ashash, &as, aspath_hash_alloc);
828 /* bug! should not happen, let the daemon crash below */
831 /* if the aspath was already hashed free temporary memory. */
834 assegment_free_all (as.segments);
835 /* aspath_key_make() always updates the string */
836 XFREE (MTYPE_AS_STR, as.str);
845 assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
848 assert (num <= AS_SEGMENT_MAX);
850 for (i = 0; i < num; i++)
852 stream_putl (s, as[i]);
855 if ( as[i] <= BGP_AS_MAX )
856 stream_putw(s, as[i]);
858 stream_putw(s, BGP_AS_TRANS);
863 assegment_header_put (struct stream *s, u_char type, int length)
866 assert (length <= AS_SEGMENT_MAX);
867 stream_putc (s, type);
868 lenp = stream_get_endp (s);
869 stream_putc (s, length);
873 /* write aspath data to stream */
875 aspath_put (struct stream *s, struct aspath *as, int use32bit )
877 struct assegment *seg = as->segments;
880 if (!seg || seg->length == 0)
886 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
887 * At the moment, we would write out a partial aspath, and our peer
888 * will complain and drop the session :-/
890 * The general assumption here is that many things tested will
891 * never happen. And, in real live, up to now, they have not.
893 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
895 struct assegment *next = seg->next;
900 /* Overlength segments have to be split up */
901 while ( (seg->length - written) > AS_SEGMENT_MAX)
903 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
904 assegment_data_put (s, (seg->as+written), AS_SEGMENT_MAX, use32bit);
905 written += AS_SEGMENT_MAX;
906 bytes += ASSEGMENT_SIZE (AS_SEGMENT_MAX, use32bit);
909 /* write the final segment, probably is also the first */
910 lenp = assegment_header_put (s, seg->type, seg->length - written);
911 assegment_data_put (s, (seg->as + written), seg->length - written,
914 /* Sequence-type segments can be 'packed' together
915 * Case of a segment which was overlength and split up
916 * will be missed here, but that doesn't matter.
918 while (next && ASSEGMENTS_PACKABLE (seg, next))
920 /* NB: We should never normally get here given we
921 * normalise aspath data when parse them. However, better
922 * safe than sorry. We potentially could call
923 * assegment_normalise here instead, but it's cheaper and
924 * easier to do it on the fly here rather than go through
925 * the segment list twice every time we write out
929 /* Next segment's data can fit in this one */
930 assegment_data_put (s, next->as, next->length, use32bit);
932 /* update the length of the segment header */
933 stream_putc_at (s, lenp, seg->length - written + next->length);
934 asns_packed += next->length;
939 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
947 /* This is for SNMP BGP4PATHATTRASPATHSEGMENT
948 * We have no way to manage the storage, so we use a static stream
949 * wrapper around aspath_put.
952 aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
954 #define SNMP_PATHSEG_MAX 1024
957 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
959 stream_reset (snmp_stream);
966 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
968 *varlen = stream_get_endp (snmp_stream);
969 return stream_pnt(snmp_stream);
972 #define min(A,B) ((A) < (B) ? (A) : (B))
974 static struct assegment *
975 aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
980 /* If this is first AS set member, create new as-set segment. */
983 asset = assegment_new (AS_SET, 1);
984 if (! aspath->segments)
985 aspath->segments = asset;
988 struct assegment *seg = aspath->segments;
993 asset->type = AS_SET;
999 /* Check this AS value already exists or not. */
1000 for (i = 0; i < asset->length; i++)
1001 if (asset->as[i] == as)
1005 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
1006 asset->length * AS_VALUE_SIZE);
1007 asset->as[asset->length - 1] = as;
1014 /* Modify as1 using as2 for aggregation. */
1016 aspath_aggregate (struct aspath *as1, struct aspath *as2)
1022 struct assegment *seg1 = as1->segments;
1023 struct assegment *seg2 = as2->segments;
1024 struct aspath *aspath = NULL;
1025 struct assegment *asset;
1026 struct assegment *prevseg = NULL;
1033 /* First of all check common leading sequence. */
1034 while (seg1 && seg2)
1036 /* Check segment type. */
1037 if (seg1->type != seg2->type)
1040 /* Minimum segment length. */
1041 minlen = min (seg1->length, seg2->length);
1043 for (match = 0; match < minlen; match++)
1044 if (seg1->as[match] != seg2->as[match])
1049 struct assegment *seg = assegment_new (seg1->type, 0);
1051 seg = assegment_append_asns (seg, seg1->as, match);
1055 aspath = aspath_new ();
1056 aspath->segments = seg;
1059 prevseg->next = seg;
1064 if (match != minlen || match != seg1->length
1065 || seg1->length != seg2->length)
1067 /* We are moving on to the next segment to reset match */
1076 aspath = aspath_new();
1078 /* Make as-set using rest of all information. */
1082 for (i = from; i < seg1->length; i++)
1083 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1092 for (i = from; i < seg2->length; i++)
1093 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
1099 assegment_normalise (aspath->segments);
1100 aspath_str_update (aspath);
1104 /* Modify as1 using as2 for aggregation for multipath, keeping the
1105 * AS-Path length the same, and so minimising change to the preference
1106 * of the mpath aggregrate route.
1109 aspath_aggregate_mpath (struct aspath *as1, struct aspath *as2)
1115 struct assegment *seg1 = as1->segments;
1116 struct assegment *seg2 = as2->segments;
1117 struct aspath *aspath = NULL;
1118 struct assegment *asset;
1119 struct assegment *prevseg = NULL;
1126 /* First of all check common leading sequence. */
1127 while (seg1 && seg2)
1129 /* Check segment type. */
1130 if (seg1->type != seg2->type)
1133 /* Minimum segment length. */
1134 minlen = min (seg1->length, seg2->length);
1136 for (match = 0; match < minlen; match++)
1137 if (seg1->as[match] != seg2->as[match])
1142 struct assegment *seg = assegment_new (seg1->type, 0);
1144 seg = assegment_append_asns (seg, seg1->as, match);
1148 aspath = aspath_new ();
1149 aspath->segments = seg;
1152 prevseg->next = seg;
1157 if (match != minlen || match != seg1->length
1158 || seg1->length != seg2->length)
1166 aspath = aspath_new();
1168 /* Make as-set using rest of all information. */
1169 from1 = from2 = match;
1170 while (seg1 || seg2)
1174 if (seg1->type == AS_SEQUENCE)
1176 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[from1]);
1178 if (from1 >= seg1->length)
1186 for (i = from1; i < seg1->length; i++)
1187 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1196 if (seg2->type == AS_SEQUENCE)
1198 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[from2]);
1200 if (from2 >= seg2->length)
1208 for (i = from2; i < seg2->length; i++)
1209 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
1216 if (asset->length == 1)
1217 asset->type = AS_SEQUENCE;
1221 assegment_normalise (aspath->segments);
1222 aspath_str_update (aspath);
1226 /* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1227 attribute, check the leftmost AS number in the AS_PATH attribute is
1228 or not the peer's AS number. */
1230 aspath_firstas_check (struct aspath *aspath, as_t asno)
1232 if ( (aspath == NULL) || (aspath->segments == NULL) )
1235 if (aspath->segments
1236 && (aspath->segments->type == AS_SEQUENCE)
1237 && (aspath->segments->as[0] == asno ))
1243 /* AS path loop check. If aspath contains asno then return >= 1. */
1245 aspath_loop_check (struct aspath *aspath, as_t asno)
1247 struct assegment *seg;
1250 if ( (aspath == NULL) || (aspath->segments == NULL) )
1253 seg = aspath->segments;
1259 for (i = 0; i < seg->length; i++)
1260 if (seg->as[i] == asno)
1268 /* When all of AS path is private AS return 1. */
1270 aspath_private_as_check (struct aspath *aspath)
1272 struct assegment *seg;
1274 if ( !(aspath && aspath->segments) )
1277 seg = aspath->segments;
1283 for (i = 0; i < seg->length; i++)
1285 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1293 /* AS path confed check. If aspath contains confed set or sequence then return 1. */
1295 aspath_confed_check (struct aspath *aspath)
1297 struct assegment *seg;
1299 if ( !(aspath && aspath->segments) )
1302 seg = aspath->segments;
1306 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1313 /* Leftmost AS path segment confed check. If leftmost AS segment is of type
1314 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1316 aspath_left_confed_check (struct aspath *aspath)
1319 if ( !(aspath && aspath->segments) )
1322 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1323 || (aspath->segments->type == AS_CONFED_SET) )
1329 /* Merge as1 to as2. as2 should be uninterned aspath. */
1330 static struct aspath *
1331 aspath_merge (struct aspath *as1, struct aspath *as2)
1333 struct assegment *last, *new;
1338 last = new = assegment_dup_all (as1->segments);
1340 /* find the last valid segment */
1341 while (last && last->next)
1344 last->next = as2->segments;
1345 as2->segments = new;
1346 aspath_str_update (as2);
1350 /* Prepend as1 to as2. as2 should be uninterned aspath. */
1352 aspath_prepend (struct aspath *as1, struct aspath *as2)
1354 struct assegment *seg1;
1355 struct assegment *seg2;
1360 seg1 = as1->segments;
1361 seg2 = as2->segments;
1363 /* If as2 is empty, only need to dupe as1's chain onto as2 */
1366 as2->segments = assegment_dup_all (as1->segments);
1367 aspath_str_update (as2);
1371 /* If as1 is empty AS, no prepending to do. */
1375 /* find the tail as1's segment chain. */
1376 while (seg1 && seg1->next)
1379 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1380 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1381 as2 = aspath_delete_confed_seq (as2);
1383 /* as2 may have been updated */
1384 seg2 = as2->segments;
1386 /* as2 may be empty now due to aspath_delete_confed_seq, recheck */
1389 as2->segments = assegment_dup_all (as1->segments);
1390 aspath_str_update (as2);
1394 /* Compare last segment type of as1 and first segment type of as2. */
1395 if (seg1->type != seg2->type)
1396 return aspath_merge (as1, as2);
1398 if (seg1->type == AS_SEQUENCE)
1400 /* We have two chains of segments, as1->segments and seg2,
1401 * and we have to attach them together, merging the attaching
1402 * segments together into one.
1404 * 1. dupe as1->segments onto head of as2
1405 * 2. merge seg2's asns onto last segment of this new chain
1406 * 3. attach chain after seg2
1409 /* dupe as1 onto as2's head */
1410 seg1 = as2->segments = assegment_dup_all (as1->segments);
1412 /* refind the tail of as2, reusing seg1 */
1413 while (seg1 && seg1->next)
1416 /* merge the old head, seg2, into tail, seg1 */
1417 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1419 /* bypass the merged seg2, and attach any chain after it to
1420 * chain descending from as2's head
1422 seg1->next = seg2->next;
1424 /* seg2 is now referenceless and useless*/
1425 assegment_free (seg2);
1427 /* we've now prepended as1's segment chain to as2, merging
1428 * the inbetween AS_SEQUENCE of seg2 in the process
1430 aspath_str_update (as2);
1435 /* AS_SET merge code is needed at here. */
1436 return aspath_merge (as1, as2);
1438 /* XXX: Ermmm, what if as1 has multiple segments?? */
1443 /* Iterate over AS_PATH segments and wipe all occurences of the
1444 * listed AS numbers. Hence some segments may lose some or even
1445 * all data on the way, the operation is implemented as a smarter
1446 * version of aspath_dup(), which allocates memory to hold the new
1447 * data, not the original. The new AS path is returned.
1450 aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1452 struct assegment * srcseg, * exclseg, * lastseg;
1453 struct aspath * newpath;
1455 newpath = aspath_new();
1458 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1460 unsigned i, y, newlen = 0, done = 0, skip_as;
1461 struct assegment * newseg;
1463 /* Find out, how much ASns are we going to pick from this segment.
1464 * We can't perform filtering right inline, because the size of
1465 * the new segment isn't known at the moment yet.
1467 for (i = 0; i < srcseg->length; i++)
1470 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1471 for (y = 0; y < exclseg->length; y++)
1472 if (srcseg->as[i] == exclseg->as[y])
1475 // There's no sense in testing the rest of exclusion list, bail out.
1481 /* newlen is now the number of ASns to copy */
1485 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1486 newseg = assegment_new (srcseg->type, newlen);
1487 for (i = 0; i < srcseg->length; i++)
1490 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1491 for (y = 0; y < exclseg->length; y++)
1492 if (srcseg->as[i] == exclseg->as[y])
1499 newseg->as[done++] = srcseg->as[i];
1501 /* At his point newlen must be equal to done, and both must be positive. Append
1502 * the filtered segment to the gross result. */
1504 newpath->segments = newseg;
1506 lastseg->next = newseg;
1509 aspath_str_update (newpath);
1510 /* We are happy returning even an empty AS_PATH, because the administrator
1511 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1512 * by having a match rule against certain AS_PATH regexps in the route-map index.
1514 aspath_free (source);
1518 /* Add specified AS to the leftmost of aspath. */
1519 static struct aspath *
1520 aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num)
1522 struct assegment *assegment = aspath->segments;
1525 if (assegment && assegment->type == type)
1527 /* extend existing segment */
1528 aspath->segments = assegment_prepend_asns (aspath->segments, asno, num);
1532 /* prepend with new segment */
1533 struct assegment *newsegment = assegment_new (type, num);
1534 for (i = 0; i < num; i++)
1535 newsegment->as[i] = asno;
1537 /* insert potentially replacing empty segment */
1538 if (assegment && assegment->length == 0)
1540 newsegment->next = assegment->next;
1541 assegment_free (assegment);
1544 newsegment->next = assegment;
1545 aspath->segments = newsegment;
1548 aspath_str_update (aspath);
1552 /* Add specified AS to the leftmost of aspath num times. */
1554 aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num)
1556 return aspath_add_asns (aspath, asno, AS_SEQUENCE, num);
1559 /* Add specified AS to the leftmost of aspath. */
1561 aspath_add_seq (struct aspath *aspath, as_t asno)
1563 return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1);
1566 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1567 as2's leftmost AS is same return 1. */
1569 aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
1571 const struct assegment *seg1;
1572 const struct assegment *seg2;
1574 if (!(aspath1 && aspath2))
1577 seg1 = aspath1->segments;
1578 seg2 = aspath2->segments;
1580 /* If both paths are originated in this AS then we do want to compare MED */
1584 /* find first non-confed segments for each */
1585 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1586 || (seg1->type == AS_CONFED_SET)))
1589 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1590 || (seg2->type == AS_CONFED_SET)))
1595 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
1598 if (seg1->as[0] == seg2->as[0])
1604 /* Truncate an aspath after a number of hops, and put the hops remaining
1605 * at the front of another aspath. Needed for AS4 compat.
1607 * Returned aspath is a /new/ aspath, which should either by free'd or
1608 * interned by the caller, as desired.
1611 aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1613 struct assegment *seg, *newseg, *prevseg = NULL;
1614 struct aspath *newpath = NULL, *mergedpath;
1615 int hops, cpasns = 0;
1620 seg = aspath->segments;
1622 /* CONFEDs should get reconciled too.. */
1623 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1624 - aspath_count_hops (as4path);
1628 if (BGP_DEBUG (as4, AS4))
1629 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1630 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1631 * which is daft behaviour - it contains vital loop-detection
1632 * information which must have been removed from AS_PATH.
1634 hops = aspath_count_hops (aspath);
1638 return aspath_dup (as4path);
1640 if ( BGP_DEBUG(as4, AS4))
1641 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1642 aspath->str, as4path->str);
1644 while (seg && hops > 0)
1651 cpasns = seg->length;
1653 case AS_CONFED_SEQUENCE:
1654 /* Should never split a confed-sequence, if hop-count
1655 * suggests we must then something's gone wrong somewhere.
1657 * Most important goal is to preserve AS_PATHs prime function
1658 * as loop-detector, so we fudge the numbers so that the entire
1659 * confed-sequence is merged in.
1661 if (hops < seg->length)
1663 if (BGP_DEBUG (as4, AS4))
1664 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1665 " across 2/4 ASN boundary somewhere, broken..");
1669 cpasns = MIN(seg->length, hops);
1670 hops -= seg->length;
1673 assert (cpasns <= seg->length);
1675 newseg = assegment_new (seg->type, 0);
1676 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1680 newpath = aspath_new ();
1681 newpath->segments = newseg;
1684 prevseg->next = newseg;
1690 /* We may be able to join some segments here, and we must
1691 * do this because... we want normalised aspaths in out hash
1692 * and we do not want to stumble in aspath_put.
1694 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1695 aspath_free (newpath);
1696 mergedpath->segments = assegment_normalise (mergedpath->segments);
1697 aspath_str_update (mergedpath);
1699 if ( BGP_DEBUG(as4, AS4))
1700 zlog_debug ("[AS4] result of synthesizing is %s",
1706 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1707 as2's leftmost AS is same return 1. (confederation as-path
1710 aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
1712 if (! (aspath1 && aspath2) )
1715 if ( !(aspath1->segments && aspath2->segments) )
1718 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1719 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
1722 if (aspath1->segments->as[0] == aspath2->segments->as[0])
1728 /* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1729 * See RFC3065, 6.1 c1 */
1731 aspath_delete_confed_seq (struct aspath *aspath)
1733 struct assegment *seg;
1735 if (!(aspath && aspath->segments))
1738 seg = aspath->segments;
1740 /* "if the first path segment of the AS_PATH is
1741 * of type AS_CONFED_SEQUENCE,"
1743 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1746 /* "... that segment and any immediately following segments
1747 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1748 * from the AS_PATH attribute,"
1751 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
1753 aspath->segments = seg->next;
1754 assegment_free (seg);
1755 seg = aspath->segments;
1757 aspath_str_update (aspath);
1761 /* Add new AS number to the leftmost part of the aspath as
1762 AS_CONFED_SEQUENCE. */
1764 aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1766 return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1);
1769 /* Add new as value to as path structure. */
1771 aspath_as_add (struct aspath *as, as_t asno)
1773 struct assegment *seg = as->segments;
1778 /* Last segment search procedure. */
1782 assegment_append_asns (seg, &asno, 1);
1785 /* Add new as segment to the as path. */
1787 aspath_segment_add (struct aspath *as, int type)
1789 struct assegment *seg = as->segments;
1790 struct assegment *new = assegment_new (type, 0);
1805 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
1809 aspath_empty_get (void)
1811 struct aspath *aspath;
1813 aspath = aspath_new ();
1814 aspath_make_str_count (aspath);
1821 return ashash->count;
1825 Theoretically, one as path can have:
1827 One BGP packet size should be less than 4096.
1828 One BGP attribute size should be less than 4096 - BGP header size.
1829 One BGP aspath size should be less than 4096 - BGP header size -
1830 BGP mandantry attribute size.
1833 /* AS path string lexical token enum. */
1839 as_token_confed_seq_start,
1840 as_token_confed_seq_end,
1841 as_token_confed_set_start,
1842 as_token_confed_set_end,
1846 /* Return next token and point for string parse. */
1848 aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
1850 const char *p = buf;
1852 /* Skip seperators (space for sequences, ',' for sets). */
1853 while (isspace ((int) *p) || *p == ',')
1856 /* Check the end of the string and type specify characters
1863 *token = as_token_set_start;
1867 *token = as_token_set_end;
1871 *token = as_token_confed_seq_start;
1875 *token = as_token_confed_seq_end;
1879 *token = as_token_confed_set_start;
1883 *token = as_token_confed_set_end;
1888 /* Check actual AS value. */
1889 if (isdigit ((int) *p))
1893 *token = as_token_asval;
1897 while (isdigit ((int) *p))
1900 asval += (*p - '0');
1907 /* There is no match then return unknown token. */
1908 *token = as_token_unknown;
1913 aspath_str2aspath (const char *str)
1915 enum as_token token = as_token_unknown;
1918 struct aspath *aspath;
1921 aspath = aspath_new ();
1923 /* We start default type as AS_SEQUENCE. */
1924 as_type = AS_SEQUENCE;
1927 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1931 case as_token_asval:
1934 aspath_segment_add (aspath, as_type);
1937 aspath_as_add (aspath, asno);
1939 case as_token_set_start:
1941 aspath_segment_add (aspath, as_type);
1944 case as_token_set_end:
1945 as_type = AS_SEQUENCE;
1948 case as_token_confed_seq_start:
1949 as_type = AS_CONFED_SEQUENCE;
1950 aspath_segment_add (aspath, as_type);
1953 case as_token_confed_seq_end:
1954 as_type = AS_SEQUENCE;
1957 case as_token_confed_set_start:
1958 as_type = AS_CONFED_SET;
1959 aspath_segment_add (aspath, as_type);
1962 case as_token_confed_set_end:
1963 as_type = AS_SEQUENCE;
1966 case as_token_unknown:
1968 aspath_free (aspath);
1973 aspath_make_str_count (aspath);
1978 /* Make hash value by raw aspath data. */
1980 aspath_key_make (void *p)
1982 struct aspath *aspath = (struct aspath *) p;
1983 unsigned int key = 0;
1986 aspath_str_update (aspath);
1988 key = jhash (aspath->str, aspath->str_len, 2334325);
1993 /* If two aspath have same value then return 1 else return 0 */
1995 aspath_cmp (const void *arg1, const void *arg2)
1997 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1998 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
2000 while (seg1 || seg2)
2003 if ((!seg1 && seg2) || (seg1 && !seg2))
2005 if (seg1->type != seg2->type)
2007 if (seg1->length != seg2->length)
2009 for (i = 0; i < seg1->length; i++)
2010 if (seg1->as[i] != seg2->as[i])
2018 /* AS path hash initialize. */
2022 ashash = hash_create_size (32768, aspath_key_make, aspath_cmp);
2026 aspath_finish (void)
2028 hash_clean (ashash, (void (*)(void *))aspath_free);
2033 stream_free (snmp_stream);
2036 /* return and as path value */
2038 aspath_print (struct aspath *as)
2040 return (as ? as->str : NULL);
2043 /* Printing functions */
2044 /* Feed the AS_PATH to the vty; the suffix string follows it only in case
2045 * AS_PATH wasn't empty.
2048 aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
2051 vty_out (vty, format, as->str);
2052 if (as->str_len && strlen (suffix))
2053 vty_out (vty, "%s", suffix);
2057 aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
2061 as = (struct aspath *) backet->data;
2063 vty_out (vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt);
2064 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
2067 /* Print all aspath and hash information. This function is used from
2068 `show ip bgp paths' command. */
2070 aspath_print_all_vty (struct vty *vty)
2072 hash_iterate (ashash,
2073 (void (*) (struct hash_backet *, void *))
2074 aspath_show_all_iterator,