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