]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_aspath.c
[bgpd] fix some leaks introduced in aspath rewrite.
[mirror_frr.git] / bgpd / bgp_aspath.c
CommitLineData
718e3744 1/* AS path management routines.
2 Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
fe69a505 3 Copyright (C) 2005 Sun Microsystems, Inc.
718e3744 4
5This file is part of GNU Zebra.
6
7GNU Zebra is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by the
9Free Software Foundation; either version 2, or (at your option) any
10later version.
11
12GNU Zebra is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Zebra; see the file COPYING. If not, write to the Free
19Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA. */
21
22#include <zebra.h>
23
24#include "hash.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "str.h"
29#include "log.h"
fe69a505 30#include "stream.h"
718e3744 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
fe69a505 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)
718e3744 53
fe69a505 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 */
73struct assegment_header
718e3744 74{
75 u_char type;
76 u_char length;
718e3744 77};
78
79/* Hash for aspath. This is the top level structure of AS path. */
80struct hash *ashash;
81\f
fe69a505 82static inline as_t *
83assegment_data_new (int num)
84{
85 return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num)));
86}
87
88static inline void
89assegment_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 */
99static struct assegment *
100assegment_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
115static void
116assegment_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 */
130static void
131assegment_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 */
144static struct assegment *
145assegment_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 */
156static struct assegment *
157assegment_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 */
178static struct assegment *
179assegment_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 */
209static struct assegment *
210assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
211{
02335429 212 as_t *newas;
213
214 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
fe69a505 215 ASSEGMENT_DATA_SIZE (seg->length + num));
216
02335429 217 if (newas)
fe69a505 218 {
02335429 219 seg->as = newas;
fe69a505 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
229static int
230int_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 */
245static struct assegment *
246assegment_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
718e3744 291static struct aspath *
fe69a505 292aspath_new (void)
718e3744 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. */
302void
303aspath_free (struct aspath *aspath)
304{
305 if (!aspath)
306 return;
fe69a505 307 if (aspath->segments)
308 assegment_free_all (aspath->segments);
718e3744 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. */
315void
316aspath_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
335static char
336aspath_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, '{', '}' },
718e3744 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
fe69a505 365/* countup asns from this segment and index onward */
366static int
367assegment_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
384unsigned int
385aspath_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
402unsigned int
403aspath_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
420unsigned int
421aspath_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
718e3744 434/* Convert aspath structure to string expression. */
94f2b392 435static char *
718e3744 436aspath_make_str_count (struct aspath *as)
437{
fe69a505 438 struct assegment *seg;
439 int str_size;
440 int len = 0;
c9e52be3 441 char *str_buf;
718e3744 442
443 /* Empty aspath. */
fe69a505 444 if (!as->segments)
718e3744 445 {
446 str_buf = XMALLOC (MTYPE_AS_STR, 1);
447 str_buf[0] = '\0';
718e3744 448 return str_buf;
449 }
fe69a505 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);
718e3744 462 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
718e3744 463
fe69a505 464 while (seg)
718e3744 465 {
466 int i;
fe69a505 467 char seperator;
718e3744 468
fe69a505 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;
718e3744 521 }
fe69a505 522
523 assert (len < str_size);
524
525 str_buf[len] = '\0';
718e3744 526
527 return str_buf;
528}
529
fe69a505 530static void
531aspath_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
718e3744 538/* Intern allocated AS path. */
539struct aspath *
540aspath_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)
fe69a505 551 aspath_free (aspath);
718e3744 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. */
563struct aspath *
564aspath_dup (struct aspath *aspath)
565{
566 struct aspath *new;
567
fe69a505 568 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
718e3744 569
fe69a505 570 if (aspath->segments)
571 new->segments = assegment_dup_all (aspath->segments);
718e3744 572 else
fe69a505 573 new->segments = NULL;
718e3744 574
fe69a505 575 new->str = aspath_make_str_count (aspath);
718e3744 576
577 return new;
578}
579
94f2b392 580static void *
fe69a505 581aspath_hash_alloc (void *arg)
718e3744 582{
583 struct aspath *aspath;
584
585 /* New aspath strucutre is needed. */
fe69a505 586 aspath = aspath_dup (arg);
587
718e3744 588 /* Malformed AS path value. */
589 if (! aspath->str)
590 {
591 aspath_free (aspath);
592 return NULL;
593 }
594
595 return aspath;
596}
597
fe69a505 598/* parse as-segment byte stream in struct assegment */
ad72740e 599static struct assegment *
fe69a505 600assegments_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
718e3744 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. */
659struct aspath *
fe69a505 660aspath_parse (struct stream *s, size_t length)
718e3744 661{
662 struct aspath as;
663 struct aspath *find;
664
665 /* If length is odd it's malformed AS path. */
fe69a505 666 if (length % AS_VALUE_SIZE)
718e3744 667 return NULL;
668
fe69a505 669 as.segments = assegments_parse (s, length);
670
718e3744 671 /* If already same aspath exist then return it. */
672 find = hash_get (ashash, &as, aspath_hash_alloc);
02335429 673
674 /* aspath_hash_alloc dupes segments too. that probably could be
675 * optimised out.
676 */
677 assegment_free_all (as.segments);
678
718e3744 679 if (! find)
680 return NULL;
681 find->refcnt++;
682
683 return find;
684}
685
fe69a505 686static inline void
687assegment_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}
718e3744 695
fe69a505 696static inline size_t
697assegment_header_put (struct stream *s, u_char type, int length)
718e3744 698{
fe69a505 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}
718e3744 706
fe69a505 707/* write aspath data to stream */
708void
709aspath_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)
718e3744 717 {
fe69a505 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 }
718e3744 761 }
fe69a505 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 */
768u_char *
769aspath_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);
718e3744 776 else
fe69a505 777 stream_reset (s);
778
779 if (!as)
718e3744 780 {
fe69a505 781 *varlen = 0;
782 return NULL;
718e3744 783 }
fe69a505 784 aspath_put (s, as);
785
786 *varlen = stream_get_endp (s);
787 return stream_pnt(s);
718e3744 788}
fe69a505 789
790#define min(A,B) ((A) < (B) ? (A) : (B))
718e3744 791
94f2b392 792static struct assegment *
718e3744 793aspath_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 {
fe69a505 801 asset = assegment_new (AS_SET, 1);
802 if (! aspath->segments)
803 aspath->segments = asset;
718e3744 804 else
fe69a505 805 {
806 struct assegment *seg = aspath->segments;
807 while (seg->next)
808 seg = seg->next;
809 seg->next = asset;
810 }
718e3744 811 asset->type = AS_SET;
812 asset->length = 1;
fe69a505 813 asset->as[0] = as;
718e3744 814 }
815 else
816 {
718e3744 817 /* Check this AS value already exists or not. */
818 for (i = 0; i < asset->length; i++)
fe69a505 819 if (asset->as[i] == as)
718e3744 820 return asset;
fe69a505 821
718e3744 822 asset->length++;
fe69a505 823 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
824 asset->length * AS_VALUE_SIZE);
825 asset->as[asset->length - 1] = as;
718e3744 826 }
fe69a505 827
718e3744 828
829 return asset;
830}
831
832/* Modify as1 using as2 for aggregation. */
833struct aspath *
834aspath_aggregate (struct aspath *as1, struct aspath *as2)
835{
836 int i;
837 int minlen;
838 int match;
fe69a505 839 int from;
840 struct assegment *seg1 = as1->segments;
841 struct assegment *seg2 = as2->segments;
718e3744 842 struct aspath *aspath;
843 struct assegment *asset;
844
845 match = 0;
846 minlen = 0;
847 aspath = NULL;
848 asset = NULL;
718e3744 849
850 /* First of all check common leading sequence. */
fe69a505 851 while (seg1 && seg2)
718e3744 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++)
fe69a505 861 if (seg1->as[match] != seg2->as[match])
718e3744 862 break;
863
864 if (match)
865 {
866 if (! aspath)
fe69a505 867 aspath = aspath_new ();
868 aspath->segments = assegment_new (seg1->type, 0);
869 aspath->segments = assegment_append_asns (aspath->segments,
870 seg1->as, match);
718e3744 871 }
872
873 if (match != minlen || match != seg1->length
874 || seg1->length != seg2->length)
875 break;
fe69a505 876
877 seg1 = seg1->next;
878 seg2 = seg2->next;
718e3744 879 }
880
881 if (! aspath)
882 aspath = aspath_new();
883
884 /* Make as-set using rest of all information. */
fe69a505 885 from = match;
886 while (seg1)
718e3744 887 {
fe69a505 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;
718e3744 893 }
894
fe69a505 895 from = match;
896 while (seg2)
718e3744 897 {
fe69a505 898 for (i = from; i < seg2->length; i++)
899 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
718e3744 900
fe69a505 901 from = 0;
902 seg2 = seg2->next;
718e3744 903 }
fe69a505 904
905 assegment_normalise (aspath->segments);
906 aspath_str_update (aspath);
718e3744 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. */
913int
914aspath_firstas_check (struct aspath *aspath, as_t asno)
915{
fe69a505 916 if ( (aspath == NULL) || (aspath->segments == NULL) )
718e3744 917 return 0;
fe69a505 918
919 if (aspath->segments
920 && (aspath->segments->type == AS_SEQUENCE)
921 && (aspath->segments->as[0] == asno ))
718e3744 922 return 1;
923
924 return 0;
925}
926
927/* AS path loop check. If aspath contains asno then return 1. */
928int
929aspath_loop_check (struct aspath *aspath, as_t asno)
930{
fe69a505 931 struct assegment *seg;
718e3744 932 int count = 0;
933
fe69a505 934 if ( (aspath == NULL) || (aspath->segments) )
718e3744 935 return 0;
fe69a505 936
937 seg = aspath->segments;
938
939 while (seg)
718e3744 940 {
941 int i;
718e3744 942
fe69a505 943 for (i = 0; i < seg->length; i++)
944 if (seg->as[i] == asno)
718e3744 945 count++;
fe69a505 946
947 seg = seg->next;
718e3744 948 }
949 return count;
950}
951
952/* When all of AS path is private AS return 1. */
953int
954aspath_private_as_check (struct aspath *aspath)
955{
fe69a505 956 struct assegment *seg;
957
958 if ( !(aspath && aspath->segments) )
718e3744 959 return 0;
fe69a505 960
961 seg = aspath->segments;
718e3744 962
fe69a505 963 while (seg)
718e3744 964 {
965 int i;
718e3744 966
fe69a505 967 for (i = 0; i < seg->length; i++)
718e3744 968 {
fe69a505 969 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
970 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
718e3744 971 return 0;
972 }
fe69a505 973 seg = seg->next;
718e3744 974 }
975 return 1;
976}
977
978/* Merge as1 to as2. as2 should be uninterned aspath. */
94f2b392 979static struct aspath *
718e3744 980aspath_merge (struct aspath *as1, struct aspath *as2)
981{
fe69a505 982 struct assegment *last, *new;
718e3744 983
984 if (! as1 || ! as2)
985 return NULL;
986
fe69a505 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);
718e3744 996 return as2;
997}
998
999/* Prepend as1 to as2. as2 should be uninterned aspath. */
1000struct aspath *
1001aspath_prepend (struct aspath *as1, struct aspath *as2)
1002{
fe69a505 1003 struct assegment *seg1;
1004 struct assegment *seg2;
718e3744 1005
1006 if (! as1 || ! as2)
1007 return NULL;
fe69a505 1008
1009 seg1 = as1->segments;
1010 seg2 = as2->segments;
1011
1012 /* If as2 is empty, only need to dupe as1's chain onto as2 */
718e3744 1013 if (seg2 == NULL)
1014 {
fe69a505 1015 as2->segments = assegment_dup_all (as1->segments);
1016 aspath_str_update (as2);
718e3744 1017 return as2;
1018 }
fe69a505 1019
1020 /* If as1 is empty AS, no prepending to do. */
718e3744 1021 if (seg1 == NULL)
1022 return as2;
fe69a505 1023
1024 /* find the tail as1's segment chain. */
1025 while (seg1 && seg1->next)
1026 seg1 = seg1->next;
718e3744 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 {
fe69a505 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 */
718e3744 1042
fe69a505 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);
718e3744 1065 return as2;
1066 }
1067 else
1068 {
1069 /* AS_SET merge code is needed at here. */
1070 return aspath_merge (as1, as2);
1071 }
fe69a505 1072 /* XXX: Ermmm, what if as1 has multiple segments?? */
1073
718e3744 1074 /* Not reached */
1075}
1076
1077/* Add specified AS to the leftmost of aspath. */
1078static struct aspath *
1079aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1080{
fe69a505 1081 struct assegment *assegment = aspath->segments;
718e3744 1082
1083 /* In case of empty aspath. */
1084 if (assegment == NULL || assegment->length == 0)
1085 {
fe69a505 1086 aspath->segments = assegment_new (type, 1);
1087 aspath->segments->as[0] = asno;
1088
718e3744 1089 if (assegment)
fe69a505 1090 assegment_free (assegment);
718e3744 1091
1092 return aspath;
1093 }
1094
1095 if (assegment->type == type)
fe69a505 1096 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1097 else
718e3744 1098 {
fe69a505 1099 /* create new segment
1100 * push it onto head of aspath's segment chain
1101 */
718e3744 1102 struct assegment *newsegment;
fe69a505 1103
1104 newsegment = assegment_new (type, 1);
1105 newsegment->as[0] = asno;
1106
1107 newsegment->next = assegment;
1108 aspath->segments = newsegment;
718e3744 1109 }
1110
1111 return aspath;
1112}
1113
1114/* Add specified AS to the leftmost of aspath. */
1115struct aspath *
1116aspath_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. */
1123int
1124aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
1125{
fe69a505 1126 struct assegment *seg1 = NULL;
1127 struct assegment *seg2 = NULL;
718e3744 1128
fe69a505 1129 if (!(aspath1 && aspath2))
1130 return 0;
718e3744 1131
fe69a505 1132 seg1 = aspath1->segments;
1133 seg2 = aspath2->segments;
718e3744 1134
fe69a505 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;
718e3744 1139
fe69a505 1140 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1141 || (seg2->type == AS_CONFED_SET)))
1142 seg2 = seg2->next;
718e3744 1143
fe69a505 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])
718e3744 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). */
1158int
1159aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2)
1160{
fe69a505 1161 if (! (aspath1 && aspath2) )
718e3744 1162 return 0;
fe69a505 1163
ad72740e 1164 if ( !(aspath1->segments && aspath2->segments) )
1165 return 0;
1166
fe69a505 1167 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1168 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
718e3744 1169 return 0;
fe69a505 1170
1171 if (aspath1->segments->as[0] == aspath2->segments->as[0])
718e3744 1172 return 1;
1173
1174 return 0;
1175}
1176
fe69a505 1177/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1178 * See RFC3065, 6.1 c1 */
718e3744 1179struct aspath *
1180aspath_delete_confed_seq (struct aspath *aspath)
1181{
fe69a505 1182 struct assegment *seg;
718e3744 1183
fe69a505 1184 if (!(aspath && aspath->segments))
718e3744 1185 return aspath;
1186
fe69a505 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;
718e3744 1194
fe69a505 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))
718e3744 1201 {
fe69a505 1202 aspath->segments = seg->next;
1203 assegment_free (seg);
1204 seg = aspath->segments;
718e3744 1205 }
fe69a505 1206 aspath_str_update (aspath);
718e3744 1207 return aspath;
1208}
1209
1210/* Add new AS number to the leftmost part of the aspath as
1211 AS_CONFED_SEQUENCE. */
1212struct aspath*
1213aspath_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. */
94f2b392 1219static void
718e3744 1220aspath_as_add (struct aspath *as, as_t asno)
1221{
fe69a505 1222 struct assegment *seg = as->segments;
718e3744 1223
1224 /* Last segment search procedure. */
fe69a505 1225 while (seg && seg->next)
1226 seg = seg->next;
1227
1228 if (!seg)
1229 return;
1230
1231 assegment_append_asns (seg, &asno, 1);
718e3744 1232}
1233
1234/* Add new as segment to the as path. */
94f2b392 1235static void
718e3744 1236aspath_segment_add (struct aspath *as, int type)
1237{
fe69a505 1238 struct assegment *seg = as->segments;
1239 struct assegment *new = assegment_new (type, 0);
718e3744 1240
fe69a505 1241 while (seg && seg->next)
1242 seg = seg->next;
1243
1244 if (seg == NULL)
1245 as->segments = new;
718e3744 1246 else
fe69a505 1247 seg->next = new;
718e3744 1248}
1249
1250struct aspath *
94f2b392 1251aspath_empty (void)
718e3744 1252{
1253 return aspath_parse (NULL, 0);
1254}
1255
1256struct aspath *
94f2b392 1257aspath_empty_get (void)
718e3744 1258{
1259 struct aspath *aspath;
1260
1261 aspath = aspath_new ();
1262 aspath->str = aspath_make_str_count (aspath);
1263 return aspath;
1264}
1265
1266unsigned long
fe69a505 1267aspath_count (void)
718e3744 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. */
1282enum as_token
1283{
1284 as_token_asval,
1285 as_token_set_start,
1286 as_token_set_end,
fe69a505 1287 as_token_confed_seq_start,
1288 as_token_confed_seq_end,
1289 as_token_confed_set_start,
1290 as_token_confed_set_end,
718e3744 1291 as_token_unknown
1292};
1293
1294/* Return next token and point for string parse. */
94f2b392 1295static const char *
fd79ac91 1296aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
718e3744 1297{
fd79ac91 1298 const char *p = buf;
718e3744 1299
fe69a505 1300 /* Skip seperators (space for sequences, ',' for sets). */
1301 while (isspace ((int) *p) || *p == ',')
718e3744 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 '(':
fe69a505 1322 *token = as_token_confed_seq_start;
718e3744 1323 p++;
1324 return p;
1325 break;
1326 case ')':
fe69a505 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;
718e3744 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
1366struct aspath *
fd79ac91 1367aspath_str2aspath (const char *str)
718e3744 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;
fe69a505 1402 case as_token_confed_seq_start:
718e3744 1403 as_type = AS_CONFED_SEQUENCE;
1404 aspath_segment_add (aspath, as_type);
1405 needtype = 0;
1406 break;
fe69a505 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:
718e3744 1417 as_type = AS_SEQUENCE;
1418 needtype = 1;
1419 break;
1420 case as_token_unknown:
1421 default:
fe69a505 1422 aspath_free (aspath);
718e3744 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. */
1434unsigned int
1435aspath_key_make (struct aspath *aspath)
1436{
1437 unsigned int key = 0;
fe69a505 1438 unsigned int i;
1439 struct assegment *seg = aspath->segments;
1440 struct assegment *prev = NULL;
718e3744 1441
fe69a505 1442 while (seg)
718e3744 1443 {
fe69a505 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;
718e3744 1455 }
1456
1457 return key;
1458}
1459
1460/* If two aspath have same value then return 1 else return 0 */
94f2b392 1461static int
fe69a505 1462aspath_cmp (void *arg1, void *arg2)
718e3744 1463{
fe69a505 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;
718e3744 1483}
1484
1485/* AS path hash initialize. */
1486void
94f2b392 1487aspath_init (void)
718e3744 1488{
1489 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1490}
1491\f
1492/* return and as path value */
1493const char *
1494aspath_print (struct aspath *as)
1495{
fe69a505 1496 return (as ? as->str : NULL);
718e3744 1497}
1498
1499/* Printing functions */
1500void
1501aspath_print_vty (struct vty *vty, struct aspath *as)
1502{
1503 vty_out (vty, "%s", as->str);
1504}
1505
94f2b392 1506static void
718e3744 1507aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1508{
1509 struct aspath *as;
1510
1511 as = (struct aspath *) backet->data;
1512
efa9f830 1513 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
718e3744 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. */
1519void
1520aspath_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}