]> git.proxmox.com Git - mirror_frr.git/blame_incremental - bgpd/bgp_aspath.c
*: add indent control files
[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 *
5 * This file is part of GNU Zebra.
6 *
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
10 * later version.
11 *
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.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
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 /* fallthru */
1768 case AS_SEQUENCE:
1769 cpasns = MIN(seg->length, hops);
1770 hops -= seg->length;
1771 }
1772
1773 assert (cpasns <= seg->length);
1774
1775 newseg = assegment_new (seg->type, 0);
1776 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1777
1778 if (!newpath)
1779 {
1780 newpath = aspath_new ();
1781 newpath->segments = newseg;
1782 }
1783 else
1784 prevseg->next = newseg;
1785
1786 prevseg = newseg;
1787 seg = seg->next;
1788 }
1789
1790 /* We may be able to join some segments here, and we must
1791 * do this because... we want normalised aspaths in out hash
1792 * and we do not want to stumble in aspath_put.
1793 */
1794 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1795 aspath_free (newpath);
1796 mergedpath->segments = assegment_normalise (mergedpath->segments);
1797 aspath_str_update (mergedpath);
1798
1799 if ( BGP_DEBUG(as4, AS4))
1800 zlog_debug ("[AS4] result of synthesizing is %s",
1801 mergedpath->str);
1802
1803 return mergedpath;
1804}
1805
1806/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1807 as2's leftmost AS is same return 1. (confederation as-path
1808 only). */
1809int
1810aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
1811{
1812 if (! (aspath1 && aspath2) )
1813 return 0;
1814
1815 if ( !(aspath1->segments && aspath2->segments) )
1816 return 0;
1817
1818 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1819 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
1820 return 0;
1821
1822 if (aspath1->segments->as[0] == aspath2->segments->as[0])
1823 return 1;
1824
1825 return 0;
1826}
1827
1828/* Delete all AS_CONFED_SEQUENCE/SET segments from aspath.
1829 * RFC 5065 section 4.1.c.1
1830 *
1831 * 1) if any path segments of the AS_PATH are of the type
1832 * AS_CONFED_SEQUENCE or AS_CONFED_SET, those segments MUST be
1833 * removed from the AS_PATH attribute, leaving the sanitized
1834 * AS_PATH attribute to be operated on by steps 2, 3 or 4.
1835 */
1836struct aspath *
1837aspath_delete_confed_seq (struct aspath *aspath)
1838{
1839 struct assegment *seg, *prev, *next;
1840 char removed_confed_segment;
1841
1842 if (!(aspath && aspath->segments))
1843 return aspath;
1844
1845 seg = aspath->segments;
1846 removed_confed_segment = 0;
1847 next = NULL;
1848 prev = NULL;
1849
1850 while (seg)
1851 {
1852 next = seg->next;
1853
1854 if (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET)
1855 {
1856 /* This is the first segment in the aspath */
1857 if (aspath->segments == seg)
1858 aspath->segments = seg->next;
1859 else
1860 prev->next = seg->next;
1861
1862 assegment_free (seg);
1863 removed_confed_segment = 1;
1864 }
1865 else
1866 prev = seg;
1867
1868 seg = next;
1869 }
1870
1871 if (removed_confed_segment)
1872 aspath_str_update (aspath);
1873
1874 return aspath;
1875}
1876
1877/* Add new AS number to the leftmost part of the aspath as
1878 AS_CONFED_SEQUENCE. */
1879struct aspath*
1880aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1881{
1882 return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1);
1883}
1884
1885/* Add new as value to as path structure. */
1886static void
1887aspath_as_add (struct aspath *as, as_t asno)
1888{
1889 struct assegment *seg = as->segments;
1890
1891 if (!seg)
1892 return;
1893
1894 /* Last segment search procedure. */
1895 while (seg->next)
1896 seg = seg->next;
1897
1898 assegment_append_asns (seg, &asno, 1);
1899}
1900
1901/* Add new as segment to the as path. */
1902static void
1903aspath_segment_add (struct aspath *as, int type)
1904{
1905 struct assegment *seg = as->segments;
1906 struct assegment *new = assegment_new (type, 0);
1907
1908 if (seg)
1909 {
1910 while (seg->next)
1911 seg = seg->next;
1912 seg->next = new;
1913 }
1914 else
1915 as->segments = new;
1916}
1917
1918struct aspath *
1919aspath_empty (void)
1920{
1921 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
1922}
1923
1924struct aspath *
1925aspath_empty_get (void)
1926{
1927 struct aspath *aspath;
1928
1929 aspath = aspath_new ();
1930 aspath_make_str_count (aspath);
1931 return aspath;
1932}
1933
1934unsigned long
1935aspath_count (void)
1936{
1937 return ashash->count;
1938}
1939
1940/*
1941 Theoretically, one as path can have:
1942
1943 One BGP packet size should be less than 4096.
1944 One BGP attribute size should be less than 4096 - BGP header size.
1945 One BGP aspath size should be less than 4096 - BGP header size -
1946 BGP mandantry attribute size.
1947*/
1948
1949/* AS path string lexical token enum. */
1950enum as_token
1951{
1952 as_token_asval,
1953 as_token_set_start,
1954 as_token_set_end,
1955 as_token_confed_seq_start,
1956 as_token_confed_seq_end,
1957 as_token_confed_set_start,
1958 as_token_confed_set_end,
1959 as_token_unknown
1960};
1961
1962/* Return next token and point for string parse. */
1963static const char *
1964aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
1965{
1966 const char *p = buf;
1967
1968 /* Skip seperators (space for sequences, ',' for sets). */
1969 while (isspace ((int) *p) || *p == ',')
1970 p++;
1971
1972 /* Check the end of the string and type specify characters
1973 (e.g. {}()). */
1974 switch (*p)
1975 {
1976 case '\0':
1977 return NULL;
1978 case '{':
1979 *token = as_token_set_start;
1980 p++;
1981 return p;
1982 case '}':
1983 *token = as_token_set_end;
1984 p++;
1985 return p;
1986 case '(':
1987 *token = as_token_confed_seq_start;
1988 p++;
1989 return p;
1990 case ')':
1991 *token = as_token_confed_seq_end;
1992 p++;
1993 return p;
1994 case '[':
1995 *token = as_token_confed_set_start;
1996 p++;
1997 return p;
1998 case ']':
1999 *token = as_token_confed_set_end;
2000 p++;
2001 return p;
2002 }
2003
2004 /* Check actual AS value. */
2005 if (isdigit ((int) *p))
2006 {
2007 as_t asval;
2008
2009 *token = as_token_asval;
2010 asval = (*p - '0');
2011 p++;
2012
2013 while (isdigit ((int) *p))
2014 {
2015 asval *= 10;
2016 asval += (*p - '0');
2017 p++;
2018 }
2019 *asno = asval;
2020 return p;
2021 }
2022
2023 /* There is no match then return unknown token. */
2024 *token = as_token_unknown;
2025 return p++;
2026}
2027
2028struct aspath *
2029aspath_str2aspath (const char *str)
2030{
2031 enum as_token token = as_token_unknown;
2032 u_short as_type;
2033 u_long asno = 0;
2034 struct aspath *aspath;
2035 int needtype;
2036
2037 aspath = aspath_new ();
2038
2039 /* We start default type as AS_SEQUENCE. */
2040 as_type = AS_SEQUENCE;
2041 needtype = 1;
2042
2043 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
2044 {
2045 switch (token)
2046 {
2047 case as_token_asval:
2048 if (needtype)
2049 {
2050 aspath_segment_add (aspath, as_type);
2051 needtype = 0;
2052 }
2053 aspath_as_add (aspath, asno);
2054 break;
2055 case as_token_set_start:
2056 as_type = AS_SET;
2057 aspath_segment_add (aspath, as_type);
2058 needtype = 0;
2059 break;
2060 case as_token_set_end:
2061 as_type = AS_SEQUENCE;
2062 needtype = 1;
2063 break;
2064 case as_token_confed_seq_start:
2065 as_type = AS_CONFED_SEQUENCE;
2066 aspath_segment_add (aspath, as_type);
2067 needtype = 0;
2068 break;
2069 case as_token_confed_seq_end:
2070 as_type = AS_SEQUENCE;
2071 needtype = 1;
2072 break;
2073 case as_token_confed_set_start:
2074 as_type = AS_CONFED_SET;
2075 aspath_segment_add (aspath, as_type);
2076 needtype = 0;
2077 break;
2078 case as_token_confed_set_end:
2079 as_type = AS_SEQUENCE;
2080 needtype = 1;
2081 break;
2082 case as_token_unknown:
2083 default:
2084 aspath_free (aspath);
2085 return NULL;
2086 }
2087 }
2088
2089 aspath_make_str_count (aspath);
2090
2091 return aspath;
2092}
2093
2094/* Make hash value by raw aspath data. */
2095unsigned int
2096aspath_key_make (void *p)
2097{
2098 struct aspath *aspath = (struct aspath *) p;
2099 unsigned int key = 0;
2100
2101 if (!aspath->str)
2102 aspath_str_update (aspath);
2103
2104 key = jhash (aspath->str, aspath->str_len, 2334325);
2105
2106 return key;
2107}
2108
2109/* If two aspath have same value then return 1 else return 0 */
2110int
2111aspath_cmp (const void *arg1, const void *arg2)
2112{
2113 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
2114 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
2115
2116 while (seg1 || seg2)
2117 {
2118 int i;
2119 if ((!seg1 && seg2) || (seg1 && !seg2))
2120 return 0;
2121 if (seg1->type != seg2->type)
2122 return 0;
2123 if (seg1->length != seg2->length)
2124 return 0;
2125 for (i = 0; i < seg1->length; i++)
2126 if (seg1->as[i] != seg2->as[i])
2127 return 0;
2128 seg1 = seg1->next;
2129 seg2 = seg2->next;
2130 }
2131 return 1;
2132}
2133
2134/* AS path hash initialize. */
2135void
2136aspath_init (void)
2137{
2138 ashash = hash_create_size (32768, aspath_key_make, aspath_cmp, NULL);
2139}
2140
2141void
2142aspath_finish (void)
2143{
2144 hash_clean (ashash, (void (*)(void *))aspath_free);
2145 hash_free (ashash);
2146 ashash = NULL;
2147
2148 if (snmp_stream)
2149 stream_free (snmp_stream);
2150}
2151
2152/* return and as path value */
2153const char *
2154aspath_print (struct aspath *as)
2155{
2156 return (as ? as->str : NULL);
2157}
2158
2159/* Printing functions */
2160/* Feed the AS_PATH to the vty; the suffix string follows it only in case
2161 * AS_PATH wasn't empty.
2162 */
2163void
2164aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
2165{
2166 assert (format);
2167 vty_out (vty, format, as->str);
2168 if (as->str_len && strlen (suffix))
2169 vty_out (vty, "%s", suffix);
2170}
2171
2172static void
2173aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
2174{
2175 struct aspath *as;
2176
2177 as = (struct aspath *) backet->data;
2178
2179 vty_out (vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt);
2180 vty_out (vty, "%s\n", as->str);
2181}
2182
2183/* Print all aspath and hash information. This function is used from
2184 `show [ip] bgp paths' command. */
2185void
2186aspath_print_all_vty (struct vty *vty)
2187{
2188 hash_iterate (ashash,
2189 (void (*) (struct hash_backet *, void *))
2190 aspath_show_all_iterator,
2191 vty);
2192}