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
35 #include "bgpd/bgpd.h"
36 #include "bgpd/bgp_aspath.h"
37 #include "bgpd/bgp_debug.h"
38 #include "bgpd/bgp_attr.h"
40 /* Attr. Flags and Attr. Type Code. */
41 #define AS_HEADER_SIZE 2
43 /* Now FOUR octets are used for AS value. */
44 #define AS_VALUE_SIZE sizeof (as_t)
45 /* This is the old one */
46 #define AS16_VALUE_SIZE sizeof (as16_t)
48 /* Maximum protocol segment length value */
49 #define AS_SEGMENT_MAX 255
51 /* The following length and size macros relate specifically to Quagga's
52 * internal representation of AS-Segments, not per se to the on-wire
53 * sizes and lengths. At present (200508) they sort of match, however
54 * the ONLY functions which should now about the on-wire syntax are
55 * aspath_put, assegment_put and assegment_parse.
57 * aspath_put returns bytes written, the only definitive record of
58 * size of wire-format attribute..
61 /* Calculated size in bytes of ASN segment data to hold N ASN's */
62 #define ASSEGMENT_DATA_SIZE(N,S) \
63 ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )
65 /* Calculated size of segment struct to hold N ASN's */
66 #define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
68 /* AS segment octet length. */
69 #define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
71 /* AS_SEQUENCE segments can be packed together */
72 /* Can the types of X and Y be considered for packing? */
73 #define ASSEGMENT_TYPES_PACKABLE(X,Y) \
74 ( ((X)->type == (Y)->type) \
75 && ((X)->type == AS_SEQUENCE))
76 /* Types and length of X,Y suitable for packing? */
77 #define ASSEGMENTS_PACKABLE(X,Y) \
78 ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \
79 && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) )
81 /* As segment header - the on-wire representation
82 * NOT the internal representation!
84 struct assegment_header
90 /* Hash for aspath. This is the top level structure of AS path. */
91 static struct hash
*ashash
;
93 /* Stream for SNMP. See aspath_snmp_pathseg */
94 static struct stream
*snmp_stream
;
96 /* Callers are required to initialize the memory */
98 assegment_data_new (int num
)
100 return (XMALLOC (MTYPE_AS_SEG_DATA
, ASSEGMENT_DATA_SIZE (num
, 1)));
103 const char *aspath_segment_type_str
[] = {
107 "as-confed-sequence",
111 /* Get a new segment. Note that 0 is an allowed length,
112 * and will result in a segment with no allocated data segment.
113 * the caller should immediately assign data to the segment, as the segment
114 * otherwise is not generally valid
116 static struct assegment
*
117 assegment_new (u_char type
, u_short length
)
119 struct assegment
*new;
121 new = XCALLOC (MTYPE_AS_SEG
, sizeof (struct assegment
));
124 new->as
= assegment_data_new (length
);
126 new->length
= length
;
133 assegment_free (struct assegment
*seg
)
139 XFREE (MTYPE_AS_SEG_DATA
, seg
->as
);
140 memset (seg
, 0xfe, sizeof(struct assegment
));
141 XFREE (MTYPE_AS_SEG
, seg
);
146 /* free entire chain of segments */
148 assegment_free_all (struct assegment
*seg
)
150 struct assegment
*prev
;
156 assegment_free (prev
);
160 /* Duplicate just the given assegment and its data */
161 static struct assegment
*
162 assegment_dup (struct assegment
*seg
)
164 struct assegment
*new;
166 new = assegment_new (seg
->type
, seg
->length
);
167 memcpy (new->as
, seg
->as
, ASSEGMENT_DATA_SIZE (new->length
, 1) );
172 /* Duplicate entire chain of assegments, return the head */
173 static struct assegment
*
174 assegment_dup_all (struct assegment
*seg
)
176 struct assegment
*new = NULL
;
177 struct assegment
*head
= NULL
;
183 new->next
= assegment_dup (seg
);
187 head
= new = assegment_dup (seg
);
194 /* prepend the as number to given segment, given num of times */
195 static struct assegment
*
196 assegment_prepend_asns (struct assegment
*seg
, as_t asnum
, int num
)
204 if (num
>= AS_SEGMENT_MAX
)
205 return seg
; /* we don't do huge prepends */
207 newas
= assegment_data_new (seg
->length
+ num
);
209 for (i
= 0; i
< num
; i
++)
212 memcpy (newas
+ num
, seg
->as
, ASSEGMENT_DATA_SIZE (seg
->length
, 1));
213 XFREE (MTYPE_AS_SEG_DATA
, seg
->as
);
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
);
341 json_object_free(aspath
->json
);
345 XFREE (MTYPE_AS_PATH
, aspath
);
348 /* Unintern aspath from AS path bucket. */
350 aspath_unintern (struct aspath
**aspath
)
353 struct aspath
*asp
= *aspath
;
358 if (asp
->refcnt
== 0)
360 /* This aspath must exist in aspath hash table. */
361 ret
= hash_release (ashash
, asp
);
362 assert (ret
!= NULL
);
368 /* Return the start or end delimiters for a particular Segment type */
369 #define AS_SEG_START 0
372 aspath_delimiter_char (u_char type
, u_char which
)
380 } aspath_delim_char
[] =
382 { AS_SET
, '{', '}' },
383 { AS_CONFED_SET
, '[', ']' },
384 { AS_CONFED_SEQUENCE
, '(', ')' },
388 for (i
= 0; aspath_delim_char
[i
].type
!= 0; i
++)
390 if (aspath_delim_char
[i
].type
== type
)
392 if (which
== AS_SEG_START
)
393 return aspath_delim_char
[i
].start
;
394 else if (which
== AS_SEG_END
)
395 return aspath_delim_char
[i
].end
;
401 /* countup asns from this segment and index onward */
403 assegment_count_asns (struct assegment
*seg
, int from
)
409 count
+= seg
->length
;
412 count
+= (seg
->length
- from
);
421 aspath_count_confeds (struct aspath
*aspath
)
424 struct assegment
*seg
= aspath
->segments
;
428 if (seg
->type
== AS_CONFED_SEQUENCE
)
429 count
+= seg
->length
;
430 else if (seg
->type
== AS_CONFED_SET
)
439 aspath_count_hops (const struct aspath
*aspath
)
442 struct assegment
*seg
= aspath
->segments
;
446 if (seg
->type
== AS_SEQUENCE
)
447 count
+= seg
->length
;
448 else if (seg
->type
== AS_SET
)
456 /* Estimate size aspath /might/ take if encoded into an
459 * This is a quick estimate, not definitive! aspath_put()
460 * may return a different number!!
463 aspath_size (struct aspath
*aspath
)
466 struct assegment
*seg
= aspath
->segments
;
470 size
+= ASSEGMENT_SIZE(seg
->length
, 1);
476 /* Return highest public ASN in path */
478 aspath_highest (struct aspath
*aspath
)
480 struct assegment
*seg
= aspath
->segments
;
486 for (i
= 0; i
< seg
->length
; i
++)
487 if (seg
->as
[i
] > highest
&& !BGP_AS_IS_PRIVATE(seg
->as
[i
]))
488 highest
= seg
->as
[i
];
494 /* Return the left-most ASN in path */
496 aspath_leftmost (struct aspath
*aspath
)
498 struct assegment
*seg
= aspath
->segments
;
501 if (seg
&& seg
->length
&& seg
->type
== AS_SEQUENCE
)
502 leftmost
= seg
->as
[0];
507 /* Return 1 if there are any 4-byte ASes in the path */
509 aspath_has_as4 (struct aspath
*aspath
)
511 struct assegment
*seg
= aspath
->segments
;
516 for (i
= 0; i
< seg
->length
; i
++)
517 if (seg
->as
[i
] > BGP_AS_MAX
)
524 /* Convert aspath structure to string expression. */
526 aspath_make_str_count (struct aspath
*as
)
528 struct assegment
*seg
;
532 json_object
*jaspath_segments
= NULL
;
533 json_object
*jseg
= NULL
;
534 json_object
*jseg_list
= NULL
;
536 as
->json
= json_object_new_object();
537 jaspath_segments
= json_object_new_array();
542 json_object_string_add(as
->json
, "string", "Local");
543 json_object_object_add(as
->json
, "segments", jaspath_segments
);
544 json_object_int_add(as
->json
, "length", 0);
545 as
->str
= XMALLOC (MTYPE_AS_STR
, 1);
553 /* ASN takes 5 to 10 chars plus seperator, see below.
554 * If there is one differing segment type, we need an additional
555 * 2 chars for segment delimiters, and the final '\0'.
556 * Hopefully this is large enough to avoid hitting the realloc
557 * code below for most common sequences.
559 * This was changed to 10 after the well-known BGP assertion, which
560 * had hit some parts of the Internet in May of 2009.
562 #define ASN_STR_LEN (10 + 1)
563 str_size
= MAX (assegment_count_asns (seg
, 0) * ASN_STR_LEN
+ 2 + 1,
564 ASPATH_STR_DEFAULT_LEN
);
565 str_buf
= XMALLOC (MTYPE_AS_STR
, str_size
);
572 /* Check AS type validity. Set seperator for segment */
580 case AS_CONFED_SEQUENCE
:
584 XFREE (MTYPE_AS_STR
, str_buf
);
587 json_object_free(as
->json
);
592 /* We might need to increase str_buf, particularly if path has
593 * differing segments types, our initial guesstimate above will
594 * have been wrong. Need 10 chars for ASN, a seperator each and
595 * potentially two segment delimiters, plus a space between each
596 * segment and trailing zero.
598 * This definitely didn't work with the value of 5 bytes and
601 #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
602 if ( (len
+ SEGMENT_STR_LEN(seg
)) > str_size
)
604 str_size
= len
+ SEGMENT_STR_LEN(seg
);
605 str_buf
= XREALLOC (MTYPE_AS_STR
, str_buf
, str_size
);
608 #undef SEGMENT_STR_LEN
610 if (seg
->type
!= AS_SEQUENCE
)
611 len
+= snprintf (str_buf
+ len
, str_size
- len
,
613 aspath_delimiter_char (seg
->type
, AS_SEG_START
));
615 jseg_list
= json_object_new_array();
617 /* write out the ASNs, with their seperators, bar the last one*/
618 for (i
= 0; i
< seg
->length
; i
++)
620 json_object_array_add(jseg_list
, json_object_new_int(seg
->as
[i
]));
622 len
+= snprintf (str_buf
+ len
, str_size
- len
, "%u", seg
->as
[i
]);
624 if (i
< (seg
->length
- 1))
625 len
+= snprintf (str_buf
+ len
, str_size
- len
, "%c", seperator
);
628 jseg
= json_object_new_object();
629 json_object_string_add(jseg
, "type", aspath_segment_type_str
[seg
->type
]);
630 json_object_object_add(jseg
, "list", jseg_list
);
631 json_object_array_add(jaspath_segments
, jseg
);
633 if (seg
->type
!= AS_SEQUENCE
)
634 len
+= snprintf (str_buf
+ len
, str_size
- len
, "%c",
635 aspath_delimiter_char (seg
->type
, AS_SEG_END
));
637 len
+= snprintf (str_buf
+ len
, str_size
- len
, " ");
642 assert (len
< str_size
);
648 json_object_string_add(as
->json
, "string", str_buf
);
649 json_object_object_add(as
->json
, "segments", jaspath_segments
);
650 json_object_int_add(as
->json
, "length", aspath_count_hops (as
));
655 aspath_str_update (struct aspath
*as
)
658 XFREE (MTYPE_AS_STR
, as
->str
);
662 json_object_free(as
->json
);
666 aspath_make_str_count (as
);
669 /* Intern allocated AS path. */
671 aspath_intern (struct aspath
*aspath
)
675 /* Assert this AS path structure is not interned and has the string
676 representation built. */
677 assert (aspath
->refcnt
== 0);
678 assert (aspath
->str
);
680 /* Check AS path hash. */
681 find
= hash_get (ashash
, aspath
, hash_alloc_intern
);
683 aspath_free (aspath
);
690 /* Duplicate aspath structure. Created same aspath structure but
691 reference count and AS path string is cleared. */
693 aspath_dup (struct aspath
*aspath
)
695 unsigned short buflen
= aspath
->str_len
+ 1;
698 new = XCALLOC (MTYPE_AS_PATH
, sizeof (struct aspath
));
701 if (aspath
->segments
)
702 new->segments
= assegment_dup_all (aspath
->segments
);
707 new->str
= XMALLOC (MTYPE_AS_STR
, buflen
);
708 new->str_len
= aspath
->str_len
;
710 /* copy the string data */
711 if (aspath
->str_len
> 0)
712 memcpy (new->str
, aspath
->str
, buflen
);
720 aspath_hash_alloc (void *arg
)
722 const struct aspath
*aspath
= arg
;
725 /* Malformed AS path value. */
726 assert (aspath
->str
);
728 /* New aspath structure is needed. */
729 new = XMALLOC (MTYPE_AS_PATH
, sizeof (struct aspath
));
731 /* Reuse segments and string representation */
733 new->segments
= aspath
->segments
;
734 new->str
= aspath
->str
;
735 new->str_len
= aspath
->str_len
;
736 new->json
= aspath
->json
;
741 /* parse as-segment byte stream in struct assegment */
743 assegments_parse (struct stream
*s
, size_t length
,
744 struct assegment
**result
, int use32bit
)
746 struct assegment_header segh
;
747 struct assegment
*seg
, *prev
= NULL
, *head
= NULL
;
750 /* empty aspath (ie iBGP or somesuch) */
754 if (BGP_DEBUG (as4
, AS4_SEGMENT
))
755 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
756 (unsigned long) length
);
758 if ((STREAM_READABLE(s
) < length
)
759 || (STREAM_READABLE(s
) < AS_HEADER_SIZE
)
760 || (length
% AS16_VALUE_SIZE
))
763 while (bytes
< length
)
768 if ((length
- bytes
) <= AS_HEADER_SIZE
)
771 assegment_free_all (head
);
775 /* softly softly, get the header first on its own */
776 segh
.type
= stream_getc (s
);
777 segh
.length
= stream_getc (s
);
779 seg_size
= ASSEGMENT_SIZE(segh
.length
, use32bit
);
781 if (BGP_DEBUG (as4
, AS4_SEGMENT
))
782 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
783 segh
.type
, segh
.length
);
786 if ( ((bytes
+ seg_size
) > length
)
787 /* 1771bis 4.3b: seg length contains one or more */
788 || (segh
.length
== 0)
789 /* Paranoia in case someone changes type of segment length.
790 * Shift both values by 0x10 to make the comparison operate
791 * on more, than 8 bits (otherwise it's a warning, bug #564).
793 || ((sizeof segh
.length
> 1)
794 && (0x10 + segh
.length
> 0x10 + AS_SEGMENT_MAX
)))
797 assegment_free_all (head
);
805 case AS_CONFED_SEQUENCE
:
810 assegment_free_all (head
);
814 /* now its safe to trust lengths */
815 seg
= assegment_new (segh
.type
, segh
.length
);
819 else /* it's the first segment */
822 for (i
= 0; i
< segh
.length
; i
++)
823 seg
->as
[i
] = (use32bit
) ? stream_getl (s
) : stream_getw (s
);
827 if (BGP_DEBUG (as4
, AS4_SEGMENT
))
828 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
829 (unsigned long) bytes
);
834 *result
= assegment_normalise (head
);
838 /* AS path parse function. pnt is a pointer to byte stream and length
839 is length of byte stream. If there is same AS path in the the AS
840 path hash then return it else make new AS path structure.
842 On error NULL is returned.
845 aspath_parse (struct stream
*s
, size_t length
, int use32bit
)
850 /* If length is odd it's malformed AS path. */
851 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
852 * otherwise its malformed when length is larger than 2 and (length-2)
853 * is not dividable by 4.
854 * But... this time we're lazy
856 if (length
% AS16_VALUE_SIZE
)
859 memset (&as
, 0, sizeof (struct aspath
));
860 if (assegments_parse (s
, length
, &as
.segments
, use32bit
) < 0)
863 /* If already same aspath exist then return it. */
864 find
= hash_get (ashash
, &as
, aspath_hash_alloc
);
866 /* bug! should not happen, let the daemon crash below */
869 /* if the aspath was already hashed free temporary memory. */
872 assegment_free_all (as
.segments
);
873 /* aspath_key_make() always updates the string */
874 XFREE (MTYPE_AS_STR
, as
.str
);
877 json_object_free(as
.json
);
888 assegment_data_put (struct stream
*s
, as_t
*as
, int num
, int use32bit
)
891 assert (num
<= AS_SEGMENT_MAX
);
893 for (i
= 0; i
< num
; i
++)
895 stream_putl (s
, as
[i
]);
898 if ( as
[i
] <= BGP_AS_MAX
)
899 stream_putw(s
, as
[i
]);
901 stream_putw(s
, BGP_AS_TRANS
);
906 assegment_header_put (struct stream
*s
, u_char type
, int length
)
909 assert (length
<= AS_SEGMENT_MAX
);
910 stream_putc (s
, type
);
911 lenp
= stream_get_endp (s
);
912 stream_putc (s
, length
);
916 /* write aspath data to stream */
918 aspath_put (struct stream
*s
, struct aspath
*as
, int use32bit
)
920 struct assegment
*seg
= as
->segments
;
923 if (!seg
|| seg
->length
== 0)
929 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
930 * At the moment, we would write out a partial aspath, and our peer
931 * will complain and drop the session :-/
933 * The general assumption here is that many things tested will
934 * never happen. And, in real live, up to now, they have not.
936 while (seg
&& (ASSEGMENT_LEN(seg
, use32bit
) <= STREAM_WRITEABLE(s
)))
938 struct assegment
*next
= seg
->next
;
943 /* Overlength segments have to be split up */
944 while ( (seg
->length
- written
) > AS_SEGMENT_MAX
)
946 assegment_header_put (s
, seg
->type
, AS_SEGMENT_MAX
);
947 assegment_data_put (s
, seg
->as
, AS_SEGMENT_MAX
, use32bit
);
948 written
+= AS_SEGMENT_MAX
;
949 bytes
+= ASSEGMENT_SIZE (written
, use32bit
);
952 /* write the final segment, probably is also the first */
953 lenp
= assegment_header_put (s
, seg
->type
, seg
->length
- written
);
954 assegment_data_put (s
, (seg
->as
+ written
), seg
->length
- written
,
957 /* Sequence-type segments can be 'packed' together
958 * Case of a segment which was overlength and split up
959 * will be missed here, but that doesn't matter.
961 while (next
&& ASSEGMENTS_PACKABLE (seg
, next
))
963 /* NB: We should never normally get here given we
964 * normalise aspath data when parse them. However, better
965 * safe than sorry. We potentially could call
966 * assegment_normalise here instead, but it's cheaper and
967 * easier to do it on the fly here rather than go through
968 * the segment list twice every time we write out
972 /* Next segment's data can fit in this one */
973 assegment_data_put (s
, next
->as
, next
->length
, use32bit
);
975 /* update the length of the segment header */
976 stream_putc_at (s
, lenp
, seg
->length
- written
+ next
->length
);
977 asns_packed
+= next
->length
;
982 bytes
+= ASSEGMENT_SIZE (seg
->length
- written
+ asns_packed
,
990 /* This is for SNMP BGP4PATHATTRASPATHSEGMENT
991 * We have no way to manage the storage, so we use a static stream
992 * wrapper around aspath_put.
995 aspath_snmp_pathseg (struct aspath
*as
, size_t *varlen
)
997 #define SNMP_PATHSEG_MAX 1024
1000 snmp_stream
= stream_new (SNMP_PATHSEG_MAX
);
1002 stream_reset (snmp_stream
);
1009 aspath_put (snmp_stream
, as
, 0); /* use 16 bit for now here */
1011 *varlen
= stream_get_endp (snmp_stream
);
1012 return stream_pnt(snmp_stream
);
1015 #define min(A,B) ((A) < (B) ? (A) : (B))
1017 static struct assegment
*
1018 aspath_aggregate_as_set_add (struct aspath
*aspath
, struct assegment
*asset
,
1023 /* If this is first AS set member, create new as-set segment. */
1026 asset
= assegment_new (AS_SET
, 1);
1027 if (! aspath
->segments
)
1028 aspath
->segments
= asset
;
1031 struct assegment
*seg
= aspath
->segments
;
1036 asset
->type
= AS_SET
;
1042 /* Check this AS value already exists or not. */
1043 for (i
= 0; i
< asset
->length
; i
++)
1044 if (asset
->as
[i
] == as
)
1048 asset
->as
= XREALLOC (MTYPE_AS_SEG_DATA
, asset
->as
,
1049 asset
->length
* AS_VALUE_SIZE
);
1050 asset
->as
[asset
->length
- 1] = as
;
1057 /* Modify as1 using as2 for aggregation. */
1059 aspath_aggregate (struct aspath
*as1
, struct aspath
*as2
)
1065 struct assegment
*seg1
= as1
->segments
;
1066 struct assegment
*seg2
= as2
->segments
;
1067 struct aspath
*aspath
= NULL
;
1068 struct assegment
*asset
= NULL
;
1069 struct assegment
*prevseg
= NULL
;
1071 /* First of all check common leading sequence. */
1072 while (seg1
&& seg2
)
1074 /* Check segment type. */
1075 if (seg1
->type
!= seg2
->type
)
1078 /* Minimum segment length. */
1079 minlen
= min (seg1
->length
, seg2
->length
);
1081 for (match
= 0; match
< minlen
; match
++)
1082 if (seg1
->as
[match
] != seg2
->as
[match
])
1087 struct assegment
*seg
= assegment_new (seg1
->type
, 0);
1089 seg
= assegment_append_asns (seg
, seg1
->as
, match
);
1093 aspath
= aspath_new ();
1094 aspath
->segments
= seg
;
1097 prevseg
->next
= seg
;
1102 if (match
!= minlen
|| match
!= seg1
->length
1103 || seg1
->length
!= seg2
->length
)
1105 /* We are moving on to the next segment to reset match */
1114 aspath
= aspath_new();
1116 /* Make as-set using rest of all information. */
1120 for (i
= from
; i
< seg1
->length
; i
++)
1121 asset
= aspath_aggregate_as_set_add (aspath
, asset
, seg1
->as
[i
]);
1130 for (i
= from
; i
< seg2
->length
; i
++)
1131 asset
= aspath_aggregate_as_set_add (aspath
, asset
, seg2
->as
[i
]);
1137 assegment_normalise (aspath
->segments
);
1138 aspath_str_update (aspath
);
1142 /* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1143 attribute, check the leftmost AS number in the AS_PATH attribute is
1144 or not the peer's AS number. */
1146 aspath_firstas_check (struct aspath
*aspath
, as_t asno
)
1148 if ( (aspath
== NULL
) || (aspath
->segments
== NULL
) )
1151 if (aspath
->segments
1152 && (aspath
->segments
->type
== AS_SEQUENCE
)
1153 && (aspath
->segments
->as
[0] == asno
))
1160 aspath_get_firstas (struct aspath
*aspath
)
1162 if (aspath
== NULL
|| aspath
->segments
== NULL
)
1165 return aspath
->segments
->as
[0];
1168 /* AS path loop check. If aspath contains asno then return >= 1. */
1170 aspath_loop_check (struct aspath
*aspath
, as_t asno
)
1172 struct assegment
*seg
;
1175 if ( (aspath
== NULL
) || (aspath
->segments
== NULL
) )
1178 seg
= aspath
->segments
;
1184 for (i
= 0; i
< seg
->length
; i
++)
1185 if (seg
->as
[i
] == asno
)
1193 /* When all of AS path is private AS return 1. */
1195 aspath_private_as_check (struct aspath
*aspath
)
1197 struct assegment
*seg
;
1199 if ( !(aspath
&& aspath
->segments
) )
1202 seg
= aspath
->segments
;
1208 for (i
= 0; i
< seg
->length
; i
++)
1210 if (!BGP_AS_IS_PRIVATE(seg
->as
[i
]))
1218 /* Return True if the entire ASPATH consist of the specified ASN */
1220 aspath_single_asn_check (struct aspath
*aspath
, as_t asn
)
1222 struct assegment
*seg
;
1224 if ( !(aspath
&& aspath
->segments
) )
1227 seg
= aspath
->segments
;
1233 for (i
= 0; i
< seg
->length
; i
++)
1235 if (seg
->as
[i
] != asn
)
1243 /* Replace all instances of the target ASN with our own ASN */
1245 aspath_replace_specific_asn (struct aspath
*aspath
, as_t target_asn
,
1249 struct assegment
*seg
;
1251 new = aspath_dup(aspath
);
1252 seg
= new->segments
;
1258 for (i
= 0; i
< seg
->length
; i
++)
1260 if (seg
->as
[i
] == target_asn
)
1261 seg
->as
[i
] = our_asn
;
1266 aspath_str_update(new);
1270 /* Replace all private ASNs with our own ASN */
1272 aspath_replace_private_asns (struct aspath
*aspath
, as_t asn
)
1275 struct assegment
*seg
;
1277 new = aspath_dup(aspath
);
1278 seg
= new->segments
;
1284 for (i
= 0; i
< seg
->length
; i
++)
1286 if (BGP_AS_IS_PRIVATE(seg
->as
[i
]))
1292 aspath_str_update(new);
1296 /* Remove all private ASNs */
1298 aspath_remove_private_asns (struct aspath
*aspath
)
1301 struct assegment
*seg
;
1302 struct assegment
*new_seg
;
1303 struct assegment
*last_new_seg
;
1308 new = XCALLOC (MTYPE_AS_PATH
, sizeof (struct aspath
));
1312 last_new_seg
= NULL
;
1313 seg
= aspath
->segments
;
1317 for (i
= 0; i
< seg
->length
; i
++)
1320 if (!BGP_AS_IS_PRIVATE(seg
->as
[i
]))
1326 // The entire segment is private so skip it
1333 // The entire segment is public so copy it
1334 else if (public == seg
->length
)
1336 new_seg
= assegment_dup (seg
);
1339 // The segment is a mix of public and private ASNs. Copy as many spots as
1340 // there are public ASNs then come back and fill in only the public ASNs.
1343 new_seg
= assegment_new (seg
->type
, public);
1345 for (i
= 0; i
< seg
->length
; i
++)
1348 if (!BGP_AS_IS_PRIVATE(seg
->as
[i
]))
1350 new_seg
->as
[j
] = seg
->as
[i
];
1356 // This is the first segment so set the aspath segments pointer to this one
1358 new->segments
= new_seg
;
1360 last_new_seg
->next
= new_seg
;
1362 last_new_seg
= new_seg
;
1366 aspath_str_update(new);
1370 /* AS path confed check. If aspath contains confed set or sequence then return 1. */
1372 aspath_confed_check (struct aspath
*aspath
)
1374 struct assegment
*seg
;
1376 if ( !(aspath
&& aspath
->segments
) )
1379 seg
= aspath
->segments
;
1383 if (seg
->type
== AS_CONFED_SET
|| seg
->type
== AS_CONFED_SEQUENCE
)
1390 /* Leftmost AS path segment confed check. If leftmost AS segment is of type
1391 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1393 aspath_left_confed_check (struct aspath
*aspath
)
1396 if ( !(aspath
&& aspath
->segments
) )
1399 if ( (aspath
->segments
->type
== AS_CONFED_SEQUENCE
)
1400 || (aspath
->segments
->type
== AS_CONFED_SET
) )
1406 /* Merge as1 to as2. as2 should be uninterned aspath. */
1407 static struct aspath
*
1408 aspath_merge (struct aspath
*as1
, struct aspath
*as2
)
1410 struct assegment
*last
, *new;
1415 last
= new = assegment_dup_all (as1
->segments
);
1417 /* find the last valid segment */
1418 while (last
&& last
->next
)
1421 last
->next
= as2
->segments
;
1422 as2
->segments
= new;
1423 aspath_str_update (as2
);
1427 /* Prepend as1 to as2. as2 should be uninterned aspath. */
1429 aspath_prepend (struct aspath
*as1
, struct aspath
*as2
)
1431 struct assegment
*seg1
;
1432 struct assegment
*seg2
;
1437 seg1
= as1
->segments
;
1438 seg2
= as2
->segments
;
1440 /* If as2 is empty, only need to dupe as1's chain onto as2 */
1443 as2
->segments
= assegment_dup_all (as1
->segments
);
1444 aspath_str_update (as2
);
1448 /* If as1 is empty AS, no prepending to do. */
1452 /* find the tail as1's segment chain. */
1453 while (seg1
&& seg1
->next
)
1456 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1457 if (seg1
->type
== AS_SEQUENCE
&& seg2
->type
== AS_CONFED_SEQUENCE
)
1458 as2
= aspath_delete_confed_seq (as2
);
1460 /* Compare last segment type of as1 and first segment type of as2. */
1461 if (seg1
->type
!= seg2
->type
)
1462 return aspath_merge (as1
, as2
);
1464 if (seg1
->type
== AS_SEQUENCE
)
1466 /* We have two chains of segments, as1->segments and seg2,
1467 * and we have to attach them together, merging the attaching
1468 * segments together into one.
1470 * 1. dupe as1->segments onto head of as2
1471 * 2. merge seg2's asns onto last segment of this new chain
1472 * 3. attach chain after seg2
1475 /* dupe as1 onto as2's head */
1476 seg1
= as2
->segments
= assegment_dup_all (as1
->segments
);
1478 /* refind the tail of as2, reusing seg1 */
1479 while (seg1
&& seg1
->next
)
1482 /* merge the old head, seg2, into tail, seg1 */
1483 seg1
= assegment_append_asns (seg1
, seg2
->as
, seg2
->length
);
1485 /* bypass the merged seg2, and attach any chain after it to
1486 * chain descending from as2's head
1488 seg1
->next
= seg2
->next
;
1490 /* seg2 is now referenceless and useless*/
1491 assegment_free (seg2
);
1493 /* we've now prepended as1's segment chain to as2, merging
1494 * the inbetween AS_SEQUENCE of seg2 in the process
1496 aspath_str_update (as2
);
1501 /* AS_SET merge code is needed at here. */
1502 return aspath_merge (as1
, as2
);
1504 /* XXX: Ermmm, what if as1 has multiple segments?? */
1509 /* Iterate over AS_PATH segments and wipe all occurences of the
1510 * listed AS numbers. Hence some segments may lose some or even
1511 * all data on the way, the operation is implemented as a smarter
1512 * version of aspath_dup(), which allocates memory to hold the new
1513 * data, not the original. The new AS path is returned.
1516 aspath_filter_exclude (struct aspath
* source
, struct aspath
* exclude_list
)
1518 struct assegment
* srcseg
, * exclseg
, * lastseg
;
1519 struct aspath
* newpath
;
1521 newpath
= aspath_new();
1524 for (srcseg
= source
->segments
; srcseg
; srcseg
= srcseg
->next
)
1526 unsigned i
, y
, newlen
= 0, done
= 0, skip_as
;
1527 struct assegment
* newseg
;
1529 /* Find out, how much ASns are we going to pick from this segment.
1530 * We can't perform filtering right inline, because the size of
1531 * the new segment isn't known at the moment yet.
1533 for (i
= 0; i
< srcseg
->length
; i
++)
1536 for (exclseg
= exclude_list
->segments
; exclseg
&& !skip_as
; exclseg
= exclseg
->next
)
1537 for (y
= 0; y
< exclseg
->length
; y
++)
1538 if (srcseg
->as
[i
] == exclseg
->as
[y
])
1541 // There's no sense in testing the rest of exclusion list, bail out.
1547 /* newlen is now the number of ASns to copy */
1551 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1552 newseg
= assegment_new (srcseg
->type
, newlen
);
1553 for (i
= 0; i
< srcseg
->length
; i
++)
1556 for (exclseg
= exclude_list
->segments
; exclseg
&& !skip_as
; exclseg
= exclseg
->next
)
1557 for (y
= 0; y
< exclseg
->length
; y
++)
1558 if (srcseg
->as
[i
] == exclseg
->as
[y
])
1565 newseg
->as
[done
++] = srcseg
->as
[i
];
1567 /* At his point newlen must be equal to done, and both must be positive. Append
1568 * the filtered segment to the gross result. */
1570 newpath
->segments
= newseg
;
1572 lastseg
->next
= newseg
;
1575 aspath_str_update (newpath
);
1576 /* We are happy returning even an empty AS_PATH, because the administrator
1577 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1578 * by having a match rule against certain AS_PATH regexps in the route-map index.
1580 aspath_free (source
);
1584 /* Add specified AS to the leftmost of aspath. */
1585 static struct aspath
*
1586 aspath_add_asns (struct aspath
*aspath
, as_t asno
, u_char type
, unsigned num
)
1588 struct assegment
*assegment
= aspath
->segments
;
1591 if (assegment
&& assegment
->type
== type
)
1593 /* extend existing segment */
1594 aspath
->segments
= assegment_prepend_asns (aspath
->segments
, asno
, num
);
1598 /* prepend with new segment */
1599 struct assegment
*newsegment
= assegment_new (type
, num
);
1600 for (i
= 0; i
< num
; i
++)
1601 newsegment
->as
[i
] = asno
;
1603 /* insert potentially replacing empty segment */
1604 if (assegment
&& assegment
->length
== 0)
1606 newsegment
->next
= assegment
->next
;
1607 assegment_free (assegment
);
1610 newsegment
->next
= assegment
;
1611 aspath
->segments
= newsegment
;
1614 aspath_str_update (aspath
);
1618 /* Add specified AS to the leftmost of aspath num times. */
1620 aspath_add_seq_n (struct aspath
*aspath
, as_t asno
, unsigned num
)
1622 return aspath_add_asns (aspath
, asno
, AS_SEQUENCE
, num
);
1625 /* Add specified AS to the leftmost of aspath. */
1627 aspath_add_seq (struct aspath
*aspath
, as_t asno
)
1629 return aspath_add_asns (aspath
, asno
, AS_SEQUENCE
, 1);
1632 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1633 as2's leftmost AS is same return 1. */
1635 aspath_cmp_left (const struct aspath
*aspath1
, const struct aspath
*aspath2
)
1637 const struct assegment
*seg1
;
1638 const struct assegment
*seg2
;
1640 if (!(aspath1
&& aspath2
))
1643 seg1
= aspath1
->segments
;
1644 seg2
= aspath2
->segments
;
1646 /* If both paths are originated in this AS then we do want to compare MED */
1650 /* find first non-confed segments for each */
1651 while (seg1
&& ((seg1
->type
== AS_CONFED_SEQUENCE
)
1652 || (seg1
->type
== AS_CONFED_SET
)))
1655 while (seg2
&& ((seg2
->type
== AS_CONFED_SEQUENCE
)
1656 || (seg2
->type
== AS_CONFED_SET
)))
1661 && (seg1
->type
== AS_SEQUENCE
) && (seg2
->type
== AS_SEQUENCE
)))
1664 if (seg1
->as
[0] == seg2
->as
[0])
1670 /* Truncate an aspath after a number of hops, and put the hops remaining
1671 * at the front of another aspath. Needed for AS4 compat.
1673 * Returned aspath is a /new/ aspath, which should either by free'd or
1674 * interned by the caller, as desired.
1677 aspath_reconcile_as4 ( struct aspath
*aspath
, struct aspath
*as4path
)
1679 struct assegment
*seg
, *newseg
, *prevseg
= NULL
;
1680 struct aspath
*newpath
= NULL
, *mergedpath
;
1681 int hops
, cpasns
= 0;
1686 seg
= aspath
->segments
;
1688 /* CONFEDs should get reconciled too.. */
1689 hops
= (aspath_count_hops (aspath
) + aspath_count_confeds (aspath
))
1690 - aspath_count_hops (as4path
);
1694 if (BGP_DEBUG (as4
, AS4
))
1695 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1696 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1697 * which is daft behaviour - it contains vital loop-detection
1698 * information which must have been removed from AS_PATH.
1700 hops
= aspath_count_hops (aspath
);
1705 newpath
= aspath_dup (as4path
);
1706 aspath_str_update(newpath
);
1710 if ( BGP_DEBUG(as4
, AS4
))
1711 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1712 aspath
->str
, as4path
->str
);
1714 while (seg
&& hops
> 0)
1721 cpasns
= seg
->length
;
1723 case AS_CONFED_SEQUENCE
:
1724 /* Should never split a confed-sequence, if hop-count
1725 * suggests we must then something's gone wrong somewhere.
1727 * Most important goal is to preserve AS_PATHs prime function
1728 * as loop-detector, so we fudge the numbers so that the entire
1729 * confed-sequence is merged in.
1731 if (hops
< seg
->length
)
1733 if (BGP_DEBUG (as4
, AS4
))
1734 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1735 " across 2/4 ASN boundary somewhere, broken..");
1739 cpasns
= MIN(seg
->length
, hops
);
1740 hops
-= seg
->length
;
1743 assert (cpasns
<= seg
->length
);
1745 newseg
= assegment_new (seg
->type
, 0);
1746 newseg
= assegment_append_asns (newseg
, seg
->as
, cpasns
);
1750 newpath
= aspath_new ();
1751 newpath
->segments
= newseg
;
1754 prevseg
->next
= newseg
;
1760 /* We may be able to join some segments here, and we must
1761 * do this because... we want normalised aspaths in out hash
1762 * and we do not want to stumble in aspath_put.
1764 mergedpath
= aspath_merge (newpath
, aspath_dup(as4path
));
1765 aspath_free (newpath
);
1766 mergedpath
->segments
= assegment_normalise (mergedpath
->segments
);
1767 aspath_str_update (mergedpath
);
1769 if ( BGP_DEBUG(as4
, AS4
))
1770 zlog_debug ("[AS4] result of synthesizing is %s",
1776 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1777 as2's leftmost AS is same return 1. (confederation as-path
1780 aspath_cmp_left_confed (const struct aspath
*aspath1
, const struct aspath
*aspath2
)
1782 if (! (aspath1
&& aspath2
) )
1785 if ( !(aspath1
->segments
&& aspath2
->segments
) )
1788 if ( (aspath1
->segments
->type
!= AS_CONFED_SEQUENCE
)
1789 || (aspath2
->segments
->type
!= AS_CONFED_SEQUENCE
) )
1792 if (aspath1
->segments
->as
[0] == aspath2
->segments
->as
[0])
1798 /* Delete all AS_CONFED_SEQUENCE/SET segments from aspath.
1799 * RFC 5065 section 4.1.c.1
1801 * 1) if any path segments of the AS_PATH are of the type
1802 * AS_CONFED_SEQUENCE or AS_CONFED_SET, those segments MUST be
1803 * removed from the AS_PATH attribute, leaving the sanitized
1804 * AS_PATH attribute to be operated on by steps 2, 3 or 4.
1807 aspath_delete_confed_seq (struct aspath
*aspath
)
1809 struct assegment
*seg
, *prev
, *next
;
1810 char removed_confed_segment
;
1812 if (!(aspath
&& aspath
->segments
))
1815 seg
= aspath
->segments
;
1816 removed_confed_segment
= 0;
1824 if (seg
->type
== AS_CONFED_SEQUENCE
|| seg
->type
== AS_CONFED_SET
)
1826 /* This is the first segment in the aspath */
1827 if (aspath
->segments
== seg
)
1828 aspath
->segments
= seg
->next
;
1830 prev
->next
= seg
->next
;
1832 assegment_free (seg
);
1833 removed_confed_segment
= 1;
1841 if (removed_confed_segment
)
1842 aspath_str_update (aspath
);
1847 /* Add new AS number to the leftmost part of the aspath as
1848 AS_CONFED_SEQUENCE. */
1850 aspath_add_confed_seq (struct aspath
*aspath
, as_t asno
)
1852 return aspath_add_asns (aspath
, asno
, AS_CONFED_SEQUENCE
, 1);
1855 /* Add new as value to as path structure. */
1857 aspath_as_add (struct aspath
*as
, as_t asno
)
1859 struct assegment
*seg
= as
->segments
;
1864 /* Last segment search procedure. */
1868 assegment_append_asns (seg
, &asno
, 1);
1871 /* Add new as segment to the as path. */
1873 aspath_segment_add (struct aspath
*as
, int type
)
1875 struct assegment
*seg
= as
->segments
;
1876 struct assegment
*new = assegment_new (type
, 0);
1891 return aspath_parse (NULL
, 0, 1); /* 32Bit ;-) */
1895 aspath_empty_get (void)
1897 struct aspath
*aspath
;
1899 aspath
= aspath_new ();
1900 aspath_make_str_count (aspath
);
1907 return ashash
->count
;
1911 Theoretically, one as path can have:
1913 One BGP packet size should be less than 4096.
1914 One BGP attribute size should be less than 4096 - BGP header size.
1915 One BGP aspath size should be less than 4096 - BGP header size -
1916 BGP mandantry attribute size.
1919 /* AS path string lexical token enum. */
1925 as_token_confed_seq_start
,
1926 as_token_confed_seq_end
,
1927 as_token_confed_set_start
,
1928 as_token_confed_set_end
,
1932 /* Return next token and point for string parse. */
1934 aspath_gettoken (const char *buf
, enum as_token
*token
, u_long
*asno
)
1936 const char *p
= buf
;
1938 /* Skip seperators (space for sequences, ',' for sets). */
1939 while (isspace ((int) *p
) || *p
== ',')
1942 /* Check the end of the string and type specify characters
1949 *token
= as_token_set_start
;
1953 *token
= as_token_set_end
;
1957 *token
= as_token_confed_seq_start
;
1961 *token
= as_token_confed_seq_end
;
1965 *token
= as_token_confed_set_start
;
1969 *token
= as_token_confed_set_end
;
1974 /* Check actual AS value. */
1975 if (isdigit ((int) *p
))
1979 *token
= as_token_asval
;
1983 while (isdigit ((int) *p
))
1986 asval
+= (*p
- '0');
1993 /* There is no match then return unknown token. */
1994 *token
= as_token_unknown
;
1999 aspath_str2aspath (const char *str
)
2001 enum as_token token
= as_token_unknown
;
2004 struct aspath
*aspath
;
2007 aspath
= aspath_new ();
2009 /* We start default type as AS_SEQUENCE. */
2010 as_type
= AS_SEQUENCE
;
2013 while ((str
= aspath_gettoken (str
, &token
, &asno
)) != NULL
)
2017 case as_token_asval
:
2020 aspath_segment_add (aspath
, as_type
);
2023 aspath_as_add (aspath
, asno
);
2025 case as_token_set_start
:
2027 aspath_segment_add (aspath
, as_type
);
2030 case as_token_set_end
:
2031 as_type
= AS_SEQUENCE
;
2034 case as_token_confed_seq_start
:
2035 as_type
= AS_CONFED_SEQUENCE
;
2036 aspath_segment_add (aspath
, as_type
);
2039 case as_token_confed_seq_end
:
2040 as_type
= AS_SEQUENCE
;
2043 case as_token_confed_set_start
:
2044 as_type
= AS_CONFED_SET
;
2045 aspath_segment_add (aspath
, as_type
);
2048 case as_token_confed_set_end
:
2049 as_type
= AS_SEQUENCE
;
2052 case as_token_unknown
:
2054 aspath_free (aspath
);
2059 aspath_make_str_count (aspath
);
2064 /* Make hash value by raw aspath data. */
2066 aspath_key_make (void *p
)
2068 struct aspath
*aspath
= (struct aspath
*) p
;
2069 unsigned int key
= 0;
2072 aspath_str_update (aspath
);
2074 key
= jhash (aspath
->str
, aspath
->str_len
, 2334325);
2079 /* If two aspath have same value then return 1 else return 0 */
2081 aspath_cmp (const void *arg1
, const void *arg2
)
2083 const struct assegment
*seg1
= ((const struct aspath
*)arg1
)->segments
;
2084 const struct assegment
*seg2
= ((const struct aspath
*)arg2
)->segments
;
2086 while (seg1
|| seg2
)
2089 if ((!seg1
&& seg2
) || (seg1
&& !seg2
))
2091 if (seg1
->type
!= seg2
->type
)
2093 if (seg1
->length
!= seg2
->length
)
2095 for (i
= 0; i
< seg1
->length
; i
++)
2096 if (seg1
->as
[i
] != seg2
->as
[i
])
2104 /* AS path hash initialize. */
2108 ashash
= hash_create_size (32768, aspath_key_make
, aspath_cmp
);
2112 aspath_finish (void)
2118 stream_free (snmp_stream
);
2121 /* return and as path value */
2123 aspath_print (struct aspath
*as
)
2125 return (as
? as
->str
: NULL
);
2128 /* Printing functions */
2129 /* Feed the AS_PATH to the vty; the suffix string follows it only in case
2130 * AS_PATH wasn't empty.
2133 aspath_print_vty (struct vty
*vty
, const char *format
, struct aspath
*as
, const char * suffix
)
2136 vty_out (vty
, format
, as
->str
);
2137 if (as
->str_len
&& strlen (suffix
))
2138 vty_out (vty
, "%s", suffix
);
2142 aspath_show_all_iterator (struct hash_backet
*backet
, struct vty
*vty
)
2146 as
= (struct aspath
*) backet
->data
;
2148 vty_out (vty
, "[%p:%u] (%ld) ", (void *)backet
, backet
->key
, as
->refcnt
);
2149 vty_out (vty
, "%s%s", as
->str
, VTY_NEWLINE
);
2152 /* Print all aspath and hash information. This function is used from
2153 `show ip bgp paths' command. */
2155 aspath_print_all_vty (struct vty
*vty
)
2157 hash_iterate (ashash
,
2158 (void (*) (struct hash_backet
*, void *))
2159 aspath_show_all_iterator
,