blob: a6b77bbb86d40ba41effc90e842da3eb39911861 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* AS path management routines.
2 Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
paulfe69a502005-09-10 16:55:02 +00003 Copyright (C) 2005 Sun Microsystems, Inc.
paul718e3742002-12-13 20:15:29 +00004
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"
paulfe69a502005-09-10 16:55:02 +000030#include "stream.h"
paul718e3742002-12-13 20:15:29 +000031
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_aspath.h"
34
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
paulfe69a502005-09-10 16:55:02 +000041/* Maximum protocol segment length value */
42#define AS_SEGMENT_MAX 255
paul718e3742002-12-13 20:15:29 +000043
paulfe69a502005-09-10 16:55:02 +000044/* 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 */
73struct assegment_header
paul718e3742002-12-13 20:15:29 +000074{
75 u_char type;
76 u_char length;
paul718e3742002-12-13 20:15:29 +000077};
78
79/* Hash for aspath. This is the top level structure of AS path. */
80struct hash *ashash;
81
paulfe69a502005-09-10 16:55:02 +000082static 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{
paul02335422006-01-16 11:13:27 +0000212 as_t *newas;
213
214 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
paulfe69a502005-09-10 16:55:02 +0000215 ASSEGMENT_DATA_SIZE (seg->length + num));
216
paul02335422006-01-16 11:13:27 +0000217 if (newas)
paulfe69a502005-09-10 16:55:02 +0000218 {
paul02335422006-01-16 11:13:27 +0000219 seg->as = newas;
paulfe69a502005-09-10 16:55:02 +0000220 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
paul718e3742002-12-13 20:15:29 +0000291static struct aspath *
paulfe69a502005-09-10 16:55:02 +0000292aspath_new (void)
paul718e3742002-12-13 20:15:29 +0000293{
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;
paulfe69a502005-09-10 16:55:02 +0000307 if (aspath->segments)
308 assegment_free_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000309 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, '{', '}' },
paul718e3742002-12-13 20:15:29 +0000347 { 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
paulfe69a502005-09-10 16:55:02 +0000365/* 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
paul718e3742002-12-13 20:15:29 +0000434/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000435static char *
paul718e3742002-12-13 20:15:29 +0000436aspath_make_str_count (struct aspath *as)
437{
paulfe69a502005-09-10 16:55:02 +0000438 struct assegment *seg;
439 int str_size;
440 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000441 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000442
443 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000444 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000445 {
446 str_buf = XMALLOC (MTYPE_AS_STR, 1);
447 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000448 return str_buf;
449 }
paulfe69a502005-09-10 16:55:02 +0000450
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);
paul718e3742002-12-13 20:15:29 +0000462 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000463
paulfe69a502005-09-10 16:55:02 +0000464 while (seg)
paul718e3742002-12-13 20:15:29 +0000465 {
466 int i;
paulfe69a502005-09-10 16:55:02 +0000467 char seperator;
paul718e3742002-12-13 20:15:29 +0000468
paulfe69a502005-09-10 16:55:02 +0000469 /* 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;
paul718e3742002-12-13 20:15:29 +0000521 }
paulfe69a502005-09-10 16:55:02 +0000522
523 assert (len < str_size);
524
525 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000526
527 return str_buf;
528}
529
paulfe69a502005-09-10 16:55:02 +0000530static 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
paul718e3742002-12-13 20:15:29 +0000538/* 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)
paulfe69a502005-09-10 16:55:02 +0000551 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000552
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
paulfe69a502005-09-10 16:55:02 +0000568 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000569
paulfe69a502005-09-10 16:55:02 +0000570 if (aspath->segments)
571 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000572 else
paulfe69a502005-09-10 16:55:02 +0000573 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000574
paulfe69a502005-09-10 16:55:02 +0000575 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000576
577 return new;
578}
579
paul94f2b392005-06-28 12:44:16 +0000580static void *
paulfe69a502005-09-10 16:55:02 +0000581aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000582{
583 struct aspath *aspath;
584
585 /* New aspath strucutre is needed. */
paulfe69a502005-09-10 16:55:02 +0000586 aspath = aspath_dup (arg);
587
paul718e3742002-12-13 20:15:29 +0000588 /* Malformed AS path value. */
589 if (! aspath->str)
590 {
591 aspath_free (aspath);
592 return NULL;
593 }
594
595 return aspath;
596}
597
paulfe69a502005-09-10 16:55:02 +0000598/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000599static struct assegment *
paulfe69a502005-09-10 16:55:02 +0000600assegments_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
paul718e3742002-12-13 20:15:29 +0000656/* 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 *
paulfe69a502005-09-10 16:55:02 +0000660aspath_parse (struct stream *s, size_t length)
paul718e3742002-12-13 20:15:29 +0000661{
662 struct aspath as;
663 struct aspath *find;
664
665 /* If length is odd it's malformed AS path. */
paulfe69a502005-09-10 16:55:02 +0000666 if (length % AS_VALUE_SIZE)
paul718e3742002-12-13 20:15:29 +0000667 return NULL;
668
paulfe69a502005-09-10 16:55:02 +0000669 as.segments = assegments_parse (s, length);
670
paul718e3742002-12-13 20:15:29 +0000671 /* If already same aspath exist then return it. */
672 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000673
674 /* aspath_hash_alloc dupes segments too. that probably could be
675 * optimised out.
676 */
677 assegment_free_all (as.segments);
678
paul718e3742002-12-13 20:15:29 +0000679 if (! find)
680 return NULL;
681 find->refcnt++;
682
683 return find;
684}
685
paulfe69a502005-09-10 16:55:02 +0000686static inline void
687assegment_data_put (struct stream *s, as_t *as, int num)
paul718e3742002-12-13 20:15:29 +0000688{
paulfe69a502005-09-10 16:55:02 +0000689 int i;
690 assert (num <= AS_SEGMENT_MAX);
691
692 for (i = 0; i < num; i++)
693 stream_putw (s, as[i]);
paul718e3742002-12-13 20:15:29 +0000694}
695
paulfe69a502005-09-10 16:55:02 +0000696static inline size_t
697assegment_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 */
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)
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 */
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);
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
paul94f2b392005-06-28 12:44:16 +0000792static struct assegment *
paul718e3742002-12-13 20:15:29 +0000793aspath_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 {
paulfe69a502005-09-10 16:55:02 +0000801 asset = assegment_new (AS_SET, 1);
802 if (! aspath->segments)
803 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000804 else
paulfe69a502005-09-10 16:55:02 +0000805 {
806 struct assegment *seg = aspath->segments;
807 while (seg->next)
808 seg = seg->next;
809 seg->next = asset;
810 }
paul718e3742002-12-13 20:15:29 +0000811 asset->type = AS_SET;
812 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000813 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000814 }
815 else
816 {
paul718e3742002-12-13 20:15:29 +0000817 /* Check this AS value already exists or not. */
818 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000819 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000820 return asset;
paulfe69a502005-09-10 16:55:02 +0000821
paul718e3742002-12-13 20:15:29 +0000822 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000823 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
824 asset->length * AS_VALUE_SIZE);
825 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000826 }
paulfe69a502005-09-10 16:55:02 +0000827
paul718e3742002-12-13 20:15:29 +0000828
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;
paulfe69a502005-09-10 16:55:02 +0000839 int from;
840 struct assegment *seg1 = as1->segments;
841 struct assegment *seg2 = as2->segments;
paul718e3742002-12-13 20:15:29 +0000842 struct aspath *aspath;
843 struct assegment *asset;
844
845 match = 0;
846 minlen = 0;
847 aspath = NULL;
848 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000849
850 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000851 while (seg1 && seg2)
paul718e3742002-12-13 20:15:29 +0000852 {
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++)
paulfe69a502005-09-10 16:55:02 +0000861 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +0000862 break;
863
864 if (match)
865 {
866 if (! aspath)
paulfe69a502005-09-10 16:55:02 +0000867 aspath = aspath_new ();
868 aspath->segments = assegment_new (seg1->type, 0);
869 aspath->segments = assegment_append_asns (aspath->segments,
870 seg1->as, match);
paul718e3742002-12-13 20:15:29 +0000871 }
872
873 if (match != minlen || match != seg1->length
874 || seg1->length != seg2->length)
875 break;
paulfe69a502005-09-10 16:55:02 +0000876
877 seg1 = seg1->next;
878 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +0000879 }
880
881 if (! aspath)
882 aspath = aspath_new();
883
884 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +0000885 from = match;
886 while (seg1)
paul718e3742002-12-13 20:15:29 +0000887 {
paulfe69a502005-09-10 16:55:02 +0000888 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;
paul718e3742002-12-13 20:15:29 +0000893 }
894
paulfe69a502005-09-10 16:55:02 +0000895 from = match;
896 while (seg2)
paul718e3742002-12-13 20:15:29 +0000897 {
paulfe69a502005-09-10 16:55:02 +0000898 for (i = from; i < seg2->length; i++)
899 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +0000900
paulfe69a502005-09-10 16:55:02 +0000901 from = 0;
902 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +0000903 }
paulfe69a502005-09-10 16:55:02 +0000904
905 assegment_normalise (aspath->segments);
906 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +0000907 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{
paulfe69a502005-09-10 16:55:02 +0000916 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +0000917 return 0;
paulfe69a502005-09-10 16:55:02 +0000918
919 if (aspath->segments
920 && (aspath->segments->type == AS_SEQUENCE)
921 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +0000922 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{
paulfe69a502005-09-10 16:55:02 +0000931 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +0000932 int count = 0;
933
paulfe69a502005-09-10 16:55:02 +0000934 if ( (aspath == NULL) || (aspath->segments) )
paul718e3742002-12-13 20:15:29 +0000935 return 0;
paulfe69a502005-09-10 16:55:02 +0000936
937 seg = aspath->segments;
938
939 while (seg)
paul718e3742002-12-13 20:15:29 +0000940 {
941 int i;
paul718e3742002-12-13 20:15:29 +0000942
paulfe69a502005-09-10 16:55:02 +0000943 for (i = 0; i < seg->length; i++)
944 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +0000945 count++;
paulfe69a502005-09-10 16:55:02 +0000946
947 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000948 }
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{
paulfe69a502005-09-10 16:55:02 +0000956 struct assegment *seg;
957
958 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +0000959 return 0;
paulfe69a502005-09-10 16:55:02 +0000960
961 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +0000962
paulfe69a502005-09-10 16:55:02 +0000963 while (seg)
paul718e3742002-12-13 20:15:29 +0000964 {
965 int i;
paul718e3742002-12-13 20:15:29 +0000966
paulfe69a502005-09-10 16:55:02 +0000967 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +0000968 {
paulfe69a502005-09-10 16:55:02 +0000969 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
970 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +0000971 return 0;
972 }
paulfe69a502005-09-10 16:55:02 +0000973 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000974 }
975 return 1;
976}
977
978/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +0000979static struct aspath *
paul718e3742002-12-13 20:15:29 +0000980aspath_merge (struct aspath *as1, struct aspath *as2)
981{
paulfe69a502005-09-10 16:55:02 +0000982 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +0000983
984 if (! as1 || ! as2)
985 return NULL;
986
paulfe69a502005-09-10 16:55:02 +0000987 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);
paul718e3742002-12-13 20:15:29 +0000996 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{
paulfe69a502005-09-10 16:55:02 +00001003 struct assegment *seg1;
1004 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001005
1006 if (! as1 || ! as2)
1007 return NULL;
paulfe69a502005-09-10 16:55:02 +00001008
1009 seg1 = as1->segments;
1010 seg2 = as2->segments;
1011
1012 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001013 if (seg2 == NULL)
1014 {
paulfe69a502005-09-10 16:55:02 +00001015 as2->segments = assegment_dup_all (as1->segments);
1016 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001017 return as2;
1018 }
paulfe69a502005-09-10 16:55:02 +00001019
1020 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001021 if (seg1 == NULL)
1022 return as2;
paulfe69a502005-09-10 16:55:02 +00001023
1024 /* find the tail as1's segment chain. */
1025 while (seg1 && seg1->next)
1026 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001027
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 {
paulfe69a502005-09-10 16:55:02 +00001034 /* 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 */
paul718e3742002-12-13 20:15:29 +00001042
paulfe69a502005-09-10 16:55:02 +00001043 /* 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);
paul718e3742002-12-13 20:15:29 +00001065 return as2;
1066 }
1067 else
1068 {
1069 /* AS_SET merge code is needed at here. */
1070 return aspath_merge (as1, as2);
1071 }
paulfe69a502005-09-10 16:55:02 +00001072 /* XXX: Ermmm, what if as1 has multiple segments?? */
1073
paul718e3742002-12-13 20:15:29 +00001074 /* 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{
paulfe69a502005-09-10 16:55:02 +00001081 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001082
1083 /* In case of empty aspath. */
1084 if (assegment == NULL || assegment->length == 0)
1085 {
paulfe69a502005-09-10 16:55:02 +00001086 aspath->segments = assegment_new (type, 1);
1087 aspath->segments->as[0] = asno;
1088
paul718e3742002-12-13 20:15:29 +00001089 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001090 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001091
1092 return aspath;
1093 }
1094
1095 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001096 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1097 else
paul718e3742002-12-13 20:15:29 +00001098 {
paulfe69a502005-09-10 16:55:02 +00001099 /* create new segment
1100 * push it onto head of aspath's segment chain
1101 */
paul718e3742002-12-13 20:15:29 +00001102 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001103
1104 newsegment = assegment_new (type, 1);
1105 newsegment->as[0] = asno;
1106
1107 newsegment->next = assegment;
1108 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001109 }
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{
paulfe69a502005-09-10 16:55:02 +00001126 struct assegment *seg1 = NULL;
1127 struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001128
paulfe69a502005-09-10 16:55:02 +00001129 if (!(aspath1 && aspath2))
1130 return 0;
paul718e3742002-12-13 20:15:29 +00001131
paulfe69a502005-09-10 16:55:02 +00001132 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;
paul718e3742002-12-13 20:15:29 +00001143
1144 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001145 if (!(seg1 && seg2
1146 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001147 return 0;
paulfe69a502005-09-10 16:55:02 +00001148
1149 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001150 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{
paulfe69a502005-09-10 16:55:02 +00001161 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001162 return 0;
paulfe69a502005-09-10 16:55:02 +00001163
paulad727402005-11-23 02:47:02 +00001164 if ( !(aspath1->segments && aspath2->segments) )
1165 return 0;
1166
paulfe69a502005-09-10 16:55:02 +00001167 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1168 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001169 return 0;
paulfe69a502005-09-10 16:55:02 +00001170
1171 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001172 return 1;
1173
1174 return 0;
1175}
1176
paulfe69a502005-09-10 16:55:02 +00001177/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1178 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001179struct aspath *
1180aspath_delete_confed_seq (struct aspath *aspath)
1181{
paulfe69a502005-09-10 16:55:02 +00001182 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001183
paulfe69a502005-09-10 16:55:02 +00001184 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001185 return aspath;
1186
paulfe69a502005-09-10 16:55:02 +00001187 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;
paul718e3742002-12-13 20:15:29 +00001194
paulfe69a502005-09-10 16:55:02 +00001195 /* "... 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))
paul718e3742002-12-13 20:15:29 +00001201 {
paulfe69a502005-09-10 16:55:02 +00001202 aspath->segments = seg->next;
1203 assegment_free (seg);
1204 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001205 }
paulfe69a502005-09-10 16:55:02 +00001206 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001207 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. */
paul94f2b392005-06-28 12:44:16 +00001219static void
paul718e3742002-12-13 20:15:29 +00001220aspath_as_add (struct aspath *as, as_t asno)
1221{
paulfe69a502005-09-10 16:55:02 +00001222 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001223
1224 /* Last segment search procedure. */
paulfe69a502005-09-10 16:55:02 +00001225 while (seg && seg->next)
1226 seg = seg->next;
1227
1228 if (!seg)
1229 return;
1230
1231 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001232}
1233
1234/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001235static void
paul718e3742002-12-13 20:15:29 +00001236aspath_segment_add (struct aspath *as, int type)
1237{
paulfe69a502005-09-10 16:55:02 +00001238 struct assegment *seg = as->segments;
1239 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001240
paulfe69a502005-09-10 16:55:02 +00001241 while (seg && seg->next)
1242 seg = seg->next;
1243
1244 if (seg == NULL)
1245 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001246 else
paulfe69a502005-09-10 16:55:02 +00001247 seg->next = new;
paul718e3742002-12-13 20:15:29 +00001248}
1249
1250struct aspath *
paul94f2b392005-06-28 12:44:16 +00001251aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001252{
1253 return aspath_parse (NULL, 0);
1254}
1255
1256struct aspath *
paul94f2b392005-06-28 12:44:16 +00001257aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001258{
1259 struct aspath *aspath;
1260
1261 aspath = aspath_new ();
1262 aspath->str = aspath_make_str_count (aspath);
1263 return aspath;
1264}
1265
1266unsigned long
paulfe69a502005-09-10 16:55:02 +00001267aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001268{
1269 return ashash->count;
1270}
1271
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,
paulfe69a502005-09-10 16:55:02 +00001287 as_token_confed_seq_start,
1288 as_token_confed_seq_end,
1289 as_token_confed_set_start,
1290 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001291 as_token_unknown
1292};
1293
1294/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001295static const char *
paulfd79ac92004-10-13 05:06:08 +00001296aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
paul718e3742002-12-13 20:15:29 +00001297{
paulfd79ac92004-10-13 05:06:08 +00001298 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001299
paulfe69a502005-09-10 16:55:02 +00001300 /* Skip seperators (space for sequences, ',' for sets). */
1301 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001302 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 '(':
paulfe69a502005-09-10 16:55:02 +00001322 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001323 p++;
1324 return p;
1325 break;
1326 case ')':
paulfe69a502005-09-10 16:55:02 +00001327 *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;
paul718e3742002-12-13 20:15:29 +00001338 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 *
paulfd79ac92004-10-13 05:06:08 +00001367aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001368{
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;
paulfe69a502005-09-10 16:55:02 +00001402 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001403 as_type = AS_CONFED_SEQUENCE;
1404 aspath_segment_add (aspath, as_type);
1405 needtype = 0;
1406 break;
paulfe69a502005-09-10 16:55:02 +00001407 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:
paul718e3742002-12-13 20:15:29 +00001417 as_type = AS_SEQUENCE;
1418 needtype = 1;
1419 break;
1420 case as_token_unknown:
1421 default:
paulfe69a502005-09-10 16:55:02 +00001422 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001423 return NULL;
1424 break;
1425 }
1426 }
1427
1428 aspath->str = aspath_make_str_count (aspath);
1429
1430 return aspath;
1431}
1432
1433/* Make hash value by raw aspath data. */
1434unsigned int
1435aspath_key_make (struct aspath *aspath)
1436{
1437 unsigned int key = 0;
paulfe69a502005-09-10 16:55:02 +00001438 unsigned int i;
1439 struct assegment *seg = aspath->segments;
1440 struct assegment *prev = NULL;
paul718e3742002-12-13 20:15:29 +00001441
paulfe69a502005-09-10 16:55:02 +00001442 while (seg)
paul718e3742002-12-13 20:15:29 +00001443 {
paulfe69a502005-09-10 16:55:02 +00001444 /* 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;
paul718e3742002-12-13 20:15:29 +00001455 }
1456
1457 return key;
1458}
1459
1460/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001461static int
paulfe69a502005-09-10 16:55:02 +00001462aspath_cmp (void *arg1, void *arg2)
paul718e3742002-12-13 20:15:29 +00001463{
paulfe69a502005-09-10 16:55:02 +00001464 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;
paul718e3742002-12-13 20:15:29 +00001483}
1484
1485/* AS path hash initialize. */
1486void
paul94f2b392005-06-28 12:44:16 +00001487aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001488{
1489 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1490}
1491
1492/* return and as path value */
1493const char *
1494aspath_print (struct aspath *as)
1495{
paulfe69a502005-09-10 16:55:02 +00001496 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001497}
1498
1499/* Printing functions */
1500void
1501aspath_print_vty (struct vty *vty, struct aspath *as)
1502{
1503 vty_out (vty, "%s", as->str);
1504}
1505
paul94f2b392005-06-28 12:44:16 +00001506static void
paul718e3742002-12-13 20:15:29 +00001507aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1508{
1509 struct aspath *as;
1510
1511 as = (struct aspath *) backet->data;
1512
paulefa9f832002-12-13 21:47:59 +00001513 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001514 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}