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
33 #include "bgpd/bgpd.h"
34 #include "bgpd/bgp_aspath.h"
35 #include "bgpd/bgp_debug.h"
36 #include "bgpd/bgp_attr.h"
38 /* Attr. Flags and Attr. Type Code. */
39 #define AS_HEADER_SIZE 2
41 /* Now FOUR octets are used for AS value. */
42 #define AS_VALUE_SIZE sizeof (as_t)
43 /* This is the old one */
44 #define AS16_VALUE_SIZE sizeof (as16_t)
46 /* Maximum protocol segment length value */
47 #define AS_SEGMENT_MAX 255
49 /* The following length and size macros relate specifically to Quagga's
50 * internal representation of AS-Segments, not per se to the on-wire
51 * sizes and lengths. At present (200508) they sort of match, however
52 * the ONLY functions which should now about the on-wire syntax are
53 * aspath_put, assegment_put and assegment_parse.
55 * aspath_put returns bytes written, the only definitive record of
56 * size of wire-format attribute..
59 /* Calculated size in bytes of ASN segment data to hold N ASN's */
60 #define ASSEGMENT_DATA_SIZE(N,S) \
61 ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )
63 /* Calculated size of segment struct to hold N ASN's */
64 #define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
66 /* AS segment octet length. */
67 #define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
69 /* AS_SEQUENCE segments can be packed together */
70 /* Can the types of X and Y be considered for packing? */
71 #define ASSEGMENT_TYPES_PACKABLE(X,Y) \
72 ( ((X)->type == (Y)->type) \
73 && ((X)->type == AS_SEQUENCE))
74 /* Types and length of X,Y suitable for packing? */
75 #define ASSEGMENTS_PACKABLE(X,Y) \
76 ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \
77 && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) )
79 /* As segment header - the on-wire representation
80 * NOT the internal representation!
82 struct assegment_header
88 /* Hash for aspath. This is the top level structure of AS path. */
89 static struct hash
*ashash
;
91 /* Stream for SNMP. See aspath_snmp_pathseg */
92 static struct stream
*snmp_stream
;
95 assegment_data_new (int num
)
97 return (XCALLOC (MTYPE_AS_SEG_DATA
, ASSEGMENT_DATA_SIZE (num
, 1)));
101 assegment_data_free (as_t
*asdata
)
103 XFREE (MTYPE_AS_SEG_DATA
,asdata
);
106 /* Get a new segment. Note that 0 is an allowed length,
107 * and will result in a segment with no allocated data segment.
108 * the caller should immediately assign data to the segment, as the segment
109 * otherwise is not generally valid
111 static struct assegment
*
112 assegment_new (u_char type
, u_short length
)
114 struct assegment
*new;
116 new = XCALLOC (MTYPE_AS_SEG
, sizeof (struct assegment
));
119 new->as
= assegment_data_new (length
);
121 new->length
= length
;
128 assegment_free (struct assegment
*seg
)
134 XFREE (MTYPE_AS_SEG_DATA
, seg
->as
);
135 memset (seg
, 0xfe, sizeof(struct assegment
));
136 XFREE (MTYPE_AS_SEG
, seg
);
141 /* free entire chain of segments */
143 assegment_free_all (struct assegment
*seg
)
145 struct assegment
*prev
;
151 assegment_free (prev
);
155 /* Duplicate just the given assegment and its data */
156 static struct assegment
*
157 assegment_dup (struct assegment
*seg
)
159 struct assegment
*new;
161 new = assegment_new (seg
->type
, seg
->length
);
162 memcpy (new->as
, seg
->as
, ASSEGMENT_DATA_SIZE (new->length
, 1) );
167 /* Duplicate entire chain of assegments, return the head */
168 static struct assegment
*
169 assegment_dup_all (struct assegment
*seg
)
171 struct assegment
*new = NULL
;
172 struct assegment
*head
= NULL
;
178 new->next
= assegment_dup (seg
);
182 head
= new = assegment_dup (seg
);
189 /* prepend the as number to given segment, given num of times */
190 static struct assegment
*
191 assegment_prepend_asns (struct assegment
*seg
, as_t asnum
, int num
)
198 if (num
>= AS_SEGMENT_MAX
)
199 return seg
; /* we don't do huge prepends */
201 newas
= assegment_data_new (seg
->length
+ num
);
206 for (i
= 0; i
< num
; i
++)
209 memcpy (newas
+ num
, seg
->as
, ASSEGMENT_DATA_SIZE (seg
->length
, 1));
210 XFREE (MTYPE_AS_SEG_DATA
, seg
->as
);
216 assegment_free_all (seg
);
220 /* append given array of as numbers to the segment */
221 static struct assegment
*
222 assegment_append_asns (struct assegment
*seg
, as_t
*asnos
, int num
)
226 newas
= XREALLOC (MTYPE_AS_SEG_DATA
, seg
->as
,
227 ASSEGMENT_DATA_SIZE (seg
->length
+ num
, 1));
232 memcpy (seg
->as
+ seg
->length
, asnos
, ASSEGMENT_DATA_SIZE(num
, 1));
237 assegment_free_all (seg
);
242 int_cmp (const void *p1
, const void *p2
)
244 const as_t
*as1
= p1
;
245 const as_t
*as2
= p2
;
247 return (*as1
== *as2
)
248 ? 0 : ( (*as1
> *as2
) ? 1 : -1);
251 /* normalise the segment.
252 * In particular, merge runs of AS_SEQUENCEs into one segment
253 * Internally, we do not care about the wire segment length limit, and
254 * we want each distinct AS_PATHs to have the exact same internal
255 * representation - eg, so that our hashing actually works..
257 static struct assegment
*
258 assegment_normalise (struct assegment
*head
)
260 struct assegment
*seg
= head
, *pin
;
261 struct assegment
*tmp
;
270 /* Sort values SET segments, for determinism in paths to aid
271 * creation of hash values / path comparisons
272 * and because it helps other lesser implementations ;)
274 if (seg
->type
== AS_SET
|| seg
->type
== AS_CONFED_SET
)
279 qsort (seg
->as
, seg
->length
, sizeof(as_t
), int_cmp
);
282 for (i
=1; i
< seg
->length
; i
++)
284 if (seg
->as
[tail
] == seg
->as
[i
])
289 seg
->as
[tail
] = seg
->as
[i
];
291 /* seg->length can be 0.. */
293 seg
->length
= tail
+ 1;
296 /* read ahead from the current, pinned segment while the segments
297 * are packable/mergeable. Append all following packable segments
298 * to the segment we have pinned and remove these appended
301 while (pin
->next
&& ASSEGMENT_TYPES_PACKABLE(pin
, pin
->next
))
306 /* append the next sequence to the pinned sequence */
307 pin
= assegment_append_asns (pin
, seg
->as
, seg
->length
);
309 /* bypass the next sequence */
310 pin
->next
= seg
->next
;
312 /* get rid of the now referenceless segment */
313 assegment_free (tmp
);
322 static struct aspath
*
325 return XCALLOC (MTYPE_AS_PATH
, sizeof (struct aspath
));
328 /* Free AS path structure. */
330 aspath_free (struct aspath
*aspath
)
334 if (aspath
->segments
)
335 assegment_free_all (aspath
->segments
);
337 XFREE (MTYPE_AS_STR
, aspath
->str
);
338 XFREE (MTYPE_AS_PATH
, aspath
);
341 /* Unintern aspath from AS path bucket. */
343 aspath_unintern (struct aspath
*aspath
)
350 if (aspath
->refcnt
== 0)
352 /* This aspath must exist in aspath hash table. */
353 ret
= hash_release (ashash
, aspath
);
354 assert (ret
!= NULL
);
355 aspath_free (aspath
);
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 (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 && (seg
->as
[i
] < BGP_PRIVATE_AS_MIN
480 || seg
->as
[i
] > BGP_PRIVATE_AS_MAX
))
481 highest
= seg
->as
[i
];
487 /* Return 1 if there are any 4-byte ASes in the path */
489 aspath_has_as4 (struct aspath
*aspath
)
491 struct assegment
*seg
= aspath
->segments
;
496 for (i
= 0; i
< seg
->length
; i
++)
497 if (seg
->as
[i
] > BGP_AS_MAX
)
504 /* Convert aspath structure to string expression. */
506 aspath_make_str_count (struct aspath
*as
)
508 struct assegment
*seg
;
516 str_buf
= XMALLOC (MTYPE_AS_STR
, 1);
523 /* ASN takes 5 to 10 chars plus seperator, see below.
524 * If there is one differing segment type, we need an additional
525 * 2 chars for segment delimiters, and the final '\0'.
526 * Hopefully this is large enough to avoid hitting the realloc
527 * code below for most common sequences.
529 * This was changed to 10 after the well-known BGP assertion, which
530 * had hit some parts of the Internet in May of 2009.
532 #define ASN_STR_LEN (10 + 1)
533 str_size
= MAX (assegment_count_asns (seg
, 0) * ASN_STR_LEN
+ 2 + 1,
534 ASPATH_STR_DEFAULT_LEN
);
535 str_buf
= XMALLOC (MTYPE_AS_STR
, str_size
);
542 /* Check AS type validity. Set seperator for segment */
550 case AS_CONFED_SEQUENCE
:
554 XFREE (MTYPE_AS_STR
, str_buf
);
558 /* We might need to increase str_buf, particularly if path has
559 * differing segments types, our initial guesstimate above will
560 * have been wrong. Need 10 chars for ASN, a seperator each and
561 * potentially two segment delimiters, plus a space between each
562 * segment and trailing zero.
564 * This definitely didn't work with the value of 5 bytes and
567 #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
568 if ( (len
+ SEGMENT_STR_LEN(seg
)) > str_size
)
570 str_size
= len
+ SEGMENT_STR_LEN(seg
);
571 str_buf
= XREALLOC (MTYPE_AS_STR
, str_buf
, str_size
);
574 #undef SEGMENT_STR_LEN
576 if (seg
->type
!= AS_SEQUENCE
)
577 len
+= snprintf (str_buf
+ len
, str_size
- len
,
579 aspath_delimiter_char (seg
->type
, AS_SEG_START
));
581 /* write out the ASNs, with their seperators, bar the last one*/
582 for (i
= 0; i
< seg
->length
; i
++)
584 len
+= snprintf (str_buf
+ len
, str_size
- len
, "%u", seg
->as
[i
]);
586 if (i
< (seg
->length
- 1))
587 len
+= snprintf (str_buf
+ len
, str_size
- len
, "%c", seperator
);
590 if (seg
->type
!= AS_SEQUENCE
)
591 len
+= snprintf (str_buf
+ len
, str_size
- len
, "%c",
592 aspath_delimiter_char (seg
->type
, AS_SEG_END
));
594 len
+= snprintf (str_buf
+ len
, str_size
- len
, " ");
599 assert (len
< str_size
);
607 aspath_str_update (struct aspath
*as
)
610 XFREE (MTYPE_AS_STR
, as
->str
);
611 as
->str
= aspath_make_str_count (as
);
614 /* Intern allocated AS path. */
616 aspath_intern (struct aspath
*aspath
)
620 /* Assert this AS path structure is not interned. */
621 assert (aspath
->refcnt
== 0);
623 /* Check AS path hash. */
624 find
= hash_get (ashash
, aspath
, hash_alloc_intern
);
627 aspath_free (aspath
);
632 find
->str
= aspath_make_str_count (find
);
637 /* Duplicate aspath structure. Created same aspath structure but
638 reference count and AS path string is cleared. */
640 aspath_dup (struct aspath
*aspath
)
644 new = XCALLOC (MTYPE_AS_PATH
, sizeof (struct aspath
));
646 if (aspath
->segments
)
647 new->segments
= assegment_dup_all (aspath
->segments
);
649 new->segments
= NULL
;
651 new->str
= aspath_make_str_count (aspath
);
657 aspath_hash_alloc (void *arg
)
659 struct aspath
*aspath
;
661 /* New aspath structure is needed. */
662 aspath
= aspath_dup (arg
);
664 /* Malformed AS path value. */
667 aspath_free (aspath
);
674 /* parse as-segment byte stream in struct assegment */
675 static struct assegment
*
676 assegments_parse (struct stream
*s
, size_t length
, int use32bit
)
678 struct assegment_header segh
;
679 struct assegment
*seg
, *prev
= NULL
, *head
= NULL
;
682 /* empty aspath (ie iBGP or somesuch) */
686 if (BGP_DEBUG (as4
, AS4_SEGMENT
))
687 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
688 (unsigned long) length
);
690 if ( (STREAM_READABLE(s
) < length
)
691 || (STREAM_READABLE(s
) < AS_HEADER_SIZE
)
692 || (length
% AS16_VALUE_SIZE
))
695 while ( (STREAM_READABLE(s
) > AS_HEADER_SIZE
)
701 /* softly softly, get the header first on its own */
702 segh
.type
= stream_getc (s
);
703 segh
.length
= stream_getc (s
);
705 seg_size
= ASSEGMENT_SIZE(segh
.length
, use32bit
);
707 if (BGP_DEBUG (as4
, AS4_SEGMENT
))
708 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
709 segh
.type
, segh
.length
);
712 if ( ((bytes
+ seg_size
) > length
)
713 /* 1771bis 4.3b: seg length contains one or more */
714 || (segh
.length
== 0)
715 /* Paranoia in case someone changes type of segment length.
716 * Shift both values by 0x10 to make the comparison operate
717 * on more, than 8 bits (otherwise it's a warning, bug #564).
719 || ((sizeof segh
.length
> 1) && (0x10 + segh
.length
> 0x10 + AS_SEGMENT_MAX
)) )
722 assegment_free_all (head
);
726 /* now its safe to trust lengths */
727 seg
= assegment_new (segh
.type
, segh
.length
);
731 else /* it's the first segment */
734 for (i
= 0; i
< segh
.length
; i
++)
735 seg
->as
[i
] = (use32bit
) ? stream_getl (s
) : stream_getw (s
);
739 if (BGP_DEBUG (as4
, AS4_SEGMENT
))
740 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
741 (unsigned long) bytes
);
746 return assegment_normalise (head
);
749 /* AS path parse function. pnt is a pointer to byte stream and length
750 is length of byte stream. If there is same AS path in the the AS
751 path hash then return it else make new AS path structure. */
753 aspath_parse (struct stream
*s
, size_t length
, int use32bit
)
758 /* If length is odd it's malformed AS path. */
759 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
760 * otherwise its malformed when length is larger than 2 and (length-2)
761 * is not dividable by 4.
762 * But... this time we're lazy
764 if (length
% AS16_VALUE_SIZE
)
767 memset (&as
, 0, sizeof (struct aspath
));
768 as
.segments
= assegments_parse (s
, length
, use32bit
);
770 /* If already same aspath exist then return it. */
771 find
= hash_get (ashash
, &as
, aspath_hash_alloc
);
773 /* aspath_hash_alloc dupes segments too. that probably could be
776 assegment_free_all (as
.segments
);
778 XFREE (MTYPE_AS_STR
, as
.str
);
788 assegment_data_put (struct stream
*s
, as_t
*as
, int num
, int use32bit
)
791 assert (num
<= AS_SEGMENT_MAX
);
793 for (i
= 0; i
< num
; i
++)
795 stream_putl (s
, as
[i
]);
798 if ( as
[i
] <= BGP_AS_MAX
)
799 stream_putw(s
, as
[i
]);
801 stream_putw(s
, BGP_AS_TRANS
);
806 assegment_header_put (struct stream
*s
, u_char type
, int length
)
809 assert (length
<= AS_SEGMENT_MAX
);
810 stream_putc (s
, type
);
811 lenp
= stream_get_endp (s
);
812 stream_putc (s
, length
);
816 /* write aspath data to stream */
818 aspath_put (struct stream
*s
, struct aspath
*as
, int use32bit
)
820 struct assegment
*seg
= as
->segments
;
823 if (!seg
|| seg
->length
== 0)
829 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
830 * At the moment, we would write out a partial aspath, and our peer
831 * will complain and drop the session :-/
833 * The general assumption here is that many things tested will
834 * never happen. And, in real live, up to now, they have not.
836 while (seg
&& (ASSEGMENT_LEN(seg
, use32bit
) <= STREAM_WRITEABLE(s
)))
838 struct assegment
*next
= seg
->next
;
843 /* Overlength segments have to be split up */
844 while ( (seg
->length
- written
) > AS_SEGMENT_MAX
)
846 assegment_header_put (s
, seg
->type
, AS_SEGMENT_MAX
);
847 assegment_data_put (s
, seg
->as
, AS_SEGMENT_MAX
, use32bit
);
848 written
+= AS_SEGMENT_MAX
;
849 bytes
+= ASSEGMENT_SIZE (written
, use32bit
);
852 /* write the final segment, probably is also the first */
853 lenp
= assegment_header_put (s
, seg
->type
, seg
->length
- written
);
854 assegment_data_put (s
, (seg
->as
+ written
), seg
->length
- written
,
857 /* Sequence-type segments can be 'packed' together
858 * Case of a segment which was overlength and split up
859 * will be missed here, but that doesn't matter.
861 while (next
&& ASSEGMENTS_PACKABLE (seg
, next
))
863 /* NB: We should never normally get here given we
864 * normalise aspath data when parse them. However, better
865 * safe than sorry. We potentially could call
866 * assegment_normalise here instead, but it's cheaper and
867 * easier to do it on the fly here rather than go through
868 * the segment list twice every time we write out
872 /* Next segment's data can fit in this one */
873 assegment_data_put (s
, next
->as
, next
->length
, use32bit
);
875 /* update the length of the segment header */
876 stream_putc_at (s
, lenp
, seg
->length
- written
+ next
->length
);
877 asns_packed
+= next
->length
;
882 bytes
+= ASSEGMENT_SIZE (seg
->length
- written
+ asns_packed
,
890 /* This is for SNMP BGP4PATHATTRASPATHSEGMENT
891 * We have no way to manage the storage, so we use a static stream
892 * wrapper around aspath_put.
895 aspath_snmp_pathseg (struct aspath
*as
, size_t *varlen
)
897 #define SNMP_PATHSEG_MAX 1024
900 snmp_stream
= stream_new (SNMP_PATHSEG_MAX
);
902 stream_reset (snmp_stream
);
909 aspath_put (snmp_stream
, as
, 0); /* use 16 bit for now here */
911 *varlen
= stream_get_endp (snmp_stream
);
912 return stream_pnt(snmp_stream
);
915 #define min(A,B) ((A) < (B) ? (A) : (B))
917 static struct assegment
*
918 aspath_aggregate_as_set_add (struct aspath
*aspath
, struct assegment
*asset
,
923 /* If this is first AS set member, create new as-set segment. */
926 asset
= assegment_new (AS_SET
, 1);
927 if (! aspath
->segments
)
928 aspath
->segments
= asset
;
931 struct assegment
*seg
= aspath
->segments
;
936 asset
->type
= AS_SET
;
942 /* Check this AS value already exists or not. */
943 for (i
= 0; i
< asset
->length
; i
++)
944 if (asset
->as
[i
] == as
)
948 asset
->as
= XREALLOC (MTYPE_AS_SEG_DATA
, asset
->as
,
949 asset
->length
* AS_VALUE_SIZE
);
950 asset
->as
[asset
->length
- 1] = as
;
957 /* Modify as1 using as2 for aggregation. */
959 aspath_aggregate (struct aspath
*as1
, struct aspath
*as2
)
965 struct assegment
*seg1
= as1
->segments
;
966 struct assegment
*seg2
= as2
->segments
;
967 struct aspath
*aspath
= NULL
;
968 struct assegment
*asset
;
969 struct assegment
*prevseg
= NULL
;
976 /* First of all check common leading sequence. */
979 /* Check segment type. */
980 if (seg1
->type
!= seg2
->type
)
983 /* Minimum segment length. */
984 minlen
= min (seg1
->length
, seg2
->length
);
986 for (match
= 0; match
< minlen
; match
++)
987 if (seg1
->as
[match
] != seg2
->as
[match
])
992 struct assegment
*seg
= assegment_new (seg1
->type
, 0);
994 seg
= assegment_append_asns (seg
, seg1
->as
, match
);
998 aspath
= aspath_new ();
999 aspath
->segments
= seg
;
1002 prevseg
->next
= seg
;
1007 if (match
!= minlen
|| match
!= seg1
->length
1008 || seg1
->length
!= seg2
->length
)
1016 aspath
= aspath_new();
1018 /* Make as-set using rest of all information. */
1022 for (i
= from
; i
< seg1
->length
; i
++)
1023 asset
= aspath_aggregate_as_set_add (aspath
, asset
, seg1
->as
[i
]);
1032 for (i
= from
; i
< seg2
->length
; i
++)
1033 asset
= aspath_aggregate_as_set_add (aspath
, asset
, seg2
->as
[i
]);
1039 assegment_normalise (aspath
->segments
);
1040 aspath_str_update (aspath
);
1044 /* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1045 attribute, check the leftmost AS number in the AS_PATH attribute is
1046 or not the peer's AS number. */
1048 aspath_firstas_check (struct aspath
*aspath
, as_t asno
)
1050 if ( (aspath
== NULL
) || (aspath
->segments
== NULL
) )
1053 if (aspath
->segments
1054 && (aspath
->segments
->type
== AS_SEQUENCE
)
1055 && (aspath
->segments
->as
[0] == asno
))
1061 /* AS path loop check. If aspath contains asno then return >= 1. */
1063 aspath_loop_check (struct aspath
*aspath
, as_t asno
)
1065 struct assegment
*seg
;
1068 if ( (aspath
== NULL
) || (aspath
->segments
== NULL
) )
1071 seg
= aspath
->segments
;
1077 for (i
= 0; i
< seg
->length
; i
++)
1078 if (seg
->as
[i
] == asno
)
1086 /* When all of AS path is private AS return 1. */
1088 aspath_private_as_check (struct aspath
*aspath
)
1090 struct assegment
*seg
;
1092 if ( !(aspath
&& aspath
->segments
) )
1095 seg
= aspath
->segments
;
1101 for (i
= 0; i
< seg
->length
; i
++)
1103 if ( (seg
->as
[i
] < BGP_PRIVATE_AS_MIN
)
1104 || (seg
->as
[i
] > BGP_PRIVATE_AS_MAX
) )
1112 /* AS path confed check. If aspath contains confed set or sequence then return 1. */
1114 aspath_confed_check (struct aspath
*aspath
)
1116 struct assegment
*seg
;
1118 if ( !(aspath
&& aspath
->segments
) )
1121 seg
= aspath
->segments
;
1125 if (seg
->type
== AS_CONFED_SET
|| seg
->type
== AS_CONFED_SEQUENCE
)
1132 /* Leftmost AS path segment confed check. If leftmost AS segment is of type
1133 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1135 aspath_left_confed_check (struct aspath
*aspath
)
1138 if ( !(aspath
&& aspath
->segments
) )
1141 if ( (aspath
->segments
->type
== AS_CONFED_SEQUENCE
)
1142 || (aspath
->segments
->type
== AS_CONFED_SET
) )
1148 /* Merge as1 to as2. as2 should be uninterned aspath. */
1149 static struct aspath
*
1150 aspath_merge (struct aspath
*as1
, struct aspath
*as2
)
1152 struct assegment
*last
, *new;
1157 last
= new = assegment_dup_all (as1
->segments
);
1159 /* find the last valid segment */
1160 while (last
&& last
->next
)
1163 last
->next
= as2
->segments
;
1164 as2
->segments
= new;
1165 aspath_str_update (as2
);
1169 /* Prepend as1 to as2. as2 should be uninterned aspath. */
1171 aspath_prepend (struct aspath
*as1
, struct aspath
*as2
)
1173 struct assegment
*seg1
;
1174 struct assegment
*seg2
;
1179 seg1
= as1
->segments
;
1180 seg2
= as2
->segments
;
1182 /* If as2 is empty, only need to dupe as1's chain onto as2 */
1185 as2
->segments
= assegment_dup_all (as1
->segments
);
1186 aspath_str_update (as2
);
1190 /* If as1 is empty AS, no prepending to do. */
1194 /* find the tail as1's segment chain. */
1195 while (seg1
&& seg1
->next
)
1198 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1199 if (seg1
->type
== AS_SEQUENCE
&& seg2
->type
== AS_CONFED_SEQUENCE
)
1200 as2
= aspath_delete_confed_seq (as2
);
1202 /* Compare last segment type of as1 and first segment type of as2. */
1203 if (seg1
->type
!= seg2
->type
)
1204 return aspath_merge (as1
, as2
);
1206 if (seg1
->type
== AS_SEQUENCE
)
1208 /* We have two chains of segments, as1->segments and seg2,
1209 * and we have to attach them together, merging the attaching
1210 * segments together into one.
1212 * 1. dupe as1->segments onto head of as2
1213 * 2. merge seg2's asns onto last segment of this new chain
1214 * 3. attach chain after seg2
1217 /* dupe as1 onto as2's head */
1218 seg1
= as2
->segments
= assegment_dup_all (as1
->segments
);
1220 /* refind the tail of as2, reusing seg1 */
1221 while (seg1
&& seg1
->next
)
1224 /* merge the old head, seg2, into tail, seg1 */
1225 seg1
= assegment_append_asns (seg1
, seg2
->as
, seg2
->length
);
1227 /* bypass the merged seg2, and attach any chain after it to
1228 * chain descending from as2's head
1230 seg1
->next
= seg2
->next
;
1232 /* seg2 is now referenceless and useless*/
1233 assegment_free (seg2
);
1235 /* we've now prepended as1's segment chain to as2, merging
1236 * the inbetween AS_SEQUENCE of seg2 in the process
1238 aspath_str_update (as2
);
1243 /* AS_SET merge code is needed at here. */
1244 return aspath_merge (as1
, as2
);
1246 /* XXX: Ermmm, what if as1 has multiple segments?? */
1251 /* Iterate over AS_PATH segments and wipe all occurences of the
1252 * listed AS numbers. Hence some segments may lose some or even
1253 * all data on the way, the operation is implemented as a smarter
1254 * version of aspath_dup(), which allocates memory to hold the new
1255 * data, not the original. The new AS path is returned.
1258 aspath_filter_exclude (struct aspath
* source
, struct aspath
* exclude_list
)
1260 struct assegment
* srcseg
, * exclseg
, * lastseg
;
1261 struct aspath
* newpath
;
1263 newpath
= aspath_new();
1266 for (srcseg
= source
->segments
; srcseg
; srcseg
= srcseg
->next
)
1268 unsigned i
, y
, newlen
= 0, done
= 0, skip_as
;
1269 struct assegment
* newseg
;
1271 /* Find out, how much ASns are we going to pick from this segment.
1272 * We can't perform filtering right inline, because the size of
1273 * the new segment isn't known at the moment yet.
1275 for (i
= 0; i
< srcseg
->length
; i
++)
1278 for (exclseg
= exclude_list
->segments
; exclseg
&& !skip_as
; exclseg
= exclseg
->next
)
1279 for (y
= 0; y
< exclseg
->length
; y
++)
1280 if (srcseg
->as
[i
] == exclseg
->as
[y
])
1283 // There's no sense in testing the rest of exclusion list, bail out.
1289 /* newlen is now the number of ASns to copy */
1293 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1294 newseg
= assegment_new (srcseg
->type
, newlen
);
1295 for (i
= 0; i
< srcseg
->length
; i
++)
1298 for (exclseg
= exclude_list
->segments
; exclseg
&& !skip_as
; exclseg
= exclseg
->next
)
1299 for (y
= 0; y
< exclseg
->length
; y
++)
1300 if (srcseg
->as
[i
] == exclseg
->as
[y
])
1307 newseg
->as
[done
++] = srcseg
->as
[i
];
1309 /* At his point newlen must be equal to done, and both must be positive. Append
1310 * the filtered segment to the gross result. */
1312 newpath
->segments
= newseg
;
1314 lastseg
->next
= newseg
;
1317 aspath_str_update (newpath
);
1318 /* We are happy returning even an empty AS_PATH, because the administrator
1319 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1320 * by having a match rule against certain AS_PATH regexps in the route-map index.
1322 aspath_free (source
);
1326 /* Add specified AS to the leftmost of aspath. */
1327 static struct aspath
*
1328 aspath_add_one_as (struct aspath
*aspath
, as_t asno
, u_char type
)
1330 struct assegment
*assegment
= aspath
->segments
;
1332 /* In case of empty aspath. */
1333 if (assegment
== NULL
|| assegment
->length
== 0)
1335 aspath
->segments
= assegment_new (type
, 1);
1336 aspath
->segments
->as
[0] = asno
;
1339 assegment_free (assegment
);
1344 if (assegment
->type
== type
)
1345 aspath
->segments
= assegment_prepend_asns (aspath
->segments
, asno
, 1);
1348 /* create new segment
1349 * push it onto head of aspath's segment chain
1351 struct assegment
*newsegment
;
1353 newsegment
= assegment_new (type
, 1);
1354 newsegment
->as
[0] = asno
;
1356 newsegment
->next
= assegment
;
1357 aspath
->segments
= newsegment
;
1363 /* Add specified AS to the leftmost of aspath. */
1365 aspath_add_seq (struct aspath
*aspath
, as_t asno
)
1367 return aspath_add_one_as (aspath
, asno
, AS_SEQUENCE
);
1370 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1371 as2's leftmost AS is same return 1. */
1373 aspath_cmp_left (const struct aspath
*aspath1
, const struct aspath
*aspath2
)
1375 const struct assegment
*seg1
= NULL
;
1376 const struct assegment
*seg2
= NULL
;
1378 if (!(aspath1
&& aspath2
))
1381 seg1
= aspath1
->segments
;
1382 seg2
= aspath2
->segments
;
1384 /* find first non-confed segments for each */
1385 while (seg1
&& ((seg1
->type
== AS_CONFED_SEQUENCE
)
1386 || (seg1
->type
== AS_CONFED_SET
)))
1389 while (seg2
&& ((seg2
->type
== AS_CONFED_SEQUENCE
)
1390 || (seg2
->type
== AS_CONFED_SET
)))
1395 && (seg1
->type
== AS_SEQUENCE
) && (seg2
->type
== AS_SEQUENCE
)))
1398 if (seg1
->as
[0] == seg2
->as
[0])
1404 /* Truncate an aspath after a number of hops, and put the hops remaining
1405 * at the front of another aspath. Needed for AS4 compat.
1407 * Returned aspath is a /new/ aspath, which should either by free'd or
1408 * interned by the caller, as desired.
1411 aspath_reconcile_as4 ( struct aspath
*aspath
, struct aspath
*as4path
)
1413 struct assegment
*seg
, *newseg
, *prevseg
= NULL
;
1414 struct aspath
*newpath
= NULL
, *mergedpath
;
1415 int hops
, cpasns
= 0;
1420 seg
= aspath
->segments
;
1422 /* CONFEDs should get reconciled too.. */
1423 hops
= (aspath_count_hops (aspath
) + aspath_count_confeds (aspath
))
1424 - aspath_count_hops (as4path
);
1428 if (BGP_DEBUG (as4
, AS4
))
1429 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1430 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1431 * which is daft behaviour - it contains vital loop-detection
1432 * information which must have been removed from AS_PATH.
1434 hops
= aspath_count_hops (aspath
);
1438 return aspath_dup (as4path
);
1440 if ( BGP_DEBUG(as4
, AS4
))
1441 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1442 aspath
->str
, as4path
->str
);
1444 while (seg
&& hops
> 0)
1451 cpasns
= seg
->length
;
1453 case AS_CONFED_SEQUENCE
:
1454 /* Should never split a confed-sequence, if hop-count
1455 * suggests we must then something's gone wrong somewhere.
1457 * Most important goal is to preserve AS_PATHs prime function
1458 * as loop-detector, so we fudge the numbers so that the entire
1459 * confed-sequence is merged in.
1461 if (hops
< seg
->length
)
1463 if (BGP_DEBUG (as4
, AS4
))
1464 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1465 " across 2/4 ASN boundary somewhere, broken..");
1469 cpasns
= MIN(seg
->length
, hops
);
1470 hops
-= seg
->length
;
1473 assert (cpasns
<= seg
->length
);
1475 newseg
= assegment_new (seg
->type
, 0);
1476 newseg
= assegment_append_asns (newseg
, seg
->as
, cpasns
);
1480 newpath
= aspath_new ();
1481 newpath
->segments
= newseg
;
1484 prevseg
->next
= newseg
;
1490 /* We may be able to join some segments here, and we must
1491 * do this because... we want normalised aspaths in out hash
1492 * and we do not want to stumble in aspath_put.
1494 mergedpath
= aspath_merge (newpath
, aspath_dup(as4path
));
1495 aspath_free (newpath
);
1496 mergedpath
->segments
= assegment_normalise (mergedpath
->segments
);
1497 aspath_str_update (mergedpath
);
1499 if ( BGP_DEBUG(as4
, AS4
))
1500 zlog_debug ("[AS4] result of synthesizing is %s",
1506 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1507 as2's leftmost AS is same return 1. (confederation as-path
1510 aspath_cmp_left_confed (const struct aspath
*aspath1
, const struct aspath
*aspath2
)
1512 if (! (aspath1
&& aspath2
) )
1515 if ( !(aspath1
->segments
&& aspath2
->segments
) )
1518 if ( (aspath1
->segments
->type
!= AS_CONFED_SEQUENCE
)
1519 || (aspath2
->segments
->type
!= AS_CONFED_SEQUENCE
) )
1522 if (aspath1
->segments
->as
[0] == aspath2
->segments
->as
[0])
1528 /* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1529 * See RFC3065, 6.1 c1 */
1531 aspath_delete_confed_seq (struct aspath
*aspath
)
1533 struct assegment
*seg
;
1535 if (!(aspath
&& aspath
->segments
))
1538 seg
= aspath
->segments
;
1540 /* "if the first path segment of the AS_PATH is
1541 * of type AS_CONFED_SEQUENCE,"
1543 if (aspath
->segments
->type
!= AS_CONFED_SEQUENCE
)
1546 /* "... that segment and any immediately following segments
1547 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1548 * from the AS_PATH attribute,"
1551 (seg
->type
== AS_CONFED_SEQUENCE
|| seg
->type
== AS_CONFED_SET
))
1553 aspath
->segments
= seg
->next
;
1554 assegment_free (seg
);
1555 seg
= aspath
->segments
;
1557 aspath_str_update (aspath
);
1561 /* Add new AS number to the leftmost part of the aspath as
1562 AS_CONFED_SEQUENCE. */
1564 aspath_add_confed_seq (struct aspath
*aspath
, as_t asno
)
1566 return aspath_add_one_as (aspath
, asno
, AS_CONFED_SEQUENCE
);
1569 /* Add new as value to as path structure. */
1571 aspath_as_add (struct aspath
*as
, as_t asno
)
1573 struct assegment
*seg
= as
->segments
;
1578 /* Last segment search procedure. */
1582 assegment_append_asns (seg
, &asno
, 1);
1585 /* Add new as segment to the as path. */
1587 aspath_segment_add (struct aspath
*as
, int type
)
1589 struct assegment
*seg
= as
->segments
;
1590 struct assegment
*new = assegment_new (type
, 0);
1605 return aspath_parse (NULL
, 0, 1); /* 32Bit ;-) */
1609 aspath_empty_get (void)
1611 struct aspath
*aspath
;
1613 aspath
= aspath_new ();
1614 aspath
->str
= aspath_make_str_count (aspath
);
1621 return ashash
->count
;
1625 Theoretically, one as path can have:
1627 One BGP packet size should be less than 4096.
1628 One BGP attribute size should be less than 4096 - BGP header size.
1629 One BGP aspath size should be less than 4096 - BGP header size -
1630 BGP mandantry attribute size.
1633 /* AS path string lexical token enum. */
1639 as_token_confed_seq_start
,
1640 as_token_confed_seq_end
,
1641 as_token_confed_set_start
,
1642 as_token_confed_set_end
,
1646 /* Return next token and point for string parse. */
1648 aspath_gettoken (const char *buf
, enum as_token
*token
, u_long
*asno
)
1650 const char *p
= buf
;
1652 /* Skip seperators (space for sequences, ',' for sets). */
1653 while (isspace ((int) *p
) || *p
== ',')
1656 /* Check the end of the string and type specify characters
1663 *token
= as_token_set_start
;
1667 *token
= as_token_set_end
;
1671 *token
= as_token_confed_seq_start
;
1675 *token
= as_token_confed_seq_end
;
1679 *token
= as_token_confed_set_start
;
1683 *token
= as_token_confed_set_end
;
1688 /* Check actual AS value. */
1689 if (isdigit ((int) *p
))
1693 *token
= as_token_asval
;
1697 while (isdigit ((int) *p
))
1700 asval
+= (*p
- '0');
1707 /* There is no match then return unknown token. */
1708 *token
= as_token_unknown
;
1713 aspath_str2aspath (const char *str
)
1715 enum as_token token
= as_token_unknown
;
1718 struct aspath
*aspath
;
1721 aspath
= aspath_new ();
1723 /* We start default type as AS_SEQUENCE. */
1724 as_type
= AS_SEQUENCE
;
1727 while ((str
= aspath_gettoken (str
, &token
, &asno
)) != NULL
)
1731 case as_token_asval
:
1734 aspath_segment_add (aspath
, as_type
);
1737 aspath_as_add (aspath
, asno
);
1739 case as_token_set_start
:
1741 aspath_segment_add (aspath
, as_type
);
1744 case as_token_set_end
:
1745 as_type
= AS_SEQUENCE
;
1748 case as_token_confed_seq_start
:
1749 as_type
= AS_CONFED_SEQUENCE
;
1750 aspath_segment_add (aspath
, as_type
);
1753 case as_token_confed_seq_end
:
1754 as_type
= AS_SEQUENCE
;
1757 case as_token_confed_set_start
:
1758 as_type
= AS_CONFED_SET
;
1759 aspath_segment_add (aspath
, as_type
);
1762 case as_token_confed_set_end
:
1763 as_type
= AS_SEQUENCE
;
1766 case as_token_unknown
:
1768 aspath_free (aspath
);
1773 aspath
->str
= aspath_make_str_count (aspath
);
1778 /* Make hash value by raw aspath data. */
1780 aspath_key_make (void *p
)
1782 struct aspath
* aspath
= (struct aspath
*) p
;
1783 unsigned int key
= 0;
1786 aspath_str_update (aspath
);
1788 key
= jhash (aspath
->str
, strlen(aspath
->str
), 2334325);
1793 /* If two aspath have same value then return 1 else return 0 */
1795 aspath_cmp (const void *arg1
, const void *arg2
)
1797 const struct assegment
*seg1
= ((const struct aspath
*)arg1
)->segments
;
1798 const struct assegment
*seg2
= ((const struct aspath
*)arg2
)->segments
;
1800 while (seg1
|| seg2
)
1803 if ((!seg1
&& seg2
) || (seg1
&& !seg2
))
1805 if (seg1
->type
!= seg2
->type
)
1807 if (seg1
->length
!= seg2
->length
)
1809 for (i
= 0; i
< seg1
->length
; i
++)
1810 if (seg1
->as
[i
] != seg2
->as
[i
])
1818 /* AS path hash initialize. */
1822 ashash
= hash_create_size (32767, aspath_key_make
, aspath_cmp
);
1826 aspath_finish (void)
1832 stream_free (snmp_stream
);
1835 /* return and as path value */
1837 aspath_print (struct aspath
*as
)
1839 return (as
? as
->str
: NULL
);
1842 /* Printing functions */
1843 /* Feed the AS_PATH to the vty; the suffix string follows it only in case
1844 * AS_PATH wasn't empty.
1847 aspath_print_vty (struct vty
*vty
, const char *format
, struct aspath
*as
, const char * suffix
)
1850 vty_out (vty
, format
, as
->str
);
1851 if (strlen (as
->str
) && strlen (suffix
))
1852 vty_out (vty
, "%s", suffix
);
1856 aspath_show_all_iterator (struct hash_backet
*backet
, struct vty
*vty
)
1860 as
= (struct aspath
*) backet
->data
;
1862 vty_out (vty
, "[%p:%u] (%ld) ", backet
, backet
->key
, as
->refcnt
);
1863 vty_out (vty
, "%s%s", as
->str
, VTY_NEWLINE
);
1866 /* Print all aspath and hash information. This function is used from
1867 `show ip bgp paths' command. */
1869 aspath_print_all_vty (struct vty
*vty
)
1871 hash_iterate (ashash
,
1872 (void (*) (struct hash_backet
*, void *))
1873 aspath_show_all_iterator
,