]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_aspath.c
[bgpd] fix some leaks introduced in aspath rewrite.
[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
32 #include "bgpd/bgpd.h"
33 #include "bgpd/bgp_aspath.h"
34 \f
35 /* Attr. Flags and Attr. Type Code. */
36 #define AS_HEADER_SIZE 2
37
38 /* Two octet is used for AS value. */
39 #define AS_VALUE_SIZE sizeof (as_t)
40
41 /* Maximum protocol segment length value */
42 #define AS_SEGMENT_MAX 255
43
44 /* The following length and size macros relate specifically to Quagga's
45 * internal representation of AS-Segments, not per se to the on-wire
46 * sizes and lengths. At present (200508) they sort of match, however
47 * the ONLY functions which should now about the on-wire syntax are
48 * aspath_put, assegment_put and assegment_parse.
49 */
50
51 /* Calculated size in bytes of ASN segment data to hold N ASN's */
52 #define ASSEGMENT_DATA_SIZE(N) ((N) * AS_VALUE_SIZE)
53
54 /* Calculated size of segment struct to hold N ASN's */
55 #define ASSEGMENT_SIZE(N) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N))
56
57 /* AS segment octet length. */
58 #define ASSEGMENT_LEN(X) ASSEGMENT_SIZE((X)->length)
59
60 /* AS_SEQUENCE segments can be packed together */
61 /* Can the types of X and Y be considered for packing? */
62 #define ASSEGMENT_TYPES_PACKABLE(X,Y) \
63 ( ((X)->type == (Y)->type) \
64 && ((X)->type == AS_SEQUENCE))
65 /* Types and length of X,Y suitable for packing? */
66 #define ASSEGMENTS_PACKABLE(X,Y) \
67 ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \
68 && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) )
69
70 /* As segment header - the on-wire representation
71 * NOT the internal representation!
72 */
73 struct assegment_header
74 {
75 u_char type;
76 u_char length;
77 };
78
79 /* Hash for aspath. This is the top level structure of AS path. */
80 struct hash *ashash;
81 \f
82 static inline as_t *
83 assegment_data_new (int num)
84 {
85 return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num)));
86 }
87
88 static inline void
89 assegment_data_free (as_t *asdata)
90 {
91 XFREE (MTYPE_AS_SEG_DATA,asdata);
92 }
93
94 /* Get a new segment. Note that 0 is an allowed length,
95 * and will result in a segment with no allocated data segment.
96 * the caller should immediately assign data to the segment, as the segment
97 * otherwise is not generally valid
98 */
99 static struct assegment *
100 assegment_new (u_char type, u_short length)
101 {
102 struct assegment *new;
103
104 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
105
106 if (length)
107 new->as = assegment_data_new (length);
108
109 new->length = length;
110 new->type = type;
111
112 return new;
113 }
114
115 static void
116 assegment_free (struct assegment *seg)
117 {
118 if (!seg)
119 return;
120
121 if (seg->as)
122 XFREE (MTYPE_AS_SEG_DATA, seg->as);
123 memset (seg, 0xfe, sizeof(struct assegment));
124 XFREE (MTYPE_AS_SEG, seg);
125
126 return;
127 }
128
129 /* free entire chain of segments */
130 static void
131 assegment_free_all (struct assegment *seg)
132 {
133 struct assegment *prev;
134
135 while (seg)
136 {
137 prev = seg;
138 seg = seg->next;
139 assegment_free (prev);
140 }
141 }
142
143 /* Duplicate just the given assegment and its data */
144 static struct assegment *
145 assegment_dup (struct assegment *seg)
146 {
147 struct assegment *new;
148
149 new = assegment_new (seg->type, seg->length);
150 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length) );
151
152 return new;
153 }
154
155 /* Duplicate entire chain of assegments, return the head */
156 static struct assegment *
157 assegment_dup_all (struct assegment *seg)
158 {
159 struct assegment *new = NULL;
160 struct assegment *head = NULL;
161
162 while (seg)
163 {
164 if (head)
165 {
166 new->next = assegment_dup (seg);
167 new = new->next;
168 }
169 else
170 head = new = assegment_dup (seg);
171
172 seg = seg->next;
173 }
174 return head;
175 }
176
177 /* prepend the as number to given segment, given num of times */
178 static struct assegment *
179 assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
180 {
181 as_t *newas;
182
183 if (!num)
184 return seg;
185
186 if (num >= AS_SEGMENT_MAX)
187 return seg; /* we don't do huge prepends */
188
189 newas = assegment_data_new (seg->length + num);
190
191 if (newas)
192 {
193 int i;
194 for (i = 0; i < num; i++)
195 newas[i] = asnum;
196
197 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length));
198 XFREE (MTYPE_AS_SEG_DATA, seg->as);
199 seg->as = newas;
200 seg->length += num;
201 return seg;
202 }
203
204 assegment_free_all (seg);
205 return NULL;
206 }
207
208 /* append given array of as numbers to the segment */
209 static struct assegment *
210 assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
211 {
212 as_t *newas;
213
214 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
215 ASSEGMENT_DATA_SIZE (seg->length + num));
216
217 if (newas)
218 {
219 seg->as = newas;
220 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num));
221 seg->length += num;
222 return seg;
223 }
224
225 assegment_free_all (seg);
226 return NULL;
227 }
228
229 static int
230 int_cmp (const void *p1, const void *p2)
231 {
232 const as_t *as1 = p1;
233 const as_t *as2 = p2;
234
235 return (*as1 == *as2)
236 ? 0 : ( (*as1 > *as2) ? 1 : -1);
237 }
238
239 /* normalise the segment.
240 * In particular, merge runs of AS_SEQUENCEs into one segment
241 * Internally, we do not care about the wire segment length limit, and
242 * we want each distinct AS_PATHs to have the exact same internal
243 * representation - eg, so that our hashing actually works..
244 */
245 static struct assegment *
246 assegment_normalise (struct assegment *head)
247 {
248 struct assegment *seg = head, *pin;
249 struct assegment *tmp;
250
251 if (!head)
252 return head;
253
254 while (seg)
255 {
256 pin = seg;
257
258 /* Sort values SET segments, for determinism in paths to aid
259 * creation of hash values / path comparisons
260 * and because it helps other lesser implementations ;)
261 */
262 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
263 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
264
265 /* read ahead from the current, pinned segment while the segments
266 * are packable/mergeable. Append all following packable segments
267 * to the segment we have pinned and remove these appended
268 * segments.
269 */
270 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
271 {
272 tmp = pin->next;
273 seg = pin->next;
274
275 /* append the next sequence to the pinned sequence */
276 pin = assegment_append_asns (pin, seg->as, seg->length);
277
278 /* bypass the next sequence */
279 pin->next = seg->next;
280
281 /* get rid of the now referenceless segment */
282 assegment_free (tmp);
283
284 }
285
286 seg = pin->next;
287 }
288 return head;
289 }
290 \f
291 static struct aspath *
292 aspath_new (void)
293 {
294 struct aspath *aspath;
295
296 aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
297 memset (aspath, 0, sizeof (struct aspath));
298 return aspath;
299 }
300
301 /* Free AS path structure. */
302 void
303 aspath_free (struct aspath *aspath)
304 {
305 if (!aspath)
306 return;
307 if (aspath->segments)
308 assegment_free_all (aspath->segments);
309 if (aspath->str)
310 XFREE (MTYPE_AS_STR, aspath->str);
311 XFREE (MTYPE_AS_PATH, aspath);
312 }
313
314 /* Unintern aspath from AS path bucket. */
315 void
316 aspath_unintern (struct aspath *aspath)
317 {
318 struct aspath *ret;
319
320 if (aspath->refcnt)
321 aspath->refcnt--;
322
323 if (aspath->refcnt == 0)
324 {
325 /* This aspath must exist in aspath hash table. */
326 ret = hash_release (ashash, aspath);
327 assert (ret != NULL);
328 aspath_free (aspath);
329 }
330 }
331
332 /* Return the start or end delimiters for a particular Segment type */
333 #define AS_SEG_START 0
334 #define AS_SEG_END 1
335 static char
336 aspath_delimiter_char (u_char type, u_char which)
337 {
338 int i;
339 struct
340 {
341 int type;
342 char start;
343 char end;
344 } aspath_delim_char [] =
345 {
346 { AS_SET, '{', '}' },
347 { AS_CONFED_SET, '[', ']' },
348 { AS_CONFED_SEQUENCE, '(', ')' },
349 { 0 }
350 };
351
352 for (i = 0; aspath_delim_char[i].type != 0; i++)
353 {
354 if (aspath_delim_char[i].type == type)
355 {
356 if (which == AS_SEG_START)
357 return aspath_delim_char[i].start;
358 else if (which == AS_SEG_END)
359 return aspath_delim_char[i].end;
360 }
361 }
362 return ' ';
363 }
364
365 /* countup asns from this segment and index onward */
366 static int
367 assegment_count_asns (struct assegment *seg, int from)
368 {
369 int count = 0;
370 while (seg)
371 {
372 if (!from)
373 count += seg->length;
374 else
375 {
376 count += (seg->length - from);
377 from = 0;
378 }
379 seg = seg->next;
380 }
381 return count;
382 }
383
384 unsigned int
385 aspath_count_confeds (struct aspath *aspath)
386 {
387 int count = 0;
388 struct assegment *seg = aspath->segments;
389
390 while (seg)
391 {
392 if (seg->type == AS_CONFED_SEQUENCE)
393 count += seg->length;
394 else if (seg->type == AS_CONFED_SET)
395 count++;
396
397 seg = seg->next;
398 }
399 return count;
400 }
401
402 unsigned int
403 aspath_count_hops (struct aspath *aspath)
404 {
405 int count = 0;
406 struct assegment *seg = aspath->segments;
407
408 while (seg)
409 {
410 if (seg->type == AS_SEQUENCE)
411 count += seg->length;
412 else if (seg->type == AS_SET)
413 count++;
414
415 seg = seg->next;
416 }
417 return count;
418 }
419
420 unsigned int
421 aspath_size (struct aspath *aspath)
422 {
423 int size = 0;
424 struct assegment *seg = aspath->segments;
425
426 while (seg)
427 {
428 size += ASSEGMENT_SIZE(seg->length);
429 seg = seg->next;
430 }
431 return size;
432 }
433
434 /* Convert aspath structure to string expression. */
435 static char *
436 aspath_make_str_count (struct aspath *as)
437 {
438 struct assegment *seg;
439 int str_size;
440 int len = 0;
441 char *str_buf;
442
443 /* Empty aspath. */
444 if (!as->segments)
445 {
446 str_buf = XMALLOC (MTYPE_AS_STR, 1);
447 str_buf[0] = '\0';
448 return str_buf;
449 }
450
451 seg = as->segments;
452
453 /* ASN takes 5 chars at least, plus seperator, see below.
454 * If there is one differing segment type, we need an additional
455 * 2 chars for segment delimiters, and the final '\0'.
456 * Hopefully this is large enough to avoid hitting the realloc
457 * code below for most common sequences.
458 */
459 #define ASN_STR_LEN (5 + 1)
460 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
461 ASPATH_STR_DEFAULT_LEN);
462 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
463
464 while (seg)
465 {
466 int i;
467 char seperator;
468
469 /* Check AS type validity. Set seperator for segment */
470 switch (seg->type)
471 {
472 case AS_SET:
473 case AS_CONFED_SET:
474 seperator = ',';
475 break;
476 case AS_SEQUENCE:
477 case AS_CONFED_SEQUENCE:
478 seperator = ' ';
479 break;
480 default:
481 XFREE (MTYPE_AS_STR, str_buf);
482 return NULL;
483 }
484
485 /* We might need to increase str_buf, particularly if path has
486 * differing segments types, our initial guesstimate above will
487 * have been wrong. need 5 chars for ASN, a seperator each and
488 * potentially two segment delimiters, plus a space between each
489 * segment and trailing zero.
490 */
491 #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
492 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
493 {
494 str_size = len + SEGMENT_STR_LEN(seg);
495 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
496 }
497 #undef ASN_STR_LEN
498 #undef SEGMENT_STR_LEN
499
500 if (seg->type != AS_SEQUENCE)
501 len += snprintf (str_buf + len, str_size - len,
502 "%c",
503 aspath_delimiter_char (seg->type, AS_SEG_START));
504
505 /* write out the ASNs, with their seperators, bar the last one*/
506 for (i = 0; i < seg->length; i++)
507 {
508 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
509
510 if (i < (seg->length - 1))
511 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
512 }
513
514 if (seg->type != AS_SEQUENCE)
515 len += snprintf (str_buf + len, str_size - len, "%c",
516 aspath_delimiter_char (seg->type, AS_SEG_END));
517 if (seg->next)
518 len += snprintf (str_buf + len, str_size - len, " ");
519
520 seg = seg->next;
521 }
522
523 assert (len < str_size);
524
525 str_buf[len] = '\0';
526
527 return str_buf;
528 }
529
530 static void
531 aspath_str_update (struct aspath *as)
532 {
533 if (as->str)
534 XFREE (MTYPE_AS_STR, as->str);
535 as->str = aspath_make_str_count (as);
536 }
537
538 /* Intern allocated AS path. */
539 struct aspath *
540 aspath_intern (struct aspath *aspath)
541 {
542 struct aspath *find;
543
544 /* Assert this AS path structure is not interned. */
545 assert (aspath->refcnt == 0);
546
547 /* Check AS path hash. */
548 find = hash_get (ashash, aspath, hash_alloc_intern);
549
550 if (find != aspath)
551 aspath_free (aspath);
552
553 find->refcnt++;
554
555 if (! find->str)
556 find->str = aspath_make_str_count (find);
557
558 return find;
559 }
560
561 /* Duplicate aspath structure. Created same aspath structure but
562 reference count and AS path string is cleared. */
563 struct aspath *
564 aspath_dup (struct aspath *aspath)
565 {
566 struct aspath *new;
567
568 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
569
570 if (aspath->segments)
571 new->segments = assegment_dup_all (aspath->segments);
572 else
573 new->segments = NULL;
574
575 new->str = aspath_make_str_count (aspath);
576
577 return new;
578 }
579
580 static void *
581 aspath_hash_alloc (void *arg)
582 {
583 struct aspath *aspath;
584
585 /* New aspath strucutre is needed. */
586 aspath = aspath_dup (arg);
587
588 /* Malformed AS path value. */
589 if (! aspath->str)
590 {
591 aspath_free (aspath);
592 return NULL;
593 }
594
595 return aspath;
596 }
597
598 /* parse as-segment byte stream in struct assegment */
599 static struct assegment *
600 assegments_parse (struct stream *s, size_t length)
601 {
602 struct assegment_header segh;
603 struct assegment *seg, *prev = NULL, *head = NULL;
604 size_t bytes = 0;
605
606 /* empty aspath (ie iBGP or somesuch) */
607 if (length == 0)
608 return NULL;
609
610 /* basic checks */
611 if ( (STREAM_READABLE(s) < length)
612 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
613 || (length % AS_VALUE_SIZE))
614 return NULL;
615
616 while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
617 && (bytes < length))
618 {
619 int i;
620
621 /* softly softly, get the header first on its own */
622 segh.type = stream_getc (s);
623 segh.length = stream_getc (s);
624
625 /* check it.. */
626 if ( ((bytes + ASSEGMENT_SIZE(segh.length)) > length)
627 /* 1771bis 4.3b: seg length contains one or more */
628 || (segh.length == 0)
629 /* Paranoia in case someone changes type of segment length */
630 || ((sizeof segh.length > 1) && segh.length > AS_SEGMENT_MAX))
631 {
632 if (head)
633 assegment_free_all (head);
634 return NULL;
635 }
636
637 /* now its safe to trust lengths */
638 seg = assegment_new (segh.type, segh.length);
639
640 if (head)
641 prev->next = seg;
642 else /* it's the first segment */
643 head = prev = seg;
644
645 for (i = 0; i < segh.length; i++)
646 seg->as[i] = stream_getw (s);
647
648 bytes += ASSEGMENT_SIZE(segh.length);
649
650 prev = seg;
651 }
652
653 return assegment_normalise (head);
654 }
655
656 /* AS path parse function. pnt is a pointer to byte stream and length
657 is length of byte stream. If there is same AS path in the the AS
658 path hash then return it else make new AS path structure. */
659 struct aspath *
660 aspath_parse (struct stream *s, size_t length)
661 {
662 struct aspath as;
663 struct aspath *find;
664
665 /* If length is odd it's malformed AS path. */
666 if (length % AS_VALUE_SIZE)
667 return NULL;
668
669 as.segments = assegments_parse (s, length);
670
671 /* If already same aspath exist then return it. */
672 find = hash_get (ashash, &as, aspath_hash_alloc);
673
674 /* aspath_hash_alloc dupes segments too. that probably could be
675 * optimised out.
676 */
677 assegment_free_all (as.segments);
678
679 if (! find)
680 return NULL;
681 find->refcnt++;
682
683 return find;
684 }
685
686 static inline void
687 assegment_data_put (struct stream *s, as_t *as, int num)
688 {
689 int i;
690 assert (num <= AS_SEGMENT_MAX);
691
692 for (i = 0; i < num; i++)
693 stream_putw (s, as[i]);
694 }
695
696 static inline size_t
697 assegment_header_put (struct stream *s, u_char type, int length)
698 {
699 size_t lenp;
700 assert (length <= AS_SEGMENT_MAX);
701 stream_putc (s, type);
702 lenp = stream_get_endp (s);
703 stream_putc (s, length);
704 return lenp;
705 }
706
707 /* write aspath data to stream */
708 void
709 aspath_put (struct stream *s, struct aspath *as)
710 {
711 struct assegment *seg = as->segments;
712
713 if (!seg || seg->length == 0)
714 return;
715
716 if (seg)
717 {
718 while (seg && (ASSEGMENT_LEN (seg) <= STREAM_WRITEABLE(s)))
719 {
720 int written = 0;
721 size_t lenp;
722
723 /* Overlength segments have to be split up */
724 while ( (seg->length - written) > AS_SEGMENT_MAX)
725 {
726 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
727 assegment_data_put (s, seg->as, AS_SEGMENT_MAX);
728 written += AS_SEGMENT_MAX;
729 }
730
731 /* write the final segment, probably is also the first */
732 lenp = assegment_header_put (s, seg->type, seg->length - written);
733 assegment_data_put (s, (seg->as + written), seg->length - written);
734
735 /* Sequence-type segments can be 'packed' together
736 * Case of a segment which was overlength and split up
737 * will be missed here, but that doesn't matter.
738 */
739 if (seg->next && ASSEGMENTS_PACKABLE (seg, seg->next))
740 {
741 /* NB: We should never normally get here given we
742 * normalise aspath data when parse them. However, better
743 * safe than sorry. We potentially could call
744 * assegment_normalise here instead, but it's cheaper and
745 * easier to do it on the fly here rather than go through
746 * the segment list twice every time we write out
747 * aspath's.
748 */
749
750 /* Next segment's data can fit in this one */
751 assegment_data_put (s, seg->next->as, seg->next->length);
752
753 /* update the length of the segment header */
754 stream_putc_at (s, lenp,
755 seg->length - written + seg->next->length);
756 seg = seg->next->next; /* skip to past next */
757 }
758 else
759 seg = seg->next;
760 }
761 }
762 }
763
764 /* This is for SNMP BGP4PATHATTRASPATHSEGMENT
765 * We have no way to manage the storage, so we use a static stream
766 * wrapper around aspath_put.
767 */
768 u_char *
769 aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
770 {
771 #define SNMP_PATHSEG_MAX 1024
772 static struct stream *s = NULL;
773
774 if (!s)
775 s = stream_new (SNMP_PATHSEG_MAX);
776 else
777 stream_reset (s);
778
779 if (!as)
780 {
781 *varlen = 0;
782 return NULL;
783 }
784 aspath_put (s, as);
785
786 *varlen = stream_get_endp (s);
787 return stream_pnt(s);
788 }
789
790 #define min(A,B) ((A) < (B) ? (A) : (B))
791
792 static struct assegment *
793 aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
794 as_t as)
795 {
796 int i;
797
798 /* If this is first AS set member, create new as-set segment. */
799 if (asset == NULL)
800 {
801 asset = assegment_new (AS_SET, 1);
802 if (! aspath->segments)
803 aspath->segments = asset;
804 else
805 {
806 struct assegment *seg = aspath->segments;
807 while (seg->next)
808 seg = seg->next;
809 seg->next = asset;
810 }
811 asset->type = AS_SET;
812 asset->length = 1;
813 asset->as[0] = as;
814 }
815 else
816 {
817 /* Check this AS value already exists or not. */
818 for (i = 0; i < asset->length; i++)
819 if (asset->as[i] == as)
820 return asset;
821
822 asset->length++;
823 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
824 asset->length * AS_VALUE_SIZE);
825 asset->as[asset->length - 1] = as;
826 }
827
828
829 return asset;
830 }
831
832 /* Modify as1 using as2 for aggregation. */
833 struct aspath *
834 aspath_aggregate (struct aspath *as1, struct aspath *as2)
835 {
836 int i;
837 int minlen;
838 int match;
839 int from;
840 struct assegment *seg1 = as1->segments;
841 struct assegment *seg2 = as2->segments;
842 struct aspath *aspath;
843 struct assegment *asset;
844
845 match = 0;
846 minlen = 0;
847 aspath = NULL;
848 asset = NULL;
849
850 /* First of all check common leading sequence. */
851 while (seg1 && seg2)
852 {
853 /* Check segment type. */
854 if (seg1->type != seg2->type)
855 break;
856
857 /* Minimum segment length. */
858 minlen = min (seg1->length, seg2->length);
859
860 for (match = 0; match < minlen; match++)
861 if (seg1->as[match] != seg2->as[match])
862 break;
863
864 if (match)
865 {
866 if (! aspath)
867 aspath = aspath_new ();
868 aspath->segments = assegment_new (seg1->type, 0);
869 aspath->segments = assegment_append_asns (aspath->segments,
870 seg1->as, match);
871 }
872
873 if (match != minlen || match != seg1->length
874 || seg1->length != seg2->length)
875 break;
876
877 seg1 = seg1->next;
878 seg2 = seg2->next;
879 }
880
881 if (! aspath)
882 aspath = aspath_new();
883
884 /* Make as-set using rest of all information. */
885 from = match;
886 while (seg1)
887 {
888 for (i = from; i < seg1->length; i++)
889 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
890
891 from = 0;
892 seg1 = seg1->next;
893 }
894
895 from = match;
896 while (seg2)
897 {
898 for (i = from; i < seg2->length; i++)
899 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
900
901 from = 0;
902 seg2 = seg2->next;
903 }
904
905 assegment_normalise (aspath->segments);
906 aspath_str_update (aspath);
907 return aspath;
908 }
909
910 /* When a BGP router receives an UPDATE with an MP_REACH_NLRI
911 attribute, check the leftmost AS number in the AS_PATH attribute is
912 or not the peer's AS number. */
913 int
914 aspath_firstas_check (struct aspath *aspath, as_t asno)
915 {
916 if ( (aspath == NULL) || (aspath->segments == NULL) )
917 return 0;
918
919 if (aspath->segments
920 && (aspath->segments->type == AS_SEQUENCE)
921 && (aspath->segments->as[0] == asno ))
922 return 1;
923
924 return 0;
925 }
926
927 /* AS path loop check. If aspath contains asno then return 1. */
928 int
929 aspath_loop_check (struct aspath *aspath, as_t asno)
930 {
931 struct assegment *seg;
932 int count = 0;
933
934 if ( (aspath == NULL) || (aspath->segments) )
935 return 0;
936
937 seg = aspath->segments;
938
939 while (seg)
940 {
941 int i;
942
943 for (i = 0; i < seg->length; i++)
944 if (seg->as[i] == asno)
945 count++;
946
947 seg = seg->next;
948 }
949 return count;
950 }
951
952 /* When all of AS path is private AS return 1. */
953 int
954 aspath_private_as_check (struct aspath *aspath)
955 {
956 struct assegment *seg;
957
958 if ( !(aspath && aspath->segments) )
959 return 0;
960
961 seg = aspath->segments;
962
963 while (seg)
964 {
965 int i;
966
967 for (i = 0; i < seg->length; i++)
968 {
969 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
970 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
971 return 0;
972 }
973 seg = seg->next;
974 }
975 return 1;
976 }
977
978 /* Merge as1 to as2. as2 should be uninterned aspath. */
979 static struct aspath *
980 aspath_merge (struct aspath *as1, struct aspath *as2)
981 {
982 struct assegment *last, *new;
983
984 if (! as1 || ! as2)
985 return NULL;
986
987 last = new = assegment_dup_all (as1->segments);
988
989 /* find the last valid segment */
990 while (last && last->next)
991 last = last->next;
992
993 last->next = as2->segments;
994 as2->segments = new;
995 aspath_str_update (as2);
996 return as2;
997 }
998
999 /* Prepend as1 to as2. as2 should be uninterned aspath. */
1000 struct aspath *
1001 aspath_prepend (struct aspath *as1, struct aspath *as2)
1002 {
1003 struct assegment *seg1;
1004 struct assegment *seg2;
1005
1006 if (! as1 || ! as2)
1007 return NULL;
1008
1009 seg1 = as1->segments;
1010 seg2 = as2->segments;
1011
1012 /* If as2 is empty, only need to dupe as1's chain onto as2 */
1013 if (seg2 == NULL)
1014 {
1015 as2->segments = assegment_dup_all (as1->segments);
1016 aspath_str_update (as2);
1017 return as2;
1018 }
1019
1020 /* If as1 is empty AS, no prepending to do. */
1021 if (seg1 == NULL)
1022 return as2;
1023
1024 /* find the tail as1's segment chain. */
1025 while (seg1 && seg1->next)
1026 seg1 = seg1->next;
1027
1028 /* Compare last segment type of as1 and first segment type of as2. */
1029 if (seg1->type != seg2->type)
1030 return aspath_merge (as1, as2);
1031
1032 if (seg1->type == AS_SEQUENCE)
1033 {
1034 /* We have two chains of segments, as1->segments and seg2,
1035 * and we have to attach them together, merging the attaching
1036 * segments together into one.
1037 *
1038 * 1. dupe as1->segments onto head of as2
1039 * 2. merge seg2's asns onto last segment of this new chain
1040 * 3. attach chain after seg2
1041 */
1042
1043 /* dupe as1 onto as2's head */
1044 seg1 = as2->segments = assegment_dup_all (as1->segments);
1045
1046 /* refind the tail of as2, reusing seg1 */
1047 while (seg1 && seg1->next)
1048 seg1 = seg1->next;
1049
1050 /* merge the old head, seg2, into tail, seg1 */
1051 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1052
1053 /* bypass the merged seg2, and attach any chain after it to
1054 * chain descending from as2's head
1055 */
1056 seg1->next = seg2->next;
1057
1058 /* seg2 is now referenceless and useless*/
1059 assegment_free (seg2);
1060
1061 /* we've now prepended as1's segment chain to as2, merging
1062 * the inbetween AS_SEQUENCE of seg2 in the process
1063 */
1064 aspath_str_update (as2);
1065 return as2;
1066 }
1067 else
1068 {
1069 /* AS_SET merge code is needed at here. */
1070 return aspath_merge (as1, as2);
1071 }
1072 /* XXX: Ermmm, what if as1 has multiple segments?? */
1073
1074 /* Not reached */
1075 }
1076
1077 /* Add specified AS to the leftmost of aspath. */
1078 static struct aspath *
1079 aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1080 {
1081 struct assegment *assegment = aspath->segments;
1082
1083 /* In case of empty aspath. */
1084 if (assegment == NULL || assegment->length == 0)
1085 {
1086 aspath->segments = assegment_new (type, 1);
1087 aspath->segments->as[0] = asno;
1088
1089 if (assegment)
1090 assegment_free (assegment);
1091
1092 return aspath;
1093 }
1094
1095 if (assegment->type == type)
1096 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1097 else
1098 {
1099 /* create new segment
1100 * push it onto head of aspath's segment chain
1101 */
1102 struct assegment *newsegment;
1103
1104 newsegment = assegment_new (type, 1);
1105 newsegment->as[0] = asno;
1106
1107 newsegment->next = assegment;
1108 aspath->segments = newsegment;
1109 }
1110
1111 return aspath;
1112 }
1113
1114 /* Add specified AS to the leftmost of aspath. */
1115 struct aspath *
1116 aspath_add_seq (struct aspath *aspath, as_t asno)
1117 {
1118 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1119 }
1120
1121 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1122 as2's leftmost AS is same return 1. */
1123 int
1124 aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
1125 {
1126 struct assegment *seg1 = NULL;
1127 struct assegment *seg2 = NULL;
1128
1129 if (!(aspath1 && aspath2))
1130 return 0;
1131
1132 seg1 = aspath1->segments;
1133 seg2 = aspath2->segments;
1134
1135 /* find first non-confed segments for each */
1136 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1137 || (seg1->type == AS_CONFED_SET)))
1138 seg1 = seg1->next;
1139
1140 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1141 || (seg2->type == AS_CONFED_SET)))
1142 seg2 = seg2->next;
1143
1144 /* Check as1's */
1145 if (!(seg1 && seg2
1146 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
1147 return 0;
1148
1149 if (seg1->as[0] == seg2->as[0])
1150 return 1;
1151
1152 return 0;
1153 }
1154
1155 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1156 as2's leftmost AS is same return 1. (confederation as-path
1157 only). */
1158 int
1159 aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2)
1160 {
1161 if (! (aspath1 && aspath2) )
1162 return 0;
1163
1164 if ( !(aspath1->segments && aspath2->segments) )
1165 return 0;
1166
1167 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1168 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
1169 return 0;
1170
1171 if (aspath1->segments->as[0] == aspath2->segments->as[0])
1172 return 1;
1173
1174 return 0;
1175 }
1176
1177 /* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1178 * See RFC3065, 6.1 c1 */
1179 struct aspath *
1180 aspath_delete_confed_seq (struct aspath *aspath)
1181 {
1182 struct assegment *seg;
1183
1184 if (!(aspath && aspath->segments))
1185 return aspath;
1186
1187 seg = aspath->segments;
1188
1189 /* "if the first path segment of the AS_PATH is
1190 * of type AS_CONFED_SEQUENCE,"
1191 */
1192 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1193 return aspath;
1194
1195 /* "... that segment and any immediately following segments
1196 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1197 * from the AS_PATH attribute,"
1198 */
1199 while (seg &&
1200 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
1201 {
1202 aspath->segments = seg->next;
1203 assegment_free (seg);
1204 seg = aspath->segments;
1205 }
1206 aspath_str_update (aspath);
1207 return aspath;
1208 }
1209
1210 /* Add new AS number to the leftmost part of the aspath as
1211 AS_CONFED_SEQUENCE. */
1212 struct aspath*
1213 aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1214 {
1215 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1216 }
1217
1218 /* Add new as value to as path structure. */
1219 static void
1220 aspath_as_add (struct aspath *as, as_t asno)
1221 {
1222 struct assegment *seg = as->segments;
1223
1224 /* Last segment search procedure. */
1225 while (seg && seg->next)
1226 seg = seg->next;
1227
1228 if (!seg)
1229 return;
1230
1231 assegment_append_asns (seg, &asno, 1);
1232 }
1233
1234 /* Add new as segment to the as path. */
1235 static void
1236 aspath_segment_add (struct aspath *as, int type)
1237 {
1238 struct assegment *seg = as->segments;
1239 struct assegment *new = assegment_new (type, 0);
1240
1241 while (seg && seg->next)
1242 seg = seg->next;
1243
1244 if (seg == NULL)
1245 as->segments = new;
1246 else
1247 seg->next = new;
1248 }
1249
1250 struct aspath *
1251 aspath_empty (void)
1252 {
1253 return aspath_parse (NULL, 0);
1254 }
1255
1256 struct aspath *
1257 aspath_empty_get (void)
1258 {
1259 struct aspath *aspath;
1260
1261 aspath = aspath_new ();
1262 aspath->str = aspath_make_str_count (aspath);
1263 return aspath;
1264 }
1265
1266 unsigned long
1267 aspath_count (void)
1268 {
1269 return ashash->count;
1270 }
1271 \f
1272 /*
1273 Theoretically, one as path can have:
1274
1275 One BGP packet size should be less than 4096.
1276 One BGP attribute size should be less than 4096 - BGP header size.
1277 One BGP aspath size should be less than 4096 - BGP header size -
1278 BGP mandantry attribute size.
1279 */
1280
1281 /* AS path string lexical token enum. */
1282 enum as_token
1283 {
1284 as_token_asval,
1285 as_token_set_start,
1286 as_token_set_end,
1287 as_token_confed_seq_start,
1288 as_token_confed_seq_end,
1289 as_token_confed_set_start,
1290 as_token_confed_set_end,
1291 as_token_unknown
1292 };
1293
1294 /* Return next token and point for string parse. */
1295 static const char *
1296 aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
1297 {
1298 const char *p = buf;
1299
1300 /* Skip seperators (space for sequences, ',' for sets). */
1301 while (isspace ((int) *p) || *p == ',')
1302 p++;
1303
1304 /* Check the end of the string and type specify characters
1305 (e.g. {}()). */
1306 switch (*p)
1307 {
1308 case '\0':
1309 return NULL;
1310 break;
1311 case '{':
1312 *token = as_token_set_start;
1313 p++;
1314 return p;
1315 break;
1316 case '}':
1317 *token = as_token_set_end;
1318 p++;
1319 return p;
1320 break;
1321 case '(':
1322 *token = as_token_confed_seq_start;
1323 p++;
1324 return p;
1325 break;
1326 case ')':
1327 *token = as_token_confed_seq_end;
1328 p++;
1329 return p;
1330 break;
1331 case '[':
1332 *token = as_token_confed_set_start;
1333 p++;
1334 return p;
1335 break;
1336 case ']':
1337 *token = as_token_confed_set_end;
1338 p++;
1339 return p;
1340 break;
1341 }
1342
1343 /* Check actual AS value. */
1344 if (isdigit ((int) *p))
1345 {
1346 u_short asval;
1347
1348 *token = as_token_asval;
1349 asval = (*p - '0');
1350 p++;
1351 while (isdigit ((int) *p))
1352 {
1353 asval *= 10;
1354 asval += (*p - '0');
1355 p++;
1356 }
1357 *asno = asval;
1358 return p;
1359 }
1360
1361 /* There is no match then return unknown token. */
1362 *token = as_token_unknown;
1363 return p++;
1364 }
1365
1366 struct aspath *
1367 aspath_str2aspath (const char *str)
1368 {
1369 enum as_token token;
1370 u_short as_type;
1371 u_short asno;
1372 struct aspath *aspath;
1373 int needtype;
1374
1375 aspath = aspath_new ();
1376
1377 /* We start default type as AS_SEQUENCE. */
1378 as_type = AS_SEQUENCE;
1379 needtype = 1;
1380
1381 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1382 {
1383 switch (token)
1384 {
1385 case as_token_asval:
1386 if (needtype)
1387 {
1388 aspath_segment_add (aspath, as_type);
1389 needtype = 0;
1390 }
1391 aspath_as_add (aspath, asno);
1392 break;
1393 case as_token_set_start:
1394 as_type = AS_SET;
1395 aspath_segment_add (aspath, as_type);
1396 needtype = 0;
1397 break;
1398 case as_token_set_end:
1399 as_type = AS_SEQUENCE;
1400 needtype = 1;
1401 break;
1402 case as_token_confed_seq_start:
1403 as_type = AS_CONFED_SEQUENCE;
1404 aspath_segment_add (aspath, as_type);
1405 needtype = 0;
1406 break;
1407 case as_token_confed_seq_end:
1408 as_type = AS_SEQUENCE;
1409 needtype = 1;
1410 break;
1411 case as_token_confed_set_start:
1412 as_type = AS_CONFED_SET;
1413 aspath_segment_add (aspath, as_type);
1414 needtype = 0;
1415 break;
1416 case as_token_confed_set_end:
1417 as_type = AS_SEQUENCE;
1418 needtype = 1;
1419 break;
1420 case as_token_unknown:
1421 default:
1422 aspath_free (aspath);
1423 return NULL;
1424 break;
1425 }
1426 }
1427
1428 aspath->str = aspath_make_str_count (aspath);
1429
1430 return aspath;
1431 }
1432 \f
1433 /* Make hash value by raw aspath data. */
1434 unsigned int
1435 aspath_key_make (struct aspath *aspath)
1436 {
1437 unsigned int key = 0;
1438 unsigned int i;
1439 struct assegment *seg = aspath->segments;
1440 struct assegment *prev = NULL;
1441
1442 while (seg)
1443 {
1444 /* segment types should be part of the hash
1445 * otherwise seq(1) and set(1) will hash to same value
1446 */
1447 if (!(prev && seg->type == AS_SEQUENCE && seg->type == prev->type))
1448 key += seg->type;
1449
1450 for (i = 0; i < seg->length; i++)
1451 key += seg->as[i];
1452
1453 prev = seg;
1454 seg = seg->next;
1455 }
1456
1457 return key;
1458 }
1459
1460 /* If two aspath have same value then return 1 else return 0 */
1461 static int
1462 aspath_cmp (void *arg1, void *arg2)
1463 {
1464 struct assegment *seg1 = ((struct aspath *)arg1)->segments;
1465 struct assegment *seg2 = ((struct aspath *)arg2)->segments;
1466
1467 while (seg1 || seg2)
1468 {
1469 int i;
1470 if ((!seg1 && seg2) || (seg1 && !seg2))
1471 return 0;
1472 if (seg1->type != seg2->type)
1473 return 0;
1474 if (seg1->length != seg2->length)
1475 return 0;
1476 for (i = 0; i < seg1->length; i++)
1477 if (seg1->as[i] != seg2->as[i])
1478 return 0;
1479 seg1 = seg1->next;
1480 seg2 = seg2->next;
1481 }
1482 return 1;
1483 }
1484
1485 /* AS path hash initialize. */
1486 void
1487 aspath_init (void)
1488 {
1489 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1490 }
1491 \f
1492 /* return and as path value */
1493 const char *
1494 aspath_print (struct aspath *as)
1495 {
1496 return (as ? as->str : NULL);
1497 }
1498
1499 /* Printing functions */
1500 void
1501 aspath_print_vty (struct vty *vty, struct aspath *as)
1502 {
1503 vty_out (vty, "%s", as->str);
1504 }
1505
1506 static void
1507 aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1508 {
1509 struct aspath *as;
1510
1511 as = (struct aspath *) backet->data;
1512
1513 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
1514 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1515 }
1516
1517 /* Print all aspath and hash information. This function is used from
1518 `show ip bgp paths' command. */
1519 void
1520 aspath_print_all_vty (struct vty *vty)
1521 {
1522 hash_iterate (ashash,
1523 (void (*) (struct hash_backet *, void *))
1524 aspath_show_all_iterator,
1525 vty);
1526 }