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)));
102 const char *aspath_segment_type_str
[] = {
106 "as-confed-sequence",
110 /* Get a new segment. Note that 0 is an allowed length,
111 * and will result in a segment with no allocated data segment.
112 * the caller should immediately assign data to the segment, as the segment
113 * otherwise is not generally valid
115 static struct assegment
*
116 assegment_new (u_char type
, u_short length
)
118 struct assegment
*new;
120 new = XCALLOC (MTYPE_AS_SEG
, sizeof (struct assegment
));
123 new->as
= assegment_data_new (length
);
125 new->length
= length
;
132 assegment_free (struct assegment
*seg
)
138 XFREE (MTYPE_AS_SEG_DATA
, seg
->as
);
139 memset (seg
, 0xfe, sizeof(struct assegment
));
140 XFREE (MTYPE_AS_SEG
, seg
);
145 /* free entire chain of segments */
147 assegment_free_all (struct assegment
*seg
)
149 struct assegment
*prev
;
155 assegment_free (prev
);
159 /* Duplicate just the given assegment and its data */
160 static struct assegment
*
161 assegment_dup (struct assegment
*seg
)
163 struct assegment
*new;
165 new = assegment_new (seg
->type
, seg
->length
);
166 memcpy (new->as
, seg
->as
, ASSEGMENT_DATA_SIZE (new->length
, 1) );
171 /* Duplicate entire chain of assegments, return the head */
172 static struct assegment
*
173 assegment_dup_all (struct assegment
*seg
)
175 struct assegment
*new = NULL
;
176 struct assegment
*head
= NULL
;
182 new->next
= assegment_dup (seg
);
186 head
= new = assegment_dup (seg
);
193 /* prepend the as number to given segment, given num of times */
194 static struct assegment
*
195 assegment_prepend_asns (struct assegment
*seg
, as_t asnum
, int num
)
203 if (num
>= AS_SEGMENT_MAX
)
204 return seg
; /* we don't do huge prepends */
206 newas
= assegment_data_new (seg
->length
+ num
);
208 for (i
= 0; i
< num
; i
++)
211 memcpy (newas
+ num
, seg
->as
, ASSEGMENT_DATA_SIZE (seg
->length
, 1));
212 XFREE (MTYPE_AS_SEG_DATA
, seg
->as
);
219 /* append given array of as numbers to the segment */
220 static struct assegment
*
221 assegment_append_asns (struct assegment
*seg
, as_t
*asnos
, int num
)
225 newas
= XREALLOC (MTYPE_AS_SEG_DATA
, seg
->as
,
226 ASSEGMENT_DATA_SIZE (seg
->length
+ num
, 1));
231 memcpy (seg
->as
+ seg
->length
, asnos
, ASSEGMENT_DATA_SIZE(num
, 1));
236 assegment_free_all (seg
);
241 int_cmp (const void *p1
, const void *p2
)
243 const as_t
*as1
= p1
;
244 const as_t
*as2
= p2
;
246 return (*as1
== *as2
)
247 ? 0 : ( (*as1
> *as2
) ? 1 : -1);
250 /* normalise the segment.
251 * In particular, merge runs of AS_SEQUENCEs into one segment
252 * Internally, we do not care about the wire segment length limit, and
253 * we want each distinct AS_PATHs to have the exact same internal
254 * representation - eg, so that our hashing actually works..
256 static struct assegment
*
257 assegment_normalise (struct assegment
*head
)
259 struct assegment
*seg
= head
, *pin
;
260 struct assegment
*tmp
;
269 /* Sort values SET segments, for determinism in paths to aid
270 * creation of hash values / path comparisons
271 * and because it helps other lesser implementations ;)
273 if (seg
->type
== AS_SET
|| seg
->type
== AS_CONFED_SET
)
278 qsort (seg
->as
, seg
->length
, sizeof(as_t
), int_cmp
);
281 for (i
=1; i
< seg
->length
; i
++)
283 if (seg
->as
[tail
] == seg
->as
[i
])
288 seg
->as
[tail
] = seg
->as
[i
];
290 /* seg->length can be 0.. */
292 seg
->length
= tail
+ 1;
295 /* read ahead from the current, pinned segment while the segments
296 * are packable/mergeable. Append all following packable segments
297 * to the segment we have pinned and remove these appended
300 while (pin
->next
&& ASSEGMENT_TYPES_PACKABLE(pin
, pin
->next
))
305 /* append the next sequence to the pinned sequence */
306 pin
= assegment_append_asns (pin
, seg
->as
, seg
->length
);
308 /* bypass the next sequence */
309 pin
->next
= seg
->next
;
311 /* get rid of the now referenceless segment */
312 assegment_free (tmp
);
321 static struct aspath
*
324 return XCALLOC (MTYPE_AS_PATH
, sizeof (struct aspath
));
327 /* Free AS path structure. */
329 aspath_free (struct aspath
*aspath
)
333 if (aspath
->segments
)
334 assegment_free_all (aspath
->segments
);
336 XFREE (MTYPE_AS_STR
, aspath
->str
);
340 json_object_free(aspath
->json
);
344 XFREE (MTYPE_AS_PATH
, aspath
);
347 /* Unintern aspath from AS path bucket. */
349 aspath_unintern (struct aspath
**aspath
)
352 struct aspath
*asp
= *aspath
;
357 if (asp
->refcnt
== 0)
359 /* This aspath must exist in aspath hash table. */
360 ret
= hash_release (ashash
, asp
);
361 assert (ret
!= NULL
);
367 /* Return the start or end delimiters for a particular Segment type */
368 #define AS_SEG_START 0
371 aspath_delimiter_char (u_char type
, u_char which
)
379 } aspath_delim_char
[] =
381 { AS_SET
, '{', '}' },
382 { AS_CONFED_SET
, '[', ']' },
383 { AS_CONFED_SEQUENCE
, '(', ')' },
387 for (i
= 0; aspath_delim_char
[i
].type
!= 0; i
++)
389 if (aspath_delim_char
[i
].type
== type
)
391 if (which
== AS_SEG_START
)
392 return aspath_delim_char
[i
].start
;
393 else if (which
== AS_SEG_END
)
394 return aspath_delim_char
[i
].end
;
400 /* countup asns from this segment and index onward */
402 assegment_count_asns (struct assegment
*seg
, int from
)
408 count
+= seg
->length
;
411 count
+= (seg
->length
- from
);
420 aspath_count_confeds (struct aspath
*aspath
)
423 struct assegment
*seg
= aspath
->segments
;
427 if (seg
->type
== AS_CONFED_SEQUENCE
)
428 count
+= seg
->length
;
429 else if (seg
->type
== AS_CONFED_SET
)
438 aspath_count_hops (const struct aspath
*aspath
)
441 struct assegment
*seg
= aspath
->segments
;
445 if (seg
->type
== AS_SEQUENCE
)
446 count
+= seg
->length
;
447 else if (seg
->type
== AS_SET
)
455 /* Estimate size aspath /might/ take if encoded into an
458 * This is a quick estimate, not definitive! aspath_put()
459 * may return a different number!!
462 aspath_size (struct aspath
*aspath
)
465 struct assegment
*seg
= aspath
->segments
;
469 size
+= ASSEGMENT_SIZE(seg
->length
, 1);
475 /* Return highest public ASN in path */
477 aspath_highest (struct aspath
*aspath
)
479 struct assegment
*seg
= aspath
->segments
;
485 for (i
= 0; i
< seg
->length
; i
++)
486 if (seg
->as
[i
] > highest
&& !BGP_AS_IS_PRIVATE(seg
->as
[i
]))
487 highest
= seg
->as
[i
];
493 /* Return the left-most ASN in path */
495 aspath_leftmost (struct aspath
*aspath
)
497 struct assegment
*seg
= aspath
->segments
;
500 if (seg
&& seg
->length
&& seg
->type
== AS_SEQUENCE
)
501 leftmost
= seg
->as
[0];
506 /* Return 1 if there are any 4-byte ASes in the path */
508 aspath_has_as4 (struct aspath
*aspath
)
510 struct assegment
*seg
= aspath
->segments
;
515 for (i
= 0; i
< seg
->length
; i
++)
516 if (seg
->as
[i
] > BGP_AS_MAX
)
523 /* Convert aspath structure to string expression. */
525 aspath_make_str_count (struct aspath
*as
)
527 struct assegment
*seg
;
531 json_object
*jaspath_segments
= NULL
;
532 json_object
*jseg
= NULL
;
533 json_object
*jseg_list
= NULL
;
535 as
->json
= json_object_new_object();
536 jaspath_segments
= json_object_new_array();
541 json_object_string_add(as
->json
, "string", "Local");
542 json_object_object_add(as
->json
, "segments", jaspath_segments
);
543 json_object_int_add(as
->json
, "length", 0);
544 as
->str
= XMALLOC (MTYPE_AS_STR
, 1);
552 /* ASN takes 5 to 10 chars plus seperator, see below.
553 * If there is one differing segment type, we need an additional
554 * 2 chars for segment delimiters, and the final '\0'.
555 * Hopefully this is large enough to avoid hitting the realloc
556 * code below for most common sequences.
558 * This was changed to 10 after the well-known BGP assertion, which
559 * had hit some parts of the Internet in May of 2009.
561 #define ASN_STR_LEN (10 + 1)
562 str_size
= MAX (assegment_count_asns (seg
, 0) * ASN_STR_LEN
+ 2 + 1,
563 ASPATH_STR_DEFAULT_LEN
);
564 str_buf
= XMALLOC (MTYPE_AS_STR
, str_size
);
571 /* Check AS type validity. Set seperator for segment */
579 case AS_CONFED_SEQUENCE
:
583 XFREE (MTYPE_AS_STR
, str_buf
);
586 json_object_free(as
->json
);
591 /* We might need to increase str_buf, particularly if path has
592 * differing segments types, our initial guesstimate above will
593 * have been wrong. Need 10 chars for ASN, a seperator each and
594 * potentially two segment delimiters, plus a space between each
595 * segment and trailing zero.
597 * This definitely didn't work with the value of 5 bytes and
600 #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
601 if ( (len
+ SEGMENT_STR_LEN(seg
)) > str_size
)
603 str_size
= len
+ SEGMENT_STR_LEN(seg
);
604 str_buf
= XREALLOC (MTYPE_AS_STR
, str_buf
, str_size
);
607 #undef SEGMENT_STR_LEN
609 if (seg
->type
!= AS_SEQUENCE
)
610 len
+= snprintf (str_buf
+ len
, str_size
- len
,
612 aspath_delimiter_char (seg
->type
, AS_SEG_START
));
614 jseg_list
= json_object_new_array();
616 /* write out the ASNs, with their seperators, bar the last one*/
617 for (i
= 0; i
< seg
->length
; i
++)
619 json_object_array_add(jseg_list
, json_object_new_int(seg
->as
[i
]));
621 len
+= snprintf (str_buf
+ len
, str_size
- len
, "%u", seg
->as
[i
]);
623 if (i
< (seg
->length
- 1))
624 len
+= snprintf (str_buf
+ len
, str_size
- len
, "%c", seperator
);
627 jseg
= json_object_new_object();
628 json_object_string_add(jseg
, "type", aspath_segment_type_str
[seg
->type
]);
629 json_object_object_add(jseg
, "list", jseg_list
);
630 json_object_array_add(jaspath_segments
, jseg
);
632 if (seg
->type
!= AS_SEQUENCE
)
633 len
+= snprintf (str_buf
+ len
, str_size
- len
, "%c",
634 aspath_delimiter_char (seg
->type
, AS_SEG_END
));
636 len
+= snprintf (str_buf
+ len
, str_size
- len
, " ");
641 assert (len
< str_size
);
647 json_object_string_add(as
->json
, "string", str_buf
);
648 json_object_object_add(as
->json
, "segments", jaspath_segments
);
649 json_object_int_add(as
->json
, "length", aspath_count_hops (as
));
654 aspath_str_update (struct aspath
*as
)
657 XFREE (MTYPE_AS_STR
, as
->str
);
661 json_object_free(as
->json
);
665 aspath_make_str_count (as
);
668 /* Intern allocated AS path. */
670 aspath_intern (struct aspath
*aspath
)
674 /* Assert this AS path structure is not interned and has the string
675 representation built. */
676 assert (aspath
->refcnt
== 0);
677 assert (aspath
->str
);
679 /* Check AS path hash. */
680 find
= hash_get (ashash
, aspath
, hash_alloc_intern
);
682 aspath_free (aspath
);
689 /* Duplicate aspath structure. Created same aspath structure but
690 reference count and AS path string is cleared. */
692 aspath_dup (struct aspath
*aspath
)
694 unsigned short buflen
= aspath
->str_len
+ 1;
697 new = XCALLOC (MTYPE_AS_PATH
, sizeof (struct aspath
));
700 if (aspath
->segments
)
701 new->segments
= assegment_dup_all (aspath
->segments
);
706 new->str
= XMALLOC (MTYPE_AS_STR
, buflen
);
707 new->str_len
= aspath
->str_len
;
709 /* copy the string data */
710 if (aspath
->str_len
> 0)
711 memcpy (new->str
, aspath
->str
, buflen
);
719 aspath_hash_alloc (void *arg
)
721 const struct aspath
*aspath
= arg
;
724 /* Malformed AS path value. */
725 assert (aspath
->str
);
727 /* New aspath structure is needed. */
728 new = XMALLOC (MTYPE_AS_PATH
, sizeof (struct aspath
));
730 /* Reuse segments and string representation */
732 new->segments
= aspath
->segments
;
733 new->str
= aspath
->str
;
734 new->str_len
= aspath
->str_len
;
735 new->json
= aspath
->json
;
740 /* parse as-segment byte stream in struct assegment */
742 assegments_parse (struct stream
*s
, size_t length
,
743 struct assegment
**result
, int use32bit
)
745 struct assegment_header segh
;
746 struct assegment
*seg
, *prev
= NULL
, *head
= NULL
;
749 /* empty aspath (ie iBGP or somesuch) */
753 if (BGP_DEBUG (as4
, AS4_SEGMENT
))
754 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
755 (unsigned long) length
);
757 if ((STREAM_READABLE(s
) < length
)
758 || (STREAM_READABLE(s
) < AS_HEADER_SIZE
)
759 || (length
% AS16_VALUE_SIZE
))
762 while (bytes
< length
)
767 if ((length
- bytes
) <= AS_HEADER_SIZE
)
770 assegment_free_all (head
);
774 /* softly softly, get the header first on its own */
775 segh
.type
= stream_getc (s
);
776 segh
.length
= stream_getc (s
);
778 seg_size
= ASSEGMENT_SIZE(segh
.length
, use32bit
);
780 if (BGP_DEBUG (as4
, AS4_SEGMENT
))
781 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
782 segh
.type
, segh
.length
);
785 if ( ((bytes
+ seg_size
) > length
)
786 /* 1771bis 4.3b: seg length contains one or more */
787 || (segh
.length
== 0)
788 /* Paranoia in case someone changes type of segment length.
789 * Shift both values by 0x10 to make the comparison operate
790 * on more, than 8 bits (otherwise it's a warning, bug #564).
792 || ((sizeof segh
.length
> 1)
793 && (0x10 + segh
.length
> 0x10 + AS_SEGMENT_MAX
)))
796 assegment_free_all (head
);
804 case AS_CONFED_SEQUENCE
:
809 assegment_free_all (head
);
813 /* now its safe to trust lengths */
814 seg
= assegment_new (segh
.type
, segh
.length
);
818 else /* it's the first segment */
821 for (i
= 0; i
< segh
.length
; i
++)
822 seg
->as
[i
] = (use32bit
) ? stream_getl (s
) : stream_getw (s
);
826 if (BGP_DEBUG (as4
, AS4_SEGMENT
))
827 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
828 (unsigned long) bytes
);
833 *result
= assegment_normalise (head
);
837 /* AS path parse function. pnt is a pointer to byte stream and length
838 is length of byte stream. If there is same AS path in the the AS
839 path hash then return it else make new AS path structure.
841 On error NULL is returned.
844 aspath_parse (struct stream
*s
, size_t length
, int use32bit
)
849 /* If length is odd it's malformed AS path. */
850 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
851 * otherwise its malformed when length is larger than 2 and (length-2)
852 * is not dividable by 4.
853 * But... this time we're lazy
855 if (length
% AS16_VALUE_SIZE
)
858 memset (&as
, 0, sizeof (struct aspath
));
859 if (assegments_parse (s
, length
, &as
.segments
, use32bit
) < 0)
862 /* If already same aspath exist then return it. */
863 find
= hash_get (ashash
, &as
, aspath_hash_alloc
);
865 /* bug! should not happen, let the daemon crash below */
868 /* if the aspath was already hashed free temporary memory. */
871 assegment_free_all (as
.segments
);
872 /* aspath_key_make() always updates the string */
873 XFREE (MTYPE_AS_STR
, as
.str
);
876 json_object_free(as
.json
);
887 assegment_data_put (struct stream
*s
, as_t
*as
, int num
, int use32bit
)
890 assert (num
<= AS_SEGMENT_MAX
);
892 for (i
= 0; i
< num
; i
++)
894 stream_putl (s
, as
[i
]);
897 if ( as
[i
] <= BGP_AS_MAX
)
898 stream_putw(s
, as
[i
]);
900 stream_putw(s
, BGP_AS_TRANS
);
905 assegment_header_put (struct stream
*s
, u_char type
, int length
)
908 assert (length
<= AS_SEGMENT_MAX
);
909 stream_putc (s
, type
);
910 lenp
= stream_get_endp (s
);
911 stream_putc (s
, length
);
915 /* write aspath data to stream */
917 aspath_put (struct stream
*s
, struct aspath
*as
, int use32bit
)
919 struct assegment
*seg
= as
->segments
;
922 if (!seg
|| seg
->length
== 0)
928 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
929 * At the moment, we would write out a partial aspath, and our peer
930 * will complain and drop the session :-/
932 * The general assumption here is that many things tested will
933 * never happen. And, in real live, up to now, they have not.
935 while (seg
&& (ASSEGMENT_LEN(seg
, use32bit
) <= STREAM_WRITEABLE(s
)))
937 struct assegment
*next
= seg
->next
;
942 /* Overlength segments have to be split up */
943 while ( (seg
->length
- written
) > AS_SEGMENT_MAX
)
945 assegment_header_put (s
, seg
->type
, AS_SEGMENT_MAX
);
946 assegment_data_put (s
, seg
->as
, AS_SEGMENT_MAX
, use32bit
);
947 written
+= AS_SEGMENT_MAX
;
948 bytes
+= ASSEGMENT_SIZE (written
, use32bit
);
951 /* write the final segment, probably is also the first */
952 lenp
= assegment_header_put (s
, seg
->type
, seg
->length
- written
);
953 assegment_data_put (s
, (seg
->as
+ written
), seg
->length
- written
,
956 /* Sequence-type segments can be 'packed' together
957 * Case of a segment which was overlength and split up
958 * will be missed here, but that doesn't matter.
960 while (next
&& ASSEGMENTS_PACKABLE (seg
, next
))
962 /* NB: We should never normally get here given we
963 * normalise aspath data when parse them. However, better
964 * safe than sorry. We potentially could call
965 * assegment_normalise here instead, but it's cheaper and
966 * easier to do it on the fly here rather than go through
967 * the segment list twice every time we write out
971 /* Next segment's data can fit in this one */
972 assegment_data_put (s
, next
->as
, next
->length
, use32bit
);
974 /* update the length of the segment header */
975 stream_putc_at (s
, lenp
, seg
->length
- written
+ next
->length
);
976 asns_packed
+= next
->length
;
981 bytes
+= ASSEGMENT_SIZE (seg
->length
- written
+ asns_packed
,
989 /* This is for SNMP BGP4PATHATTRASPATHSEGMENT
990 * We have no way to manage the storage, so we use a static stream
991 * wrapper around aspath_put.
994 aspath_snmp_pathseg (struct aspath
*as
, size_t *varlen
)
996 #define SNMP_PATHSEG_MAX 1024
999 snmp_stream
= stream_new (SNMP_PATHSEG_MAX
);
1001 stream_reset (snmp_stream
);
1008 aspath_put (snmp_stream
, as
, 0); /* use 16 bit for now here */
1010 *varlen
= stream_get_endp (snmp_stream
);
1011 return stream_pnt(snmp_stream
);
1014 #define min(A,B) ((A) < (B) ? (A) : (B))
1016 static struct assegment
*
1017 aspath_aggregate_as_set_add (struct aspath
*aspath
, struct assegment
*asset
,
1022 /* If this is first AS set member, create new as-set segment. */
1025 asset
= assegment_new (AS_SET
, 1);
1026 if (! aspath
->segments
)
1027 aspath
->segments
= asset
;
1030 struct assegment
*seg
= aspath
->segments
;
1035 asset
->type
= AS_SET
;
1041 /* Check this AS value already exists or not. */
1042 for (i
= 0; i
< asset
->length
; i
++)
1043 if (asset
->as
[i
] == as
)
1047 asset
->as
= XREALLOC (MTYPE_AS_SEG_DATA
, asset
->as
,
1048 asset
->length
* AS_VALUE_SIZE
);
1049 asset
->as
[asset
->length
- 1] = as
;
1056 /* Modify as1 using as2 for aggregation. */
1058 aspath_aggregate (struct aspath
*as1
, struct aspath
*as2
)
1064 struct assegment
*seg1
= as1
->segments
;
1065 struct assegment
*seg2
= as2
->segments
;
1066 struct aspath
*aspath
= NULL
;
1067 struct assegment
*asset
= NULL
;
1068 struct assegment
*prevseg
= NULL
;
1070 /* First of all check common leading sequence. */
1071 while (seg1
&& seg2
)
1073 /* Check segment type. */
1074 if (seg1
->type
!= seg2
->type
)
1077 /* Minimum segment length. */
1078 minlen
= min (seg1
->length
, seg2
->length
);
1080 for (match
= 0; match
< minlen
; match
++)
1081 if (seg1
->as
[match
] != seg2
->as
[match
])
1086 struct assegment
*seg
= assegment_new (seg1
->type
, 0);
1088 seg
= assegment_append_asns (seg
, seg1
->as
, match
);
1092 aspath
= aspath_new ();
1093 aspath
->segments
= seg
;
1096 prevseg
->next
= seg
;
1101 if (match
!= minlen
|| match
!= seg1
->length
1102 || seg1
->length
!= seg2
->length
)
1104 /* We are moving on to the next segment to reset match */
1113 aspath
= aspath_new();
1115 /* Make as-set using rest of all information. */
1119 for (i
= from
; i
< seg1
->length
; i
++)
1120 asset
= aspath_aggregate_as_set_add (aspath
, asset
, seg1
->as
[i
]);
1129 for (i
= from
; i
< seg2
->length
; i
++)
1130 asset
= aspath_aggregate_as_set_add (aspath
, asset
, seg2
->as
[i
]);
1136 assegment_normalise (aspath
->segments
);
1137 aspath_str_update (aspath
);
1141 /* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1142 attribute, check the leftmost AS number in the AS_PATH attribute is
1143 or not the peer's AS number. */
1145 aspath_firstas_check (struct aspath
*aspath
, as_t asno
)
1147 if ( (aspath
== NULL
) || (aspath
->segments
== NULL
) )
1150 if (aspath
->segments
1151 && (aspath
->segments
->type
== AS_SEQUENCE
)
1152 && (aspath
->segments
->as
[0] == asno
))
1159 aspath_get_firstas (struct aspath
*aspath
)
1161 if (aspath
== NULL
|| aspath
->segments
== NULL
)
1164 return aspath
->segments
->as
[0];
1167 /* AS path loop check. If aspath contains asno then return >= 1. */
1169 aspath_loop_check (struct aspath
*aspath
, as_t asno
)
1171 struct assegment
*seg
;
1174 if ( (aspath
== NULL
) || (aspath
->segments
== NULL
) )
1177 seg
= aspath
->segments
;
1183 for (i
= 0; i
< seg
->length
; i
++)
1184 if (seg
->as
[i
] == asno
)
1192 /* When all of AS path is private AS return 1. */
1194 aspath_private_as_check (struct aspath
*aspath
)
1196 struct assegment
*seg
;
1198 if ( !(aspath
&& aspath
->segments
) )
1201 seg
= aspath
->segments
;
1207 for (i
= 0; i
< seg
->length
; i
++)
1209 if (!BGP_AS_IS_PRIVATE(seg
->as
[i
]))
1217 /* Return True if the entire ASPATH consist of the specified ASN */
1219 aspath_single_asn_check (struct aspath
*aspath
, as_t asn
)
1221 struct assegment
*seg
;
1223 if ( !(aspath
&& aspath
->segments
) )
1226 seg
= aspath
->segments
;
1232 for (i
= 0; i
< seg
->length
; i
++)
1234 if (seg
->as
[i
] != asn
)
1242 /* Replace all instances of the target ASN with our own ASN */
1244 aspath_replace_specific_asn (struct aspath
*aspath
, as_t target_asn
,
1248 struct assegment
*seg
;
1250 new = aspath_dup(aspath
);
1251 seg
= new->segments
;
1257 for (i
= 0; i
< seg
->length
; i
++)
1259 if (seg
->as
[i
] == target_asn
)
1260 seg
->as
[i
] = our_asn
;
1265 aspath_str_update(new);
1269 /* Replace all private ASNs with our own ASN */
1271 aspath_replace_private_asns (struct aspath
*aspath
, as_t asn
)
1274 struct assegment
*seg
;
1276 new = aspath_dup(aspath
);
1277 seg
= new->segments
;
1283 for (i
= 0; i
< seg
->length
; i
++)
1285 if (BGP_AS_IS_PRIVATE(seg
->as
[i
]))
1291 aspath_str_update(new);
1295 /* Remove all private ASNs */
1297 aspath_remove_private_asns (struct aspath
*aspath
)
1300 struct assegment
*seg
;
1301 struct assegment
*new_seg
;
1302 struct assegment
*last_new_seg
;
1307 new = XCALLOC (MTYPE_AS_PATH
, sizeof (struct aspath
));
1311 last_new_seg
= NULL
;
1312 seg
= aspath
->segments
;
1316 for (i
= 0; i
< seg
->length
; i
++)
1319 if (!BGP_AS_IS_PRIVATE(seg
->as
[i
]))
1325 // The entire segment is private so skip it
1332 // The entire segment is public so copy it
1333 else if (public == seg
->length
)
1335 new_seg
= assegment_dup (seg
);
1338 // The segment is a mix of public and private ASNs. Copy as many spots as
1339 // there are public ASNs then come back and fill in only the public ASNs.
1342 new_seg
= assegment_new (seg
->type
, public);
1344 for (i
= 0; i
< seg
->length
; i
++)
1347 if (!BGP_AS_IS_PRIVATE(seg
->as
[i
]))
1349 new_seg
->as
[j
] = seg
->as
[i
];
1355 // This is the first segment so set the aspath segments pointer to this one
1357 new->segments
= new_seg
;
1359 last_new_seg
->next
= new_seg
;
1361 last_new_seg
= new_seg
;
1365 aspath_str_update(new);
1369 /* AS path confed check. If aspath contains confed set or sequence then return 1. */
1371 aspath_confed_check (struct aspath
*aspath
)
1373 struct assegment
*seg
;
1375 if ( !(aspath
&& aspath
->segments
) )
1378 seg
= aspath
->segments
;
1382 if (seg
->type
== AS_CONFED_SET
|| seg
->type
== AS_CONFED_SEQUENCE
)
1389 /* Leftmost AS path segment confed check. If leftmost AS segment is of type
1390 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1392 aspath_left_confed_check (struct aspath
*aspath
)
1395 if ( !(aspath
&& aspath
->segments
) )
1398 if ( (aspath
->segments
->type
== AS_CONFED_SEQUENCE
)
1399 || (aspath
->segments
->type
== AS_CONFED_SET
) )
1405 /* Merge as1 to as2. as2 should be uninterned aspath. */
1406 static struct aspath
*
1407 aspath_merge (struct aspath
*as1
, struct aspath
*as2
)
1409 struct assegment
*last
, *new;
1414 last
= new = assegment_dup_all (as1
->segments
);
1416 /* find the last valid segment */
1417 while (last
&& last
->next
)
1420 last
->next
= as2
->segments
;
1421 as2
->segments
= new;
1422 aspath_str_update (as2
);
1426 /* Prepend as1 to as2. as2 should be uninterned aspath. */
1428 aspath_prepend (struct aspath
*as1
, struct aspath
*as2
)
1430 struct assegment
*seg1
;
1431 struct assegment
*seg2
;
1436 seg1
= as1
->segments
;
1437 seg2
= as2
->segments
;
1439 /* If as2 is empty, only need to dupe as1's chain onto as2 */
1442 as2
->segments
= assegment_dup_all (as1
->segments
);
1443 aspath_str_update (as2
);
1447 /* If as1 is empty AS, no prepending to do. */
1451 /* find the tail as1's segment chain. */
1452 while (seg1
&& seg1
->next
)
1455 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1456 if (seg1
->type
== AS_SEQUENCE
&& seg2
->type
== AS_CONFED_SEQUENCE
)
1457 as2
= aspath_delete_confed_seq (as2
);
1459 /* Compare last segment type of as1 and first segment type of as2. */
1460 if (seg1
->type
!= seg2
->type
)
1461 return aspath_merge (as1
, as2
);
1463 if (seg1
->type
== AS_SEQUENCE
)
1465 /* We have two chains of segments, as1->segments and seg2,
1466 * and we have to attach them together, merging the attaching
1467 * segments together into one.
1469 * 1. dupe as1->segments onto head of as2
1470 * 2. merge seg2's asns onto last segment of this new chain
1471 * 3. attach chain after seg2
1474 /* dupe as1 onto as2's head */
1475 seg1
= as2
->segments
= assegment_dup_all (as1
->segments
);
1477 /* refind the tail of as2, reusing seg1 */
1478 while (seg1
&& seg1
->next
)
1481 /* merge the old head, seg2, into tail, seg1 */
1482 seg1
= assegment_append_asns (seg1
, seg2
->as
, seg2
->length
);
1484 /* bypass the merged seg2, and attach any chain after it to
1485 * chain descending from as2's head
1487 seg1
->next
= seg2
->next
;
1489 /* seg2 is now referenceless and useless*/
1490 assegment_free (seg2
);
1492 /* we've now prepended as1's segment chain to as2, merging
1493 * the inbetween AS_SEQUENCE of seg2 in the process
1495 aspath_str_update (as2
);
1500 /* AS_SET merge code is needed at here. */
1501 return aspath_merge (as1
, as2
);
1503 /* XXX: Ermmm, what if as1 has multiple segments?? */
1508 /* Iterate over AS_PATH segments and wipe all occurences of the
1509 * listed AS numbers. Hence some segments may lose some or even
1510 * all data on the way, the operation is implemented as a smarter
1511 * version of aspath_dup(), which allocates memory to hold the new
1512 * data, not the original. The new AS path is returned.
1515 aspath_filter_exclude (struct aspath
* source
, struct aspath
* exclude_list
)
1517 struct assegment
* srcseg
, * exclseg
, * lastseg
;
1518 struct aspath
* newpath
;
1520 newpath
= aspath_new();
1523 for (srcseg
= source
->segments
; srcseg
; srcseg
= srcseg
->next
)
1525 unsigned i
, y
, newlen
= 0, done
= 0, skip_as
;
1526 struct assegment
* newseg
;
1528 /* Find out, how much ASns are we going to pick from this segment.
1529 * We can't perform filtering right inline, because the size of
1530 * the new segment isn't known at the moment yet.
1532 for (i
= 0; i
< srcseg
->length
; i
++)
1535 for (exclseg
= exclude_list
->segments
; exclseg
&& !skip_as
; exclseg
= exclseg
->next
)
1536 for (y
= 0; y
< exclseg
->length
; y
++)
1537 if (srcseg
->as
[i
] == exclseg
->as
[y
])
1540 // There's no sense in testing the rest of exclusion list, bail out.
1546 /* newlen is now the number of ASns to copy */
1550 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1551 newseg
= assegment_new (srcseg
->type
, newlen
);
1552 for (i
= 0; i
< srcseg
->length
; i
++)
1555 for (exclseg
= exclude_list
->segments
; exclseg
&& !skip_as
; exclseg
= exclseg
->next
)
1556 for (y
= 0; y
< exclseg
->length
; y
++)
1557 if (srcseg
->as
[i
] == exclseg
->as
[y
])
1564 newseg
->as
[done
++] = srcseg
->as
[i
];
1566 /* At his point newlen must be equal to done, and both must be positive. Append
1567 * the filtered segment to the gross result. */
1569 newpath
->segments
= newseg
;
1571 lastseg
->next
= newseg
;
1574 aspath_str_update (newpath
);
1575 /* We are happy returning even an empty AS_PATH, because the administrator
1576 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1577 * by having a match rule against certain AS_PATH regexps in the route-map index.
1579 aspath_free (source
);
1583 /* Add specified AS to the leftmost of aspath. */
1584 static struct aspath
*
1585 aspath_add_asns (struct aspath
*aspath
, as_t asno
, u_char type
, unsigned num
)
1587 struct assegment
*assegment
= aspath
->segments
;
1590 if (assegment
&& assegment
->type
== type
)
1592 /* extend existing segment */
1593 aspath
->segments
= assegment_prepend_asns (aspath
->segments
, asno
, num
);
1597 /* prepend with new segment */
1598 struct assegment
*newsegment
= assegment_new (type
, num
);
1599 for (i
= 0; i
< num
; i
++)
1600 newsegment
->as
[i
] = asno
;
1602 /* insert potentially replacing empty segment */
1603 if (assegment
&& assegment
->length
== 0)
1605 newsegment
->next
= assegment
->next
;
1606 assegment_free (assegment
);
1609 newsegment
->next
= assegment
;
1610 aspath
->segments
= newsegment
;
1613 aspath_str_update (aspath
);
1617 /* Add specified AS to the leftmost of aspath num times. */
1619 aspath_add_seq_n (struct aspath
*aspath
, as_t asno
, unsigned num
)
1621 return aspath_add_asns (aspath
, asno
, AS_SEQUENCE
, num
);
1624 /* Add specified AS to the leftmost of aspath. */
1626 aspath_add_seq (struct aspath
*aspath
, as_t asno
)
1628 return aspath_add_asns (aspath
, asno
, AS_SEQUENCE
, 1);
1631 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1632 as2's leftmost AS is same return 1. */
1634 aspath_cmp_left (const struct aspath
*aspath1
, const struct aspath
*aspath2
)
1636 const struct assegment
*seg1
;
1637 const struct assegment
*seg2
;
1639 if (!(aspath1
&& aspath2
))
1642 seg1
= aspath1
->segments
;
1643 seg2
= aspath2
->segments
;
1645 /* If both paths are originated in this AS then we do want to compare MED */
1649 /* find first non-confed segments for each */
1650 while (seg1
&& ((seg1
->type
== AS_CONFED_SEQUENCE
)
1651 || (seg1
->type
== AS_CONFED_SET
)))
1654 while (seg2
&& ((seg2
->type
== AS_CONFED_SEQUENCE
)
1655 || (seg2
->type
== AS_CONFED_SET
)))
1660 && (seg1
->type
== AS_SEQUENCE
) && (seg2
->type
== AS_SEQUENCE
)))
1663 if (seg1
->as
[0] == seg2
->as
[0])
1669 /* Truncate an aspath after a number of hops, and put the hops remaining
1670 * at the front of another aspath. Needed for AS4 compat.
1672 * Returned aspath is a /new/ aspath, which should either by free'd or
1673 * interned by the caller, as desired.
1676 aspath_reconcile_as4 ( struct aspath
*aspath
, struct aspath
*as4path
)
1678 struct assegment
*seg
, *newseg
, *prevseg
= NULL
;
1679 struct aspath
*newpath
= NULL
, *mergedpath
;
1680 int hops
, cpasns
= 0;
1685 seg
= aspath
->segments
;
1687 /* CONFEDs should get reconciled too.. */
1688 hops
= (aspath_count_hops (aspath
) + aspath_count_confeds (aspath
))
1689 - aspath_count_hops (as4path
);
1693 if (BGP_DEBUG (as4
, AS4
))
1694 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1695 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1696 * which is daft behaviour - it contains vital loop-detection
1697 * information which must have been removed from AS_PATH.
1699 hops
= aspath_count_hops (aspath
);
1704 newpath
= aspath_dup (as4path
);
1705 aspath_str_update(newpath
);
1709 if ( BGP_DEBUG(as4
, AS4
))
1710 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1711 aspath
->str
, as4path
->str
);
1713 while (seg
&& hops
> 0)
1720 cpasns
= seg
->length
;
1722 case AS_CONFED_SEQUENCE
:
1723 /* Should never split a confed-sequence, if hop-count
1724 * suggests we must then something's gone wrong somewhere.
1726 * Most important goal is to preserve AS_PATHs prime function
1727 * as loop-detector, so we fudge the numbers so that the entire
1728 * confed-sequence is merged in.
1730 if (hops
< seg
->length
)
1732 if (BGP_DEBUG (as4
, AS4
))
1733 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1734 " across 2/4 ASN boundary somewhere, broken..");
1738 cpasns
= MIN(seg
->length
, hops
);
1739 hops
-= seg
->length
;
1742 assert (cpasns
<= seg
->length
);
1744 newseg
= assegment_new (seg
->type
, 0);
1745 newseg
= assegment_append_asns (newseg
, seg
->as
, cpasns
);
1749 newpath
= aspath_new ();
1750 newpath
->segments
= newseg
;
1753 prevseg
->next
= newseg
;
1759 /* We may be able to join some segments here, and we must
1760 * do this because... we want normalised aspaths in out hash
1761 * and we do not want to stumble in aspath_put.
1763 mergedpath
= aspath_merge (newpath
, aspath_dup(as4path
));
1764 aspath_free (newpath
);
1765 mergedpath
->segments
= assegment_normalise (mergedpath
->segments
);
1766 aspath_str_update (mergedpath
);
1768 if ( BGP_DEBUG(as4
, AS4
))
1769 zlog_debug ("[AS4] result of synthesizing is %s",
1775 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1776 as2's leftmost AS is same return 1. (confederation as-path
1779 aspath_cmp_left_confed (const struct aspath
*aspath1
, const struct aspath
*aspath2
)
1781 if (! (aspath1
&& aspath2
) )
1784 if ( !(aspath1
->segments
&& aspath2
->segments
) )
1787 if ( (aspath1
->segments
->type
!= AS_CONFED_SEQUENCE
)
1788 || (aspath2
->segments
->type
!= AS_CONFED_SEQUENCE
) )
1791 if (aspath1
->segments
->as
[0] == aspath2
->segments
->as
[0])
1797 /* Delete all AS_CONFED_SEQUENCE/SET segments from aspath.
1798 * RFC 5065 section 4.1.c.1
1800 * 1) if any path segments of the AS_PATH are of the type
1801 * AS_CONFED_SEQUENCE or AS_CONFED_SET, those segments MUST be
1802 * removed from the AS_PATH attribute, leaving the sanitized
1803 * AS_PATH attribute to be operated on by steps 2, 3 or 4.
1806 aspath_delete_confed_seq (struct aspath
*aspath
)
1808 struct assegment
*seg
, *prev
, *next
;
1809 char removed_confed_segment
;
1811 if (!(aspath
&& aspath
->segments
))
1814 seg
= aspath
->segments
;
1815 removed_confed_segment
= 0;
1823 if (seg
->type
== AS_CONFED_SEQUENCE
|| seg
->type
== AS_CONFED_SET
)
1825 /* This is the first segment in the aspath */
1826 if (aspath
->segments
== seg
)
1827 aspath
->segments
= seg
->next
;
1829 prev
->next
= seg
->next
;
1831 assegment_free (seg
);
1832 removed_confed_segment
= 1;
1840 if (removed_confed_segment
)
1841 aspath_str_update (aspath
);
1846 /* Add new AS number to the leftmost part of the aspath as
1847 AS_CONFED_SEQUENCE. */
1849 aspath_add_confed_seq (struct aspath
*aspath
, as_t asno
)
1851 return aspath_add_asns (aspath
, asno
, AS_CONFED_SEQUENCE
, 1);
1854 /* Add new as value to as path structure. */
1856 aspath_as_add (struct aspath
*as
, as_t asno
)
1858 struct assegment
*seg
= as
->segments
;
1863 /* Last segment search procedure. */
1867 assegment_append_asns (seg
, &asno
, 1);
1870 /* Add new as segment to the as path. */
1872 aspath_segment_add (struct aspath
*as
, int type
)
1874 struct assegment
*seg
= as
->segments
;
1875 struct assegment
*new = assegment_new (type
, 0);
1890 return aspath_parse (NULL
, 0, 1); /* 32Bit ;-) */
1894 aspath_empty_get (void)
1896 struct aspath
*aspath
;
1898 aspath
= aspath_new ();
1899 aspath_make_str_count (aspath
);
1906 return ashash
->count
;
1910 Theoretically, one as path can have:
1912 One BGP packet size should be less than 4096.
1913 One BGP attribute size should be less than 4096 - BGP header size.
1914 One BGP aspath size should be less than 4096 - BGP header size -
1915 BGP mandantry attribute size.
1918 /* AS path string lexical token enum. */
1924 as_token_confed_seq_start
,
1925 as_token_confed_seq_end
,
1926 as_token_confed_set_start
,
1927 as_token_confed_set_end
,
1931 /* Return next token and point for string parse. */
1933 aspath_gettoken (const char *buf
, enum as_token
*token
, u_long
*asno
)
1935 const char *p
= buf
;
1937 /* Skip seperators (space for sequences, ',' for sets). */
1938 while (isspace ((int) *p
) || *p
== ',')
1941 /* Check the end of the string and type specify characters
1948 *token
= as_token_set_start
;
1952 *token
= as_token_set_end
;
1956 *token
= as_token_confed_seq_start
;
1960 *token
= as_token_confed_seq_end
;
1964 *token
= as_token_confed_set_start
;
1968 *token
= as_token_confed_set_end
;
1973 /* Check actual AS value. */
1974 if (isdigit ((int) *p
))
1978 *token
= as_token_asval
;
1982 while (isdigit ((int) *p
))
1985 asval
+= (*p
- '0');
1992 /* There is no match then return unknown token. */
1993 *token
= as_token_unknown
;
1998 aspath_str2aspath (const char *str
)
2000 enum as_token token
= as_token_unknown
;
2003 struct aspath
*aspath
;
2006 aspath
= aspath_new ();
2008 /* We start default type as AS_SEQUENCE. */
2009 as_type
= AS_SEQUENCE
;
2012 while ((str
= aspath_gettoken (str
, &token
, &asno
)) != NULL
)
2016 case as_token_asval
:
2019 aspath_segment_add (aspath
, as_type
);
2022 aspath_as_add (aspath
, asno
);
2024 case as_token_set_start
:
2026 aspath_segment_add (aspath
, as_type
);
2029 case as_token_set_end
:
2030 as_type
= AS_SEQUENCE
;
2033 case as_token_confed_seq_start
:
2034 as_type
= AS_CONFED_SEQUENCE
;
2035 aspath_segment_add (aspath
, as_type
);
2038 case as_token_confed_seq_end
:
2039 as_type
= AS_SEQUENCE
;
2042 case as_token_confed_set_start
:
2043 as_type
= AS_CONFED_SET
;
2044 aspath_segment_add (aspath
, as_type
);
2047 case as_token_confed_set_end
:
2048 as_type
= AS_SEQUENCE
;
2051 case as_token_unknown
:
2053 aspath_free (aspath
);
2058 aspath_make_str_count (aspath
);
2063 /* Make hash value by raw aspath data. */
2065 aspath_key_make (void *p
)
2067 struct aspath
*aspath
= (struct aspath
*) p
;
2068 unsigned int key
= 0;
2071 aspath_str_update (aspath
);
2073 key
= jhash (aspath
->str
, aspath
->str_len
, 2334325);
2078 /* If two aspath have same value then return 1 else return 0 */
2080 aspath_cmp (const void *arg1
, const void *arg2
)
2082 const struct assegment
*seg1
= ((const struct aspath
*)arg1
)->segments
;
2083 const struct assegment
*seg2
= ((const struct aspath
*)arg2
)->segments
;
2085 while (seg1
|| seg2
)
2088 if ((!seg1
&& seg2
) || (seg1
&& !seg2
))
2090 if (seg1
->type
!= seg2
->type
)
2092 if (seg1
->length
!= seg2
->length
)
2094 for (i
= 0; i
< seg1
->length
; i
++)
2095 if (seg1
->as
[i
] != seg2
->as
[i
])
2103 /* AS path hash initialize. */
2107 ashash
= hash_create_size (32768, aspath_key_make
, aspath_cmp
);
2111 aspath_finish (void)
2117 stream_free (snmp_stream
);
2120 /* return and as path value */
2122 aspath_print (struct aspath
*as
)
2124 return (as
? as
->str
: NULL
);
2127 /* Printing functions */
2128 /* Feed the AS_PATH to the vty; the suffix string follows it only in case
2129 * AS_PATH wasn't empty.
2132 aspath_print_vty (struct vty
*vty
, const char *format
, struct aspath
*as
, const char * suffix
)
2135 vty_out (vty
, format
, as
->str
);
2136 if (as
->str_len
&& strlen (suffix
))
2137 vty_out (vty
, "%s", suffix
);
2141 aspath_show_all_iterator (struct hash_backet
*backet
, struct vty
*vty
)
2145 as
= (struct aspath
*) backet
->data
;
2147 vty_out (vty
, "[%p:%u] (%ld) ", backet
, backet
->key
, as
->refcnt
);
2148 vty_out (vty
, "%s%s", as
->str
, VTY_NEWLINE
);
2151 /* Print all aspath and hash information. This function is used from
2152 `show ip bgp paths' command. */
2154 aspath_print_all_vty (struct vty
*vty
)
2156 hash_iterate (ashash
,
2157 (void (*) (struct hash_backet
*, void *))
2158 aspath_show_all_iterator
,