]> git.proxmox.com Git - mirror_frr.git/blame_incremental - bgpd/bgp_aspath.c
Merge pull request #410 from dslicenc/rdnbrd-vrr
[mirror_frr.git] / bgpd / bgp_aspath.c
... / ...
CommitLineData
1/* AS path management routines.
2 Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
3 Copyright (C) 2005 Sun Microsystems, Inc.
4
5This file is part of GNU Zebra.
6
7GNU Zebra is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by the
9Free Software Foundation; either version 2, or (at your option) any
10later version.
11
12GNU Zebra is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Zebra; see the file COPYING. If not, write to the Free
19Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA. */
21
22#include <zebra.h>
23
24#include "hash.h"
25#include "memory.h"
26#include "vector.h"
27#include "log.h"
28#include "stream.h"
29#include "command.h"
30#include "jhash.h"
31#include "queue.h"
32#include "filter.h"
33
34#include "bgpd/bgpd.h"
35#include "bgpd/bgp_aspath.h"
36#include "bgpd/bgp_debug.h"
37#include "bgpd/bgp_attr.h"
38
39/* Attr. Flags and Attr. Type Code. */
40#define AS_HEADER_SIZE 2
41
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)
46
47/* Maximum protocol segment length value */
48#define AS_SEGMENT_MAX 255
49
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.
55 *
56 * aspath_put returns bytes written, the only definitive record of
57 * size of wire-format attribute..
58 */
59
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) )
63
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))
66
67/* AS segment octet length. */
68#define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
69
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 ) )
79
80/* As segment header - the on-wire representation
81 * NOT the internal representation!
82 */
83struct assegment_header
84{
85 u_char type;
86 u_char length;
87};
88
89/* Hash for aspath. This is the top level structure of AS path. */
90static struct hash *ashash;
91
92/* Stream for SNMP. See aspath_snmp_pathseg */
93static struct stream *snmp_stream;
94
95/* Callers are required to initialize the memory */
96static as_t *
97assegment_data_new (int num)
98{
99 return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
100}
101
102static void
103assegment_data_free (as_t *asdata)
104{
105 XFREE (MTYPE_AS_SEG_DATA, asdata);
106}
107
108const char *aspath_segment_type_str[] = {
109 "as-invalid",
110 "as-set",
111 "as-sequence",
112 "as-confed-sequence",
113 "as-confed-set"
114};
115
116/* Get a new segment. Note that 0 is an allowed length,
117 * and will result in a segment with no allocated data segment.
118 * the caller should immediately assign data to the segment, as the segment
119 * otherwise is not generally valid
120 */
121static struct assegment *
122assegment_new (u_char type, u_short length)
123{
124 struct assegment *new;
125
126 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
127
128 if (length)
129 new->as = assegment_data_new (length);
130
131 new->length = length;
132 new->type = type;
133
134 return new;
135}
136
137static void
138assegment_free (struct assegment *seg)
139{
140 if (!seg)
141 return;
142
143 if (seg->as)
144 assegment_data_free (seg->as);
145 memset (seg, 0xfe, sizeof(struct assegment));
146 XFREE (MTYPE_AS_SEG, seg);
147
148 return;
149}
150
151/* free entire chain of segments */
152static void
153assegment_free_all (struct assegment *seg)
154{
155 struct assegment *prev;
156
157 while (seg)
158 {
159 prev = seg;
160 seg = seg->next;
161 assegment_free (prev);
162 }
163}
164
165/* Duplicate just the given assegment and its data */
166static struct assegment *
167assegment_dup (struct assegment *seg)
168{
169 struct assegment *new;
170
171 new = assegment_new (seg->type, seg->length);
172 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );
173
174 return new;
175}
176
177/* Duplicate entire chain of assegments, return the head */
178static struct assegment *
179assegment_dup_all (struct assegment *seg)
180{
181 struct assegment *new = NULL;
182 struct assegment *head = NULL;
183
184 while (seg)
185 {
186 if (head)
187 {
188 new->next = assegment_dup (seg);
189 new = new->next;
190 }
191 else
192 head = new = assegment_dup (seg);
193
194 seg = seg->next;
195 }
196 return head;
197}
198
199/* prepend the as number to given segment, given num of times */
200static struct assegment *
201assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
202{
203 as_t *newas;
204 int i;
205
206 if (!num)
207 return seg;
208
209 if (num >= AS_SEGMENT_MAX)
210 return seg; /* we don't do huge prepends */
211
212 if ((newas = assegment_data_new (seg->length + num)) == NULL)
213 return seg;
214
215 for (i = 0; i < num; i++)
216 newas[i] = asnum;
217
218 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
219 assegment_data_free (seg->as);
220 seg->as = newas;
221 seg->length += num;
222
223 return seg;
224}
225
226/* append given array of as numbers to the segment */
227static struct assegment *
228assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
229{
230 as_t *newas;
231
232 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
233 ASSEGMENT_DATA_SIZE (seg->length + num, 1));
234
235 if (newas)
236 {
237 seg->as = newas;
238 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));
239 seg->length += num;
240 return seg;
241 }
242
243 assegment_free_all (seg);
244 return NULL;
245}
246
247static int
248int_cmp (const void *p1, const void *p2)
249{
250 const as_t *as1 = p1;
251 const as_t *as2 = p2;
252
253 return (*as1 == *as2)
254 ? 0 : ( (*as1 > *as2) ? 1 : -1);
255}
256
257/* normalise the segment.
258 * In particular, merge runs of AS_SEQUENCEs into one segment
259 * Internally, we do not care about the wire segment length limit, and
260 * we want each distinct AS_PATHs to have the exact same internal
261 * representation - eg, so that our hashing actually works..
262 */
263static struct assegment *
264assegment_normalise (struct assegment *head)
265{
266 struct assegment *seg = head, *pin;
267 struct assegment *tmp;
268
269 if (!head)
270 return head;
271
272 while (seg)
273 {
274 pin = seg;
275
276 /* Sort values SET segments, for determinism in paths to aid
277 * creation of hash values / path comparisons
278 * and because it helps other lesser implementations ;)
279 */
280 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
281 {
282 int tail = 0;
283 int i;
284
285 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
286
287 /* weed out dupes */
288 for (i=1; i < seg->length; i++)
289 {
290 if (seg->as[tail] == seg->as[i])
291 continue;
292
293 tail++;
294 if (tail < i)
295 seg->as[tail] = seg->as[i];
296 }
297 /* seg->length can be 0.. */
298 if (seg->length)
299 seg->length = tail + 1;
300 }
301
302 /* read ahead from the current, pinned segment while the segments
303 * are packable/mergeable. Append all following packable segments
304 * to the segment we have pinned and remove these appended
305 * segments.
306 */
307 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
308 {
309 tmp = pin->next;
310 seg = pin->next;
311
312 /* append the next sequence to the pinned sequence */
313 pin = assegment_append_asns (pin, seg->as, seg->length);
314
315 /* bypass the next sequence */
316 pin->next = seg->next;
317
318 /* get rid of the now referenceless segment */
319 assegment_free (tmp);
320
321 }
322
323 seg = pin->next;
324 }
325 return head;
326}
327
328static struct aspath *
329aspath_new (void)
330{
331 return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
332}
333
334/* Free AS path structure. */
335void
336aspath_free (struct aspath *aspath)
337{
338 if (!aspath)
339 return;
340 if (aspath->segments)
341 assegment_free_all (aspath->segments);
342 if (aspath->str)
343 XFREE (MTYPE_AS_STR, aspath->str);
344
345 if (aspath->json)
346 {
347 json_object_free(aspath->json);
348 aspath->json = NULL;
349 }
350
351 XFREE (MTYPE_AS_PATH, aspath);
352}
353
354/* Unintern aspath from AS path bucket. */
355void
356aspath_unintern (struct aspath **aspath)
357{
358 struct aspath *ret;
359 struct aspath *asp = *aspath;
360
361 if (asp->refcnt)
362 asp->refcnt--;
363
364 if (asp->refcnt == 0)
365 {
366 /* This aspath must exist in aspath hash table. */
367 ret = hash_release (ashash, asp);
368 assert (ret != NULL);
369 aspath_free (asp);
370 *aspath = NULL;
371 }
372}
373
374/* Return the start or end delimiters for a particular Segment type */
375#define AS_SEG_START 0
376#define AS_SEG_END 1
377static char
378aspath_delimiter_char (u_char type, u_char which)
379{
380 int i;
381 struct
382 {
383 int type;
384 char start;
385 char end;
386 } aspath_delim_char [] =
387 {
388 { AS_SET, '{', '}' },
389 { AS_CONFED_SET, '[', ']' },
390 { AS_CONFED_SEQUENCE, '(', ')' },
391 { 0 }
392 };
393
394 for (i = 0; aspath_delim_char[i].type != 0; i++)
395 {
396 if (aspath_delim_char[i].type == type)
397 {
398 if (which == AS_SEG_START)
399 return aspath_delim_char[i].start;
400 else if (which == AS_SEG_END)
401 return aspath_delim_char[i].end;
402 }
403 }
404 return ' ';
405}
406
407/* countup asns from this segment and index onward */
408static int
409assegment_count_asns (struct assegment *seg, int from)
410{
411 int count = 0;
412 while (seg)
413 {
414 if (!from)
415 count += seg->length;
416 else
417 {
418 count += (seg->length - from);
419 from = 0;
420 }
421 seg = seg->next;
422 }
423 return count;
424}
425
426unsigned int
427aspath_count_confeds (struct aspath *aspath)
428{
429 int count = 0;
430 struct assegment *seg = aspath->segments;
431
432 while (seg)
433 {
434 if (seg->type == AS_CONFED_SEQUENCE)
435 count += seg->length;
436 else if (seg->type == AS_CONFED_SET)
437 count++;
438
439 seg = seg->next;
440 }
441 return count;
442}
443
444unsigned int
445aspath_count_hops (const struct aspath *aspath)
446{
447 int count = 0;
448 struct assegment *seg = aspath->segments;
449
450 while (seg)
451 {
452 if (seg->type == AS_SEQUENCE)
453 count += seg->length;
454 else if (seg->type == AS_SET)
455 count++;
456
457 seg = seg->next;
458 }
459 return count;
460}
461
462/* Estimate size aspath /might/ take if encoded into an
463 * ASPATH attribute.
464 *
465 * This is a quick estimate, not definitive! aspath_put()
466 * may return a different number!!
467 */
468unsigned int
469aspath_size (struct aspath *aspath)
470{
471 int size = 0;
472 struct assegment *seg = aspath->segments;
473
474 while (seg)
475 {
476 size += ASSEGMENT_SIZE(seg->length, 1);
477 seg = seg->next;
478 }
479 return size;
480}
481
482/* Return highest public ASN in path */
483as_t
484aspath_highest (struct aspath *aspath)
485{
486 struct assegment *seg = aspath->segments;
487 as_t highest = 0;
488 unsigned int i;
489
490 while (seg)
491 {
492 for (i = 0; i < seg->length; i++)
493 if (seg->as[i] > highest && !BGP_AS_IS_PRIVATE(seg->as[i]))
494 highest = seg->as[i];
495 seg = seg->next;
496 }
497 return highest;
498}
499
500/* Return the left-most ASN in path */
501as_t
502aspath_leftmost (struct aspath *aspath)
503{
504 struct assegment *seg = aspath->segments;
505 as_t leftmost = 0;
506
507 if (seg && seg->length && seg->type == AS_SEQUENCE)
508 leftmost = seg->as[0];
509
510 return leftmost;
511}
512
513/* Return 1 if there are any 4-byte ASes in the path */
514unsigned int
515aspath_has_as4 (struct aspath *aspath)
516{
517 struct assegment *seg = aspath->segments;
518 unsigned int i;
519
520 while (seg)
521 {
522 for (i = 0; i < seg->length; i++)
523 if (seg->as[i] > BGP_AS_MAX)
524 return 1;
525 seg = seg->next;
526 }
527 return 0;
528}
529
530/* Convert aspath structure to string expression. */
531static void
532aspath_make_str_count (struct aspath *as)
533{
534 struct assegment *seg;
535 int str_size;
536 int len = 0;
537 char *str_buf;
538 json_object *jaspath_segments = NULL;
539 json_object *jseg = NULL;
540 json_object *jseg_list = NULL;
541
542 as->json = json_object_new_object();
543 jaspath_segments = json_object_new_array();
544
545 /* Empty aspath. */
546 if (!as->segments)
547 {
548 json_object_string_add(as->json, "string", "Local");
549 json_object_object_add(as->json, "segments", jaspath_segments);
550 json_object_int_add(as->json, "length", 0);
551 as->str = XMALLOC (MTYPE_AS_STR, 1);
552 as->str[0] = '\0';
553 as->str_len = 0;
554 return;
555 }
556
557 seg = as->segments;
558
559 /* ASN takes 5 to 10 chars plus seperator, see below.
560 * If there is one differing segment type, we need an additional
561 * 2 chars for segment delimiters, and the final '\0'.
562 * Hopefully this is large enough to avoid hitting the realloc
563 * code below for most common sequences.
564 *
565 * This was changed to 10 after the well-known BGP assertion, which
566 * had hit some parts of the Internet in May of 2009.
567 */
568#define ASN_STR_LEN (10 + 1)
569 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
570 ASPATH_STR_DEFAULT_LEN);
571 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
572
573 while (seg)
574 {
575 int i;
576 char seperator;
577
578 /* Check AS type validity. Set seperator for segment */
579 switch (seg->type)
580 {
581 case AS_SET:
582 case AS_CONFED_SET:
583 seperator = ',';
584 break;
585 case AS_SEQUENCE:
586 case AS_CONFED_SEQUENCE:
587 seperator = ' ';
588 break;
589 default:
590 XFREE (MTYPE_AS_STR, str_buf);
591 as->str = NULL;
592 as->str_len = 0;
593 json_object_free(as->json);
594 as->json = NULL;
595 return;
596 }
597
598 /* We might need to increase str_buf, particularly if path has
599 * differing segments types, our initial guesstimate above will
600 * have been wrong. Need 10 chars for ASN, a seperator each and
601 * potentially two segment delimiters, plus a space between each
602 * segment and trailing zero.
603 *
604 * This definitely didn't work with the value of 5 bytes and
605 * 32-bit ASNs.
606 */
607#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
608 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
609 {
610 str_size = len + SEGMENT_STR_LEN(seg);
611 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
612 }
613#undef ASN_STR_LEN
614#undef SEGMENT_STR_LEN
615
616 if (seg->type != AS_SEQUENCE)
617 len += snprintf (str_buf + len, str_size - len,
618 "%c",
619 aspath_delimiter_char (seg->type, AS_SEG_START));
620
621 jseg_list = json_object_new_array();
622
623 /* write out the ASNs, with their seperators, bar the last one*/
624 for (i = 0; i < seg->length; i++)
625 {
626 json_object_array_add(jseg_list, json_object_new_int(seg->as[i]));
627
628 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
629
630 if (i < (seg->length - 1))
631 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
632 }
633
634 jseg = json_object_new_object();
635 json_object_string_add(jseg, "type", aspath_segment_type_str[seg->type]);
636 json_object_object_add(jseg, "list", jseg_list);
637 json_object_array_add(jaspath_segments, jseg);
638
639 if (seg->type != AS_SEQUENCE)
640 len += snprintf (str_buf + len, str_size - len, "%c",
641 aspath_delimiter_char (seg->type, AS_SEG_END));
642 if (seg->next)
643 len += snprintf (str_buf + len, str_size - len, " ");
644
645 seg = seg->next;
646 }
647
648 assert (len < str_size);
649
650 str_buf[len] = '\0';
651 as->str = str_buf;
652 as->str_len = len;
653
654 json_object_string_add(as->json, "string", str_buf);
655 json_object_object_add(as->json, "segments", jaspath_segments);
656 json_object_int_add(as->json, "length", aspath_count_hops (as));
657 return;
658}
659
660static void
661aspath_str_update (struct aspath *as)
662{
663 if (as->str)
664 XFREE (MTYPE_AS_STR, as->str);
665
666 if (as->json)
667 {
668 json_object_free(as->json);
669 as->json = NULL;
670 }
671
672 aspath_make_str_count (as);
673}
674
675/* Intern allocated AS path. */
676struct aspath *
677aspath_intern (struct aspath *aspath)
678{
679 struct aspath *find;
680
681 /* Assert this AS path structure is not interned and has the string
682 representation built. */
683 assert (aspath->refcnt == 0);
684 assert (aspath->str);
685
686 /* Check AS path hash. */
687 find = hash_get (ashash, aspath, hash_alloc_intern);
688 if (find != aspath)
689 aspath_free (aspath);
690
691 find->refcnt++;
692
693 return find;
694}
695
696/* Duplicate aspath structure. Created same aspath structure but
697 reference count and AS path string is cleared. */
698struct aspath *
699aspath_dup (struct aspath *aspath)
700{
701 unsigned short buflen = aspath->str_len + 1;
702 struct aspath *new;
703
704 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
705 new->json = NULL;
706
707 if (aspath->segments)
708 new->segments = assegment_dup_all (aspath->segments);
709
710 if (!aspath->str)
711 return new;
712
713 new->str = XMALLOC (MTYPE_AS_STR, buflen);
714 new->str_len = aspath->str_len;
715
716 /* copy the string data */
717 if (aspath->str_len > 0)
718 memcpy (new->str, aspath->str, buflen);
719 else
720 new->str[0] = '\0';
721
722 return new;
723}
724
725static void *
726aspath_hash_alloc (void *arg)
727{
728 const struct aspath *aspath = arg;
729 struct aspath *new;
730
731 /* Malformed AS path value. */
732 assert (aspath->str);
733
734 /* New aspath structure is needed. */
735 new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
736
737 /* Reuse segments and string representation */
738 new->refcnt = 0;
739 new->segments = aspath->segments;
740 new->str = aspath->str;
741 new->str_len = aspath->str_len;
742 new->json = aspath->json;
743
744 return new;
745}
746
747/* parse as-segment byte stream in struct assegment */
748static int
749assegments_parse (struct stream *s, size_t length,
750 struct assegment **result, int use32bit)
751{
752 struct assegment_header segh;
753 struct assegment *seg, *prev = NULL, *head = NULL;
754 size_t bytes = 0;
755
756 /* empty aspath (ie iBGP or somesuch) */
757 if (length == 0)
758 return 0;
759
760 if (BGP_DEBUG (as4, AS4_SEGMENT))
761 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
762 (unsigned long) length);
763 /* basic checks */
764 if ((STREAM_READABLE(s) < length)
765 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
766 || (length % AS16_VALUE_SIZE ))
767 return -1;
768
769 while (bytes < length)
770 {
771 int i;
772 size_t seg_size;
773
774 if ((length - bytes) <= AS_HEADER_SIZE)
775 {
776 if (head)
777 assegment_free_all (head);
778 return -1;
779 }
780
781 /* softly softly, get the header first on its own */
782 segh.type = stream_getc (s);
783 segh.length = stream_getc (s);
784
785 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
786
787 if (BGP_DEBUG (as4, AS4_SEGMENT))
788 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
789 segh.type, segh.length);
790
791 /* check it.. */
792 if ( ((bytes + seg_size) > length)
793 /* 1771bis 4.3b: seg length contains one or more */
794 || (segh.length == 0)
795 /* Paranoia in case someone changes type of segment length.
796 * Shift both values by 0x10 to make the comparison operate
797 * on more, than 8 bits (otherwise it's a warning, bug #564).
798 */
799 || ((sizeof segh.length > 1)
800 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
801 {
802 if (head)
803 assegment_free_all (head);
804 return -1;
805 }
806
807 switch (segh.type)
808 {
809 case AS_SEQUENCE:
810 case AS_SET:
811 case AS_CONFED_SEQUENCE:
812 case AS_CONFED_SET:
813 break;
814 default:
815 if (head)
816 assegment_free_all (head);
817 return -1;
818 }
819
820 /* now its safe to trust lengths */
821 seg = assegment_new (segh.type, segh.length);
822
823 if (head)
824 prev->next = seg;
825 else /* it's the first segment */
826 head = prev = seg;
827
828 for (i = 0; i < segh.length; i++)
829 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
830
831 bytes += seg_size;
832
833 if (BGP_DEBUG (as4, AS4_SEGMENT))
834 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
835 (unsigned long) bytes);
836
837 prev = seg;
838 }
839
840 *result = assegment_normalise (head);
841 return 0;
842}
843
844/* AS path parse function. pnt is a pointer to byte stream and length
845 is length of byte stream. If there is same AS path in the the AS
846 path hash then return it else make new AS path structure.
847
848 On error NULL is returned.
849 */
850struct aspath *
851aspath_parse (struct stream *s, size_t length, int use32bit)
852{
853 struct aspath as;
854 struct aspath *find;
855
856 /* If length is odd it's malformed AS path. */
857 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
858 * otherwise its malformed when length is larger than 2 and (length-2)
859 * is not dividable by 4.
860 * But... this time we're lazy
861 */
862 if (length % AS16_VALUE_SIZE )
863 return NULL;
864
865 memset (&as, 0, sizeof (struct aspath));
866 if (assegments_parse (s, length, &as.segments, use32bit) < 0)
867 return NULL;
868
869 /* If already same aspath exist then return it. */
870 find = hash_get (ashash, &as, aspath_hash_alloc);
871
872 /* bug! should not happen, let the daemon crash below */
873 assert (find);
874
875 /* if the aspath was already hashed free temporary memory. */
876 if (find->refcnt)
877 {
878 assegment_free_all (as.segments);
879 /* aspath_key_make() always updates the string */
880 XFREE (MTYPE_AS_STR, as.str);
881 if (as.json)
882 {
883 json_object_free(as.json);
884 as.json = NULL;
885 }
886 }
887
888 find->refcnt++;
889
890 return find;
891}
892
893static void
894assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
895{
896 int i;
897 assert (num <= AS_SEGMENT_MAX);
898
899 for (i = 0; i < num; i++)
900 if ( use32bit )
901 stream_putl (s, as[i]);
902 else
903 {
904 if ( as[i] <= BGP_AS_MAX )
905 stream_putw(s, as[i]);
906 else
907 stream_putw(s, BGP_AS_TRANS);
908 }
909}
910
911static size_t
912assegment_header_put (struct stream *s, u_char type, int length)
913{
914 size_t lenp;
915 assert (length <= AS_SEGMENT_MAX);
916 stream_putc (s, type);
917 lenp = stream_get_endp (s);
918 stream_putc (s, length);
919 return lenp;
920}
921
922/* write aspath data to stream */
923size_t
924aspath_put (struct stream *s, struct aspath *as, int use32bit )
925{
926 struct assegment *seg = as->segments;
927 size_t bytes = 0;
928
929 if (!seg || seg->length == 0)
930 return 0;
931
932 if (seg)
933 {
934 /*
935 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
936 * At the moment, we would write out a partial aspath, and our peer
937 * will complain and drop the session :-/
938 *
939 * The general assumption here is that many things tested will
940 * never happen. And, in real live, up to now, they have not.
941 */
942 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
943 {
944 struct assegment *next = seg->next;
945 int written = 0;
946 int asns_packed = 0;
947 size_t lenp;
948
949 /* Overlength segments have to be split up */
950 while ( (seg->length - written) > AS_SEGMENT_MAX)
951 {
952 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
953 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
954 written += AS_SEGMENT_MAX;
955 bytes += ASSEGMENT_SIZE (written, use32bit);
956 }
957
958 /* write the final segment, probably is also the first */
959 lenp = assegment_header_put (s, seg->type, seg->length - written);
960 assegment_data_put (s, (seg->as + written), seg->length - written,
961 use32bit);
962
963 /* Sequence-type segments can be 'packed' together
964 * Case of a segment which was overlength and split up
965 * will be missed here, but that doesn't matter.
966 */
967 while (next && ASSEGMENTS_PACKABLE (seg, next))
968 {
969 /* NB: We should never normally get here given we
970 * normalise aspath data when parse them. However, better
971 * safe than sorry. We potentially could call
972 * assegment_normalise here instead, but it's cheaper and
973 * easier to do it on the fly here rather than go through
974 * the segment list twice every time we write out
975 * aspath's.
976 */
977
978 /* Next segment's data can fit in this one */
979 assegment_data_put (s, next->as, next->length, use32bit);
980
981 /* update the length of the segment header */
982 stream_putc_at (s, lenp, seg->length - written + next->length);
983 asns_packed += next->length;
984
985 next = next->next;
986 }
987
988 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
989 use32bit);
990 seg = next;
991 }
992 }
993 return bytes;
994}
995
996/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
997 * We have no way to manage the storage, so we use a static stream
998 * wrapper around aspath_put.
999 */
1000u_char *
1001aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
1002{
1003#define SNMP_PATHSEG_MAX 1024
1004
1005 if (!snmp_stream)
1006 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
1007 else
1008 stream_reset (snmp_stream);
1009
1010 if (!as)
1011 {
1012 *varlen = 0;
1013 return NULL;
1014 }
1015 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
1016
1017 *varlen = stream_get_endp (snmp_stream);
1018 return stream_pnt(snmp_stream);
1019}
1020
1021#define min(A,B) ((A) < (B) ? (A) : (B))
1022
1023static struct assegment *
1024aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
1025 as_t as)
1026{
1027 int i;
1028
1029 /* If this is first AS set member, create new as-set segment. */
1030 if (asset == NULL)
1031 {
1032 asset = assegment_new (AS_SET, 1);
1033 if (! aspath->segments)
1034 aspath->segments = asset;
1035 else
1036 {
1037 struct assegment *seg = aspath->segments;
1038 while (seg->next)
1039 seg = seg->next;
1040 seg->next = asset;
1041 }
1042 asset->type = AS_SET;
1043 asset->length = 1;
1044 asset->as[0] = as;
1045 }
1046 else
1047 {
1048 /* Check this AS value already exists or not. */
1049 for (i = 0; i < asset->length; i++)
1050 if (asset->as[i] == as)
1051 return asset;
1052
1053 asset->length++;
1054 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
1055 asset->length * AS_VALUE_SIZE);
1056 asset->as[asset->length - 1] = as;
1057 }
1058
1059
1060 return asset;
1061}
1062
1063/* Modify as1 using as2 for aggregation. */
1064struct aspath *
1065aspath_aggregate (struct aspath *as1, struct aspath *as2)
1066{
1067 int i;
1068 int minlen = 0;
1069 int match = 0;
1070 int from;
1071 struct assegment *seg1 = as1->segments;
1072 struct assegment *seg2 = as2->segments;
1073 struct aspath *aspath = NULL;
1074 struct assegment *asset = NULL;
1075 struct assegment *prevseg = NULL;
1076
1077 /* First of all check common leading sequence. */
1078 while (seg1 && seg2)
1079 {
1080 /* Check segment type. */
1081 if (seg1->type != seg2->type)
1082 break;
1083
1084 /* Minimum segment length. */
1085 minlen = min (seg1->length, seg2->length);
1086
1087 for (match = 0; match < minlen; match++)
1088 if (seg1->as[match] != seg2->as[match])
1089 break;
1090
1091 if (match)
1092 {
1093 struct assegment *seg = assegment_new (seg1->type, 0);
1094
1095 seg = assegment_append_asns (seg, seg1->as, match);
1096
1097 if (! aspath)
1098 {
1099 aspath = aspath_new ();
1100 aspath->segments = seg;
1101 }
1102 else
1103 prevseg->next = seg;
1104
1105 prevseg = seg;
1106 }
1107
1108 if (match != minlen || match != seg1->length
1109 || seg1->length != seg2->length)
1110 break;
1111 /* We are moving on to the next segment to reset match */
1112 else
1113 match = 0;
1114
1115 seg1 = seg1->next;
1116 seg2 = seg2->next;
1117 }
1118
1119 if (! aspath)
1120 aspath = aspath_new();
1121
1122 /* Make as-set using rest of all information. */
1123 from = match;
1124 while (seg1)
1125 {
1126 for (i = from; i < seg1->length; i++)
1127 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1128
1129 from = 0;
1130 seg1 = seg1->next;
1131 }
1132
1133 from = match;
1134 while (seg2)
1135 {
1136 for (i = from; i < seg2->length; i++)
1137 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
1138
1139 from = 0;
1140 seg2 = seg2->next;
1141 }
1142
1143 assegment_normalise (aspath->segments);
1144 aspath_str_update (aspath);
1145 return aspath;
1146}
1147
1148/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1149 attribute, check the leftmost AS number in the AS_PATH attribute is
1150 or not the peer's AS number. */
1151int
1152aspath_firstas_check (struct aspath *aspath, as_t asno)
1153{
1154 if ( (aspath == NULL) || (aspath->segments == NULL) )
1155 return 0;
1156
1157 if (aspath->segments
1158 && (aspath->segments->type == AS_SEQUENCE)
1159 && (aspath->segments->as[0] == asno ))
1160 return 1;
1161
1162 return 0;
1163}
1164
1165unsigned int
1166aspath_get_first_as (struct aspath *aspath)
1167{
1168 if (aspath == NULL || aspath->segments == NULL)
1169 return 0;
1170
1171 return aspath->segments->as[0];
1172}
1173
1174unsigned int
1175aspath_get_last_as (struct aspath *aspath)
1176{
1177 int i;
1178 unsigned int last_as = 0;
1179 const struct assegment *seg;
1180
1181 if (aspath == NULL || aspath->segments == NULL)
1182 return last_as;
1183
1184 seg = aspath->segments;
1185
1186 while (seg)
1187 {
1188 if (seg->type == AS_SEQUENCE || seg->type == AS_CONFED_SEQUENCE)
1189 for (i = 0; i < seg->length; i++)
1190 last_as = seg->as[i];
1191 seg = seg->next;
1192 }
1193
1194 return last_as;
1195}
1196
1197/* AS path loop check. If aspath contains asno then return >= 1. */
1198int
1199aspath_loop_check (struct aspath *aspath, as_t asno)
1200{
1201 struct assegment *seg;
1202 int count = 0;
1203
1204 if ( (aspath == NULL) || (aspath->segments == NULL) )
1205 return 0;
1206
1207 seg = aspath->segments;
1208
1209 while (seg)
1210 {
1211 int i;
1212
1213 for (i = 0; i < seg->length; i++)
1214 if (seg->as[i] == asno)
1215 count++;
1216
1217 seg = seg->next;
1218 }
1219 return count;
1220}
1221
1222/* When all of AS path is private AS return 1. */
1223int
1224aspath_private_as_check (struct aspath *aspath)
1225{
1226 struct assegment *seg;
1227
1228 if ( !(aspath && aspath->segments) )
1229 return 0;
1230
1231 seg = aspath->segments;
1232
1233 while (seg)
1234 {
1235 int i;
1236
1237 for (i = 0; i < seg->length; i++)
1238 {
1239 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1240 return 0;
1241 }
1242 seg = seg->next;
1243 }
1244 return 1;
1245}
1246
1247/* Return True if the entire ASPATH consist of the specified ASN */
1248int
1249aspath_single_asn_check (struct aspath *aspath, as_t asn)
1250{
1251 struct assegment *seg;
1252
1253 if ( !(aspath && aspath->segments) )
1254 return 0;
1255
1256 seg = aspath->segments;
1257
1258 while (seg)
1259 {
1260 int i;
1261
1262 for (i = 0; i < seg->length; i++)
1263 {
1264 if (seg->as[i] != asn)
1265 return 0;
1266 }
1267 seg = seg->next;
1268 }
1269 return 1;
1270}
1271
1272/* Replace all instances of the target ASN with our own ASN */
1273struct aspath *
1274aspath_replace_specific_asn (struct aspath *aspath, as_t target_asn,
1275 as_t our_asn)
1276{
1277 struct aspath *new;
1278 struct assegment *seg;
1279
1280 new = aspath_dup(aspath);
1281 seg = new->segments;
1282
1283 while (seg)
1284 {
1285 int i;
1286
1287 for (i = 0; i < seg->length; i++)
1288 {
1289 if (seg->as[i] == target_asn)
1290 seg->as[i] = our_asn;
1291 }
1292 seg = seg->next;
1293 }
1294
1295 aspath_str_update(new);
1296 return new;
1297}
1298
1299/* Replace all private ASNs with our own ASN */
1300struct aspath *
1301aspath_replace_private_asns (struct aspath *aspath, as_t asn)
1302{
1303 struct aspath *new;
1304 struct assegment *seg;
1305
1306 new = aspath_dup(aspath);
1307 seg = new->segments;
1308
1309 while (seg)
1310 {
1311 int i;
1312
1313 for (i = 0; i < seg->length; i++)
1314 {
1315 if (BGP_AS_IS_PRIVATE(seg->as[i]))
1316 seg->as[i] = asn;
1317 }
1318 seg = seg->next;
1319 }
1320
1321 aspath_str_update(new);
1322 return new;
1323}
1324
1325/* Remove all private ASNs */
1326struct aspath *
1327aspath_remove_private_asns (struct aspath *aspath)
1328{
1329 struct aspath *new;
1330 struct assegment *seg;
1331 struct assegment *new_seg;
1332 struct assegment *last_new_seg;
1333 int i;
1334 int j;
1335 int public = 0;
1336
1337 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
1338
1339 new->json = NULL;
1340 new_seg = NULL;
1341 last_new_seg = NULL;
1342 seg = aspath->segments;
1343 while (seg)
1344 {
1345 public = 0;
1346 for (i = 0; i < seg->length; i++)
1347 {
1348 // ASN is public
1349 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1350 {
1351 public++;
1352 }
1353 }
1354
1355 // The entire segment is private so skip it
1356 if (!public)
1357 {
1358 seg = seg->next;
1359 continue;
1360 }
1361
1362 // The entire segment is public so copy it
1363 else if (public == seg->length)
1364 {
1365 new_seg = assegment_dup (seg);
1366 }
1367
1368 // The segment is a mix of public and private ASNs. Copy as many spots as
1369 // there are public ASNs then come back and fill in only the public ASNs.
1370 else
1371 {
1372 new_seg = assegment_new (seg->type, public);
1373 j = 0;
1374 for (i = 0; i < seg->length; i++)
1375 {
1376 // ASN is public
1377 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1378 {
1379 new_seg->as[j] = seg->as[i];
1380 j++;
1381 }
1382 }
1383 }
1384
1385 // This is the first segment so set the aspath segments pointer to this one
1386 if (!last_new_seg)
1387 new->segments = new_seg;
1388 else
1389 last_new_seg->next = new_seg;
1390
1391 last_new_seg = new_seg;
1392 seg = seg->next;
1393 }
1394
1395 aspath_str_update(new);
1396 return new;
1397}
1398
1399/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1400int
1401aspath_confed_check (struct aspath *aspath)
1402{
1403 struct assegment *seg;
1404
1405 if ( !(aspath && aspath->segments) )
1406 return 0;
1407
1408 seg = aspath->segments;
1409
1410 while (seg)
1411 {
1412 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1413 return 1;
1414 seg = seg->next;
1415 }
1416 return 0;
1417}
1418
1419/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1420 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1421int
1422aspath_left_confed_check (struct aspath *aspath)
1423{
1424
1425 if ( !(aspath && aspath->segments) )
1426 return 0;
1427
1428 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1429 || (aspath->segments->type == AS_CONFED_SET) )
1430 return 1;
1431
1432 return 0;
1433}
1434
1435/* Merge as1 to as2. as2 should be uninterned aspath. */
1436static struct aspath *
1437aspath_merge (struct aspath *as1, struct aspath *as2)
1438{
1439 struct assegment *last, *new;
1440
1441 if (! as1 || ! as2)
1442 return NULL;
1443
1444 last = new = assegment_dup_all (as1->segments);
1445
1446 /* find the last valid segment */
1447 while (last && last->next)
1448 last = last->next;
1449
1450 last->next = as2->segments;
1451 as2->segments = new;
1452 aspath_str_update (as2);
1453 return as2;
1454}
1455
1456/* Prepend as1 to as2. as2 should be uninterned aspath. */
1457struct aspath *
1458aspath_prepend (struct aspath *as1, struct aspath *as2)
1459{
1460 struct assegment *seg1;
1461 struct assegment *seg2;
1462
1463 if (! as1 || ! as2)
1464 return NULL;
1465
1466 seg1 = as1->segments;
1467 seg2 = as2->segments;
1468
1469 /* If as2 is empty, only need to dupe as1's chain onto as2 */
1470 if (seg2 == NULL)
1471 {
1472 as2->segments = assegment_dup_all (as1->segments);
1473 aspath_str_update (as2);
1474 return as2;
1475 }
1476
1477 /* If as1 is empty AS, no prepending to do. */
1478 if (seg1 == NULL)
1479 return as2;
1480
1481 /* find the tail as1's segment chain. */
1482 while (seg1 && seg1->next)
1483 seg1 = seg1->next;
1484
1485 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1486 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1487 as2 = aspath_delete_confed_seq (as2);
1488
1489 /* Compare last segment type of as1 and first segment type of as2. */
1490 if (seg1->type != seg2->type)
1491 return aspath_merge (as1, as2);
1492
1493 if (seg1->type == AS_SEQUENCE)
1494 {
1495 /* We have two chains of segments, as1->segments and seg2,
1496 * and we have to attach them together, merging the attaching
1497 * segments together into one.
1498 *
1499 * 1. dupe as1->segments onto head of as2
1500 * 2. merge seg2's asns onto last segment of this new chain
1501 * 3. attach chain after seg2
1502 */
1503
1504 /* dupe as1 onto as2's head */
1505 seg1 = as2->segments = assegment_dup_all (as1->segments);
1506
1507 /* refind the tail of as2, reusing seg1 */
1508 while (seg1 && seg1->next)
1509 seg1 = seg1->next;
1510
1511 /* merge the old head, seg2, into tail, seg1 */
1512 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1513
1514 /* bypass the merged seg2, and attach any chain after it to
1515 * chain descending from as2's head
1516 */
1517 seg1->next = seg2->next;
1518
1519 /* seg2 is now referenceless and useless*/
1520 assegment_free (seg2);
1521
1522 /* we've now prepended as1's segment chain to as2, merging
1523 * the inbetween AS_SEQUENCE of seg2 in the process
1524 */
1525 aspath_str_update (as2);
1526 return as2;
1527 }
1528 else
1529 {
1530 /* AS_SET merge code is needed at here. */
1531 return aspath_merge (as1, as2);
1532 }
1533 /* XXX: Ermmm, what if as1 has multiple segments?? */
1534
1535 /* Not reached */
1536}
1537
1538/* Iterate over AS_PATH segments and wipe all occurences of the
1539 * listed AS numbers. Hence some segments may lose some or even
1540 * all data on the way, the operation is implemented as a smarter
1541 * version of aspath_dup(), which allocates memory to hold the new
1542 * data, not the original. The new AS path is returned.
1543 */
1544struct aspath *
1545aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1546{
1547 struct assegment * srcseg, * exclseg, * lastseg;
1548 struct aspath * newpath;
1549
1550 newpath = aspath_new();
1551 lastseg = NULL;
1552
1553 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1554 {
1555 unsigned i, y, newlen = 0, done = 0, skip_as;
1556 struct assegment * newseg;
1557
1558 /* Find out, how much ASns are we going to pick from this segment.
1559 * We can't perform filtering right inline, because the size of
1560 * the new segment isn't known at the moment yet.
1561 */
1562 for (i = 0; i < srcseg->length; i++)
1563 {
1564 skip_as = 0;
1565 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1566 for (y = 0; y < exclseg->length; y++)
1567 if (srcseg->as[i] == exclseg->as[y])
1568 {
1569 skip_as = 1;
1570 // There's no sense in testing the rest of exclusion list, bail out.
1571 break;
1572 }
1573 if (!skip_as)
1574 newlen++;
1575 }
1576 /* newlen is now the number of ASns to copy */
1577 if (!newlen)
1578 continue;
1579
1580 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1581 newseg = assegment_new (srcseg->type, newlen);
1582 for (i = 0; i < srcseg->length; i++)
1583 {
1584 skip_as = 0;
1585 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1586 for (y = 0; y < exclseg->length; y++)
1587 if (srcseg->as[i] == exclseg->as[y])
1588 {
1589 skip_as = 1;
1590 break;
1591 }
1592 if (skip_as)
1593 continue;
1594 newseg->as[done++] = srcseg->as[i];
1595 }
1596 /* At his point newlen must be equal to done, and both must be positive. Append
1597 * the filtered segment to the gross result. */
1598 if (!lastseg)
1599 newpath->segments = newseg;
1600 else
1601 lastseg->next = newseg;
1602 lastseg = newseg;
1603 }
1604 aspath_str_update (newpath);
1605 /* We are happy returning even an empty AS_PATH, because the administrator
1606 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1607 * by having a match rule against certain AS_PATH regexps in the route-map index.
1608 */
1609 aspath_free (source);
1610 return newpath;
1611}
1612
1613/* Add specified AS to the leftmost of aspath. */
1614static struct aspath *
1615aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num)
1616{
1617 struct assegment *assegment = aspath->segments;
1618 unsigned i;
1619
1620 if (assegment && assegment->type == type)
1621 {
1622 /* extend existing segment */
1623 aspath->segments = assegment_prepend_asns (aspath->segments, asno, num);
1624 }
1625 else
1626 {
1627 /* prepend with new segment */
1628 struct assegment *newsegment = assegment_new (type, num);
1629 for (i = 0; i < num; i++)
1630 newsegment->as[i] = asno;
1631
1632 /* insert potentially replacing empty segment */
1633 if (assegment && assegment->length == 0)
1634 {
1635 newsegment->next = assegment->next;
1636 assegment_free (assegment);
1637 }
1638 else
1639 newsegment->next = assegment;
1640 aspath->segments = newsegment;
1641 }
1642
1643 aspath_str_update (aspath);
1644 return aspath;
1645}
1646
1647/* Add specified AS to the leftmost of aspath num times. */
1648struct aspath *
1649aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num)
1650{
1651 return aspath_add_asns (aspath, asno, AS_SEQUENCE, num);
1652}
1653
1654/* Add specified AS to the leftmost of aspath. */
1655struct aspath *
1656aspath_add_seq (struct aspath *aspath, as_t asno)
1657{
1658 return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1);
1659}
1660
1661/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1662 as2's leftmost AS is same return 1. */
1663int
1664aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
1665{
1666 const struct assegment *seg1;
1667 const struct assegment *seg2;
1668
1669 if (!(aspath1 && aspath2))
1670 return 0;
1671
1672 seg1 = aspath1->segments;
1673 seg2 = aspath2->segments;
1674
1675 /* If both paths are originated in this AS then we do want to compare MED */
1676 if (!seg1 && !seg2)
1677 return 1;
1678
1679 /* find first non-confed segments for each */
1680 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1681 || (seg1->type == AS_CONFED_SET)))
1682 seg1 = seg1->next;
1683
1684 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1685 || (seg2->type == AS_CONFED_SET)))
1686 seg2 = seg2->next;
1687
1688 /* Check as1's */
1689 if (!(seg1 && seg2
1690 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
1691 return 0;
1692
1693 if (seg1->as[0] == seg2->as[0])
1694 return 1;
1695
1696 return 0;
1697}
1698
1699/* Truncate an aspath after a number of hops, and put the hops remaining
1700 * at the front of another aspath. Needed for AS4 compat.
1701 *
1702 * Returned aspath is a /new/ aspath, which should either by free'd or
1703 * interned by the caller, as desired.
1704 */
1705struct aspath *
1706aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1707{
1708 struct assegment *seg, *newseg, *prevseg = NULL;
1709 struct aspath *newpath = NULL, *mergedpath;
1710 int hops, cpasns = 0;
1711
1712 if (!aspath)
1713 return NULL;
1714
1715 seg = aspath->segments;
1716
1717 /* CONFEDs should get reconciled too.. */
1718 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1719 - aspath_count_hops (as4path);
1720
1721 if (hops < 0)
1722 {
1723 if (BGP_DEBUG (as4, AS4))
1724 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1725 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1726 * which is daft behaviour - it contains vital loop-detection
1727 * information which must have been removed from AS_PATH.
1728 */
1729 hops = aspath_count_hops (aspath);
1730 }
1731
1732 if (!hops)
1733 {
1734 newpath = aspath_dup (as4path);
1735 aspath_str_update(newpath);
1736 return newpath;
1737 }
1738
1739 if ( BGP_DEBUG(as4, AS4))
1740 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1741 aspath->str, as4path->str);
1742
1743 while (seg && hops > 0)
1744 {
1745 switch (seg->type)
1746 {
1747 case AS_SET:
1748 case AS_CONFED_SET:
1749 hops--;
1750 cpasns = seg->length;
1751 break;
1752 case AS_CONFED_SEQUENCE:
1753 /* Should never split a confed-sequence, if hop-count
1754 * suggests we must then something's gone wrong somewhere.
1755 *
1756 * Most important goal is to preserve AS_PATHs prime function
1757 * as loop-detector, so we fudge the numbers so that the entire
1758 * confed-sequence is merged in.
1759 */
1760 if (hops < seg->length)
1761 {
1762 if (BGP_DEBUG (as4, AS4))
1763 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1764 " across 2/4 ASN boundary somewhere, broken..");
1765 hops = seg->length;
1766 }
1767 case AS_SEQUENCE:
1768 cpasns = MIN(seg->length, hops);
1769 hops -= seg->length;
1770 }
1771
1772 assert (cpasns <= seg->length);
1773
1774 newseg = assegment_new (seg->type, 0);
1775 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1776
1777 if (!newpath)
1778 {
1779 newpath = aspath_new ();
1780 newpath->segments = newseg;
1781 }
1782 else
1783 prevseg->next = newseg;
1784
1785 prevseg = newseg;
1786 seg = seg->next;
1787 }
1788
1789 /* We may be able to join some segments here, and we must
1790 * do this because... we want normalised aspaths in out hash
1791 * and we do not want to stumble in aspath_put.
1792 */
1793 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1794 aspath_free (newpath);
1795 mergedpath->segments = assegment_normalise (mergedpath->segments);
1796 aspath_str_update (mergedpath);
1797
1798 if ( BGP_DEBUG(as4, AS4))
1799 zlog_debug ("[AS4] result of synthesizing is %s",
1800 mergedpath->str);
1801
1802 return mergedpath;
1803}
1804
1805/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1806 as2's leftmost AS is same return 1. (confederation as-path
1807 only). */
1808int
1809aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
1810{
1811 if (! (aspath1 && aspath2) )
1812 return 0;
1813
1814 if ( !(aspath1->segments && aspath2->segments) )
1815 return 0;
1816
1817 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1818 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
1819 return 0;
1820
1821 if (aspath1->segments->as[0] == aspath2->segments->as[0])
1822 return 1;
1823
1824 return 0;
1825}
1826
1827/* Delete all AS_CONFED_SEQUENCE/SET segments from aspath.
1828 * RFC 5065 section 4.1.c.1
1829 *
1830 * 1) if any path segments of the AS_PATH are of the type
1831 * AS_CONFED_SEQUENCE or AS_CONFED_SET, those segments MUST be
1832 * removed from the AS_PATH attribute, leaving the sanitized
1833 * AS_PATH attribute to be operated on by steps 2, 3 or 4.
1834 */
1835struct aspath *
1836aspath_delete_confed_seq (struct aspath *aspath)
1837{
1838 struct assegment *seg, *prev, *next;
1839 char removed_confed_segment;
1840
1841 if (!(aspath && aspath->segments))
1842 return aspath;
1843
1844 seg = aspath->segments;
1845 removed_confed_segment = 0;
1846 next = NULL;
1847 prev = NULL;
1848
1849 while (seg)
1850 {
1851 next = seg->next;
1852
1853 if (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET)
1854 {
1855 /* This is the first segment in the aspath */
1856 if (aspath->segments == seg)
1857 aspath->segments = seg->next;
1858 else
1859 prev->next = seg->next;
1860
1861 assegment_free (seg);
1862 removed_confed_segment = 1;
1863 }
1864 else
1865 prev = seg;
1866
1867 seg = next;
1868 }
1869
1870 if (removed_confed_segment)
1871 aspath_str_update (aspath);
1872
1873 return aspath;
1874}
1875
1876/* Add new AS number to the leftmost part of the aspath as
1877 AS_CONFED_SEQUENCE. */
1878struct aspath*
1879aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1880{
1881 return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1);
1882}
1883
1884/* Add new as value to as path structure. */
1885static void
1886aspath_as_add (struct aspath *as, as_t asno)
1887{
1888 struct assegment *seg = as->segments;
1889
1890 if (!seg)
1891 return;
1892
1893 /* Last segment search procedure. */
1894 while (seg->next)
1895 seg = seg->next;
1896
1897 assegment_append_asns (seg, &asno, 1);
1898}
1899
1900/* Add new as segment to the as path. */
1901static void
1902aspath_segment_add (struct aspath *as, int type)
1903{
1904 struct assegment *seg = as->segments;
1905 struct assegment *new = assegment_new (type, 0);
1906
1907 if (seg)
1908 {
1909 while (seg->next)
1910 seg = seg->next;
1911 seg->next = new;
1912 }
1913 else
1914 as->segments = new;
1915}
1916
1917struct aspath *
1918aspath_empty (void)
1919{
1920 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
1921}
1922
1923struct aspath *
1924aspath_empty_get (void)
1925{
1926 struct aspath *aspath;
1927
1928 aspath = aspath_new ();
1929 aspath_make_str_count (aspath);
1930 return aspath;
1931}
1932
1933unsigned long
1934aspath_count (void)
1935{
1936 return ashash->count;
1937}
1938
1939/*
1940 Theoretically, one as path can have:
1941
1942 One BGP packet size should be less than 4096.
1943 One BGP attribute size should be less than 4096 - BGP header size.
1944 One BGP aspath size should be less than 4096 - BGP header size -
1945 BGP mandantry attribute size.
1946*/
1947
1948/* AS path string lexical token enum. */
1949enum as_token
1950{
1951 as_token_asval,
1952 as_token_set_start,
1953 as_token_set_end,
1954 as_token_confed_seq_start,
1955 as_token_confed_seq_end,
1956 as_token_confed_set_start,
1957 as_token_confed_set_end,
1958 as_token_unknown
1959};
1960
1961/* Return next token and point for string parse. */
1962static const char *
1963aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
1964{
1965 const char *p = buf;
1966
1967 /* Skip seperators (space for sequences, ',' for sets). */
1968 while (isspace ((int) *p) || *p == ',')
1969 p++;
1970
1971 /* Check the end of the string and type specify characters
1972 (e.g. {}()). */
1973 switch (*p)
1974 {
1975 case '\0':
1976 return NULL;
1977 case '{':
1978 *token = as_token_set_start;
1979 p++;
1980 return p;
1981 case '}':
1982 *token = as_token_set_end;
1983 p++;
1984 return p;
1985 case '(':
1986 *token = as_token_confed_seq_start;
1987 p++;
1988 return p;
1989 case ')':
1990 *token = as_token_confed_seq_end;
1991 p++;
1992 return p;
1993 case '[':
1994 *token = as_token_confed_set_start;
1995 p++;
1996 return p;
1997 case ']':
1998 *token = as_token_confed_set_end;
1999 p++;
2000 return p;
2001 }
2002
2003 /* Check actual AS value. */
2004 if (isdigit ((int) *p))
2005 {
2006 as_t asval;
2007
2008 *token = as_token_asval;
2009 asval = (*p - '0');
2010 p++;
2011
2012 while (isdigit ((int) *p))
2013 {
2014 asval *= 10;
2015 asval += (*p - '0');
2016 p++;
2017 }
2018 *asno = asval;
2019 return p;
2020 }
2021
2022 /* There is no match then return unknown token. */
2023 *token = as_token_unknown;
2024 return p++;
2025}
2026
2027struct aspath *
2028aspath_str2aspath (const char *str)
2029{
2030 enum as_token token = as_token_unknown;
2031 u_short as_type;
2032 u_long asno = 0;
2033 struct aspath *aspath;
2034 int needtype;
2035
2036 aspath = aspath_new ();
2037
2038 /* We start default type as AS_SEQUENCE. */
2039 as_type = AS_SEQUENCE;
2040 needtype = 1;
2041
2042 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
2043 {
2044 switch (token)
2045 {
2046 case as_token_asval:
2047 if (needtype)
2048 {
2049 aspath_segment_add (aspath, as_type);
2050 needtype = 0;
2051 }
2052 aspath_as_add (aspath, asno);
2053 break;
2054 case as_token_set_start:
2055 as_type = AS_SET;
2056 aspath_segment_add (aspath, as_type);
2057 needtype = 0;
2058 break;
2059 case as_token_set_end:
2060 as_type = AS_SEQUENCE;
2061 needtype = 1;
2062 break;
2063 case as_token_confed_seq_start:
2064 as_type = AS_CONFED_SEQUENCE;
2065 aspath_segment_add (aspath, as_type);
2066 needtype = 0;
2067 break;
2068 case as_token_confed_seq_end:
2069 as_type = AS_SEQUENCE;
2070 needtype = 1;
2071 break;
2072 case as_token_confed_set_start:
2073 as_type = AS_CONFED_SET;
2074 aspath_segment_add (aspath, as_type);
2075 needtype = 0;
2076 break;
2077 case as_token_confed_set_end:
2078 as_type = AS_SEQUENCE;
2079 needtype = 1;
2080 break;
2081 case as_token_unknown:
2082 default:
2083 aspath_free (aspath);
2084 return NULL;
2085 }
2086 }
2087
2088 aspath_make_str_count (aspath);
2089
2090 return aspath;
2091}
2092
2093/* Make hash value by raw aspath data. */
2094unsigned int
2095aspath_key_make (void *p)
2096{
2097 struct aspath *aspath = (struct aspath *) p;
2098 unsigned int key = 0;
2099
2100 if (!aspath->str)
2101 aspath_str_update (aspath);
2102
2103 key = jhash (aspath->str, aspath->str_len, 2334325);
2104
2105 return key;
2106}
2107
2108/* If two aspath have same value then return 1 else return 0 */
2109int
2110aspath_cmp (const void *arg1, const void *arg2)
2111{
2112 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
2113 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
2114
2115 while (seg1 || seg2)
2116 {
2117 int i;
2118 if ((!seg1 && seg2) || (seg1 && !seg2))
2119 return 0;
2120 if (seg1->type != seg2->type)
2121 return 0;
2122 if (seg1->length != seg2->length)
2123 return 0;
2124 for (i = 0; i < seg1->length; i++)
2125 if (seg1->as[i] != seg2->as[i])
2126 return 0;
2127 seg1 = seg1->next;
2128 seg2 = seg2->next;
2129 }
2130 return 1;
2131}
2132
2133/* AS path hash initialize. */
2134void
2135aspath_init (void)
2136{
2137 ashash = hash_create_size (32768, aspath_key_make, aspath_cmp);
2138}
2139
2140void
2141aspath_finish (void)
2142{
2143 hash_clean (ashash, (void (*)(void *))aspath_free);
2144 hash_free (ashash);
2145 ashash = NULL;
2146
2147 if (snmp_stream)
2148 stream_free (snmp_stream);
2149}
2150
2151/* return and as path value */
2152const char *
2153aspath_print (struct aspath *as)
2154{
2155 return (as ? as->str : NULL);
2156}
2157
2158/* Printing functions */
2159/* Feed the AS_PATH to the vty; the suffix string follows it only in case
2160 * AS_PATH wasn't empty.
2161 */
2162void
2163aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
2164{
2165 assert (format);
2166 vty_out (vty, format, as->str);
2167 if (as->str_len && strlen (suffix))
2168 vty_out (vty, "%s", suffix);
2169}
2170
2171static void
2172aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
2173{
2174 struct aspath *as;
2175
2176 as = (struct aspath *) backet->data;
2177
2178 vty_out (vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt);
2179 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
2180}
2181
2182/* Print all aspath and hash information. This function is used from
2183 `show [ip] bgp paths' command. */
2184void
2185aspath_print_all_vty (struct vty *vty)
2186{
2187 hash_iterate (ashash,
2188 (void (*) (struct hash_backet *, void *))
2189 aspath_show_all_iterator,
2190 vty);
2191}