blob: 9ff1205cb2d74a80689a1ac1ca2e77281124f0c4 [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{
212 seg->as = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
213 ASSEGMENT_DATA_SIZE (seg->length + num));
214
215 if (seg->as)
216 {
217 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num));
218 seg->length += num;
219 return seg;
220 }
221
222 assegment_free_all (seg);
223 return NULL;
224}
225
226static int
227int_cmp (const void *p1, const void *p2)
228{
229 const as_t *as1 = p1;
230 const as_t *as2 = p2;
231
232 return (*as1 == *as2)
233 ? 0 : ( (*as1 > *as2) ? 1 : -1);
234}
235
236/* normalise the segment.
237 * In particular, merge runs of AS_SEQUENCEs into one segment
238 * Internally, we do not care about the wire segment length limit, and
239 * we want each distinct AS_PATHs to have the exact same internal
240 * representation - eg, so that our hashing actually works..
241 */
242static struct assegment *
243assegment_normalise (struct assegment *head)
244{
245 struct assegment *seg = head, *pin;
246 struct assegment *tmp;
247
248 if (!head)
249 return head;
250
251 while (seg)
252 {
253 pin = seg;
254
255 /* Sort values SET segments, for determinism in paths to aid
256 * creation of hash values / path comparisons
257 * and because it helps other lesser implementations ;)
258 */
259 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
260 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
261
262 /* read ahead from the current, pinned segment while the segments
263 * are packable/mergeable. Append all following packable segments
264 * to the segment we have pinned and remove these appended
265 * segments.
266 */
267 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
268 {
269 tmp = pin->next;
270 seg = pin->next;
271
272 /* append the next sequence to the pinned sequence */
273 pin = assegment_append_asns (pin, seg->as, seg->length);
274
275 /* bypass the next sequence */
276 pin->next = seg->next;
277
278 /* get rid of the now referenceless segment */
279 assegment_free (tmp);
280
281 }
282
283 seg = pin->next;
284 }
285 return head;
286}
287
paul718e3742002-12-13 20:15:29 +0000288static struct aspath *
paulfe69a502005-09-10 16:55:02 +0000289aspath_new (void)
paul718e3742002-12-13 20:15:29 +0000290{
291 struct aspath *aspath;
292
293 aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
294 memset (aspath, 0, sizeof (struct aspath));
295 return aspath;
296}
297
298/* Free AS path structure. */
299void
300aspath_free (struct aspath *aspath)
301{
302 if (!aspath)
303 return;
paulfe69a502005-09-10 16:55:02 +0000304 if (aspath->segments)
305 assegment_free_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000306 if (aspath->str)
307 XFREE (MTYPE_AS_STR, aspath->str);
308 XFREE (MTYPE_AS_PATH, aspath);
309}
310
311/* Unintern aspath from AS path bucket. */
312void
313aspath_unintern (struct aspath *aspath)
314{
315 struct aspath *ret;
316
317 if (aspath->refcnt)
318 aspath->refcnt--;
319
320 if (aspath->refcnt == 0)
321 {
322 /* This aspath must exist in aspath hash table. */
323 ret = hash_release (ashash, aspath);
324 assert (ret != NULL);
325 aspath_free (aspath);
326 }
327}
328
329/* Return the start or end delimiters for a particular Segment type */
330#define AS_SEG_START 0
331#define AS_SEG_END 1
332static char
333aspath_delimiter_char (u_char type, u_char which)
334{
335 int i;
336 struct
337 {
338 int type;
339 char start;
340 char end;
341 } aspath_delim_char [] =
342 {
343 { AS_SET, '{', '}' },
paul718e3742002-12-13 20:15:29 +0000344 { AS_CONFED_SET, '[', ']' },
345 { AS_CONFED_SEQUENCE, '(', ')' },
346 { 0 }
347 };
348
349 for (i = 0; aspath_delim_char[i].type != 0; i++)
350 {
351 if (aspath_delim_char[i].type == type)
352 {
353 if (which == AS_SEG_START)
354 return aspath_delim_char[i].start;
355 else if (which == AS_SEG_END)
356 return aspath_delim_char[i].end;
357 }
358 }
359 return ' ';
360}
361
paulfe69a502005-09-10 16:55:02 +0000362/* countup asns from this segment and index onward */
363static int
364assegment_count_asns (struct assegment *seg, int from)
365{
366 int count = 0;
367 while (seg)
368 {
369 if (!from)
370 count += seg->length;
371 else
372 {
373 count += (seg->length - from);
374 from = 0;
375 }
376 seg = seg->next;
377 }
378 return count;
379}
380
381unsigned int
382aspath_count_confeds (struct aspath *aspath)
383{
384 int count = 0;
385 struct assegment *seg = aspath->segments;
386
387 while (seg)
388 {
389 if (seg->type == AS_CONFED_SEQUENCE)
390 count += seg->length;
391 else if (seg->type == AS_CONFED_SET)
392 count++;
393
394 seg = seg->next;
395 }
396 return count;
397}
398
399unsigned int
400aspath_count_hops (struct aspath *aspath)
401{
402 int count = 0;
403 struct assegment *seg = aspath->segments;
404
405 while (seg)
406 {
407 if (seg->type == AS_SEQUENCE)
408 count += seg->length;
409 else if (seg->type == AS_SET)
410 count++;
411
412 seg = seg->next;
413 }
414 return count;
415}
416
417unsigned int
418aspath_size (struct aspath *aspath)
419{
420 int size = 0;
421 struct assegment *seg = aspath->segments;
422
423 while (seg)
424 {
425 size += ASSEGMENT_SIZE(seg->length);
426 seg = seg->next;
427 }
428 return size;
429}
430
paul718e3742002-12-13 20:15:29 +0000431/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000432static char *
paul718e3742002-12-13 20:15:29 +0000433aspath_make_str_count (struct aspath *as)
434{
paulfe69a502005-09-10 16:55:02 +0000435 struct assegment *seg;
436 int str_size;
437 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000438 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000439
440 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000441 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000442 {
443 str_buf = XMALLOC (MTYPE_AS_STR, 1);
444 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000445 return str_buf;
446 }
paulfe69a502005-09-10 16:55:02 +0000447
448 seg = as->segments;
449
450 /* ASN takes 5 chars at least, plus seperator, see below.
451 * If there is one differing segment type, we need an additional
452 * 2 chars for segment delimiters, and the final '\0'.
453 * Hopefully this is large enough to avoid hitting the realloc
454 * code below for most common sequences.
455 */
456#define ASN_STR_LEN (5 + 1)
457 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
458 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000459 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000460
paulfe69a502005-09-10 16:55:02 +0000461 while (seg)
paul718e3742002-12-13 20:15:29 +0000462 {
463 int i;
paulfe69a502005-09-10 16:55:02 +0000464 char seperator;
paul718e3742002-12-13 20:15:29 +0000465
paulfe69a502005-09-10 16:55:02 +0000466 /* Check AS type validity. Set seperator for segment */
467 switch (seg->type)
468 {
469 case AS_SET:
470 case AS_CONFED_SET:
471 seperator = ',';
472 break;
473 case AS_SEQUENCE:
474 case AS_CONFED_SEQUENCE:
475 seperator = ' ';
476 break;
477 default:
478 XFREE (MTYPE_AS_STR, str_buf);
479 return NULL;
480 }
481
482 /* We might need to increase str_buf, particularly if path has
483 * differing segments types, our initial guesstimate above will
484 * have been wrong. need 5 chars for ASN, a seperator each and
485 * potentially two segment delimiters, plus a space between each
486 * segment and trailing zero.
487 */
488#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
489 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
490 {
491 str_size = len + SEGMENT_STR_LEN(seg);
492 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
493 }
494#undef ASN_STR_LEN
495#undef SEGMENT_STR_LEN
496
497 if (seg->type != AS_SEQUENCE)
498 len += snprintf (str_buf + len, str_size - len,
499 "%c",
500 aspath_delimiter_char (seg->type, AS_SEG_START));
501
502 /* write out the ASNs, with their seperators, bar the last one*/
503 for (i = 0; i < seg->length; i++)
504 {
505 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
506
507 if (i < (seg->length - 1))
508 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
509 }
510
511 if (seg->type != AS_SEQUENCE)
512 len += snprintf (str_buf + len, str_size - len, "%c",
513 aspath_delimiter_char (seg->type, AS_SEG_END));
514 if (seg->next)
515 len += snprintf (str_buf + len, str_size - len, " ");
516
517 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000518 }
paulfe69a502005-09-10 16:55:02 +0000519
520 assert (len < str_size);
521
522 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000523
524 return str_buf;
525}
526
paulfe69a502005-09-10 16:55:02 +0000527static void
528aspath_str_update (struct aspath *as)
529{
530 if (as->str)
531 XFREE (MTYPE_AS_STR, as->str);
532 as->str = aspath_make_str_count (as);
533}
534
paul718e3742002-12-13 20:15:29 +0000535/* Intern allocated AS path. */
536struct aspath *
537aspath_intern (struct aspath *aspath)
538{
539 struct aspath *find;
540
541 /* Assert this AS path structure is not interned. */
542 assert (aspath->refcnt == 0);
543
544 /* Check AS path hash. */
545 find = hash_get (ashash, aspath, hash_alloc_intern);
546
547 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000548 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000549
550 find->refcnt++;
551
552 if (! find->str)
553 find->str = aspath_make_str_count (find);
554
555 return find;
556}
557
558/* Duplicate aspath structure. Created same aspath structure but
559 reference count and AS path string is cleared. */
560struct aspath *
561aspath_dup (struct aspath *aspath)
562{
563 struct aspath *new;
564
paulfe69a502005-09-10 16:55:02 +0000565 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000566
paulfe69a502005-09-10 16:55:02 +0000567 if (aspath->segments)
568 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000569 else
paulfe69a502005-09-10 16:55:02 +0000570 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000571
paulfe69a502005-09-10 16:55:02 +0000572 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000573
574 return new;
575}
576
paul94f2b392005-06-28 12:44:16 +0000577static void *
paulfe69a502005-09-10 16:55:02 +0000578aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000579{
580 struct aspath *aspath;
581
582 /* New aspath strucutre is needed. */
paulfe69a502005-09-10 16:55:02 +0000583 aspath = aspath_dup (arg);
584
paul718e3742002-12-13 20:15:29 +0000585 /* Make AS path string. */
586 aspath->str = aspath_make_str_count (aspath);
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
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);
673 if (! find)
674 return NULL;
675 find->refcnt++;
676
677 return find;
678}
679
paulfe69a502005-09-10 16:55:02 +0000680static inline void
681assegment_data_put (struct stream *s, as_t *as, int num)
paul718e3742002-12-13 20:15:29 +0000682{
paulfe69a502005-09-10 16:55:02 +0000683 int i;
684 assert (num <= AS_SEGMENT_MAX);
685
686 for (i = 0; i < num; i++)
687 stream_putw (s, as[i]);
paul718e3742002-12-13 20:15:29 +0000688}
689
paulfe69a502005-09-10 16:55:02 +0000690static inline size_t
691assegment_header_put (struct stream *s, u_char type, int length)
692{
693 size_t lenp;
694 assert (length <= AS_SEGMENT_MAX);
695 stream_putc (s, type);
696 lenp = stream_get_endp (s);
697 stream_putc (s, length);
698 return lenp;
699}
700
701/* write aspath data to stream */
702void
703aspath_put (struct stream *s, struct aspath *as)
704{
705 struct assegment *seg = as->segments;
706
707 if (!seg || seg->length == 0)
708 return;
709
710 if (seg)
711 {
712 while (seg && (ASSEGMENT_LEN (seg) <= STREAM_WRITEABLE(s)))
713 {
714 int written = 0;
715 size_t lenp;
716
717 /* Overlength segments have to be split up */
718 while ( (seg->length - written) > AS_SEGMENT_MAX)
719 {
720 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
721 assegment_data_put (s, seg->as, AS_SEGMENT_MAX);
722 written += AS_SEGMENT_MAX;
723 }
724
725 /* write the final segment, probably is also the first */
726 lenp = assegment_header_put (s, seg->type, seg->length - written);
727 assegment_data_put (s, (seg->as + written), seg->length - written);
728
729 /* Sequence-type segments can be 'packed' together
730 * Case of a segment which was overlength and split up
731 * will be missed here, but that doesn't matter.
732 */
733 if (seg->next && ASSEGMENTS_PACKABLE (seg, seg->next))
734 {
735 /* NB: We should never normally get here given we
736 * normalise aspath data when parse them. However, better
737 * safe than sorry. We potentially could call
738 * assegment_normalise here instead, but it's cheaper and
739 * easier to do it on the fly here rather than go through
740 * the segment list twice every time we write out
741 * aspath's.
742 */
743
744 /* Next segment's data can fit in this one */
745 assegment_data_put (s, seg->next->as, seg->next->length);
746
747 /* update the length of the segment header */
748 stream_putc_at (s, lenp,
749 seg->length - written + seg->next->length);
750 seg = seg->next->next; /* skip to past next */
751 }
752 else
753 seg = seg->next;
754 }
755 }
756}
757
758/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
759 * We have no way to manage the storage, so we use a static stream
760 * wrapper around aspath_put.
761 */
762u_char *
763aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
764{
765#define SNMP_PATHSEG_MAX 1024
766 static struct stream *s = NULL;
767
768 if (!s)
769 s = stream_new (SNMP_PATHSEG_MAX);
770 else
771 stream_reset (s);
772
773 if (!as)
774 {
775 *varlen = 0;
776 return NULL;
777 }
778 aspath_put (s, as);
779
780 *varlen = stream_get_endp (s);
781 return stream_pnt(s);
782}
783
784#define min(A,B) ((A) < (B) ? (A) : (B))
785
paul94f2b392005-06-28 12:44:16 +0000786static struct assegment *
paul718e3742002-12-13 20:15:29 +0000787aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
788 as_t as)
789{
790 int i;
791
792 /* If this is first AS set member, create new as-set segment. */
793 if (asset == NULL)
794 {
paulfe69a502005-09-10 16:55:02 +0000795 asset = assegment_new (AS_SET, 1);
796 if (! aspath->segments)
797 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000798 else
paulfe69a502005-09-10 16:55:02 +0000799 {
800 struct assegment *seg = aspath->segments;
801 while (seg->next)
802 seg = seg->next;
803 seg->next = asset;
804 }
paul718e3742002-12-13 20:15:29 +0000805 asset->type = AS_SET;
806 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000807 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000808 }
809 else
810 {
paul718e3742002-12-13 20:15:29 +0000811 /* Check this AS value already exists or not. */
812 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000813 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000814 return asset;
paulfe69a502005-09-10 16:55:02 +0000815
paul718e3742002-12-13 20:15:29 +0000816 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000817 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
818 asset->length * AS_VALUE_SIZE);
819 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000820 }
paulfe69a502005-09-10 16:55:02 +0000821
paul718e3742002-12-13 20:15:29 +0000822
823 return asset;
824}
825
826/* Modify as1 using as2 for aggregation. */
827struct aspath *
828aspath_aggregate (struct aspath *as1, struct aspath *as2)
829{
830 int i;
831 int minlen;
832 int match;
paulfe69a502005-09-10 16:55:02 +0000833 int from;
834 struct assegment *seg1 = as1->segments;
835 struct assegment *seg2 = as2->segments;
paul718e3742002-12-13 20:15:29 +0000836 struct aspath *aspath;
837 struct assegment *asset;
838
839 match = 0;
840 minlen = 0;
841 aspath = NULL;
842 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000843
844 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000845 while (seg1 && seg2)
paul718e3742002-12-13 20:15:29 +0000846 {
847 /* Check segment type. */
848 if (seg1->type != seg2->type)
849 break;
850
851 /* Minimum segment length. */
852 minlen = min (seg1->length, seg2->length);
853
854 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +0000855 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +0000856 break;
857
858 if (match)
859 {
860 if (! aspath)
paulfe69a502005-09-10 16:55:02 +0000861 aspath = aspath_new ();
862 aspath->segments = assegment_new (seg1->type, 0);
863 aspath->segments = assegment_append_asns (aspath->segments,
864 seg1->as, match);
paul718e3742002-12-13 20:15:29 +0000865 }
866
867 if (match != minlen || match != seg1->length
868 || seg1->length != seg2->length)
869 break;
paulfe69a502005-09-10 16:55:02 +0000870
871 seg1 = seg1->next;
872 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +0000873 }
874
875 if (! aspath)
876 aspath = aspath_new();
877
878 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +0000879 from = match;
880 while (seg1)
paul718e3742002-12-13 20:15:29 +0000881 {
paulfe69a502005-09-10 16:55:02 +0000882 for (i = from; i < seg1->length; i++)
883 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
884
885 from = 0;
886 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +0000887 }
888
paulfe69a502005-09-10 16:55:02 +0000889 from = match;
890 while (seg2)
paul718e3742002-12-13 20:15:29 +0000891 {
paulfe69a502005-09-10 16:55:02 +0000892 for (i = from; i < seg2->length; i++)
893 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +0000894
paulfe69a502005-09-10 16:55:02 +0000895 from = 0;
896 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +0000897 }
paulfe69a502005-09-10 16:55:02 +0000898
899 assegment_normalise (aspath->segments);
900 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +0000901 return aspath;
902}
903
904/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
905 attribute, check the leftmost AS number in the AS_PATH attribute is
906 or not the peer's AS number. */
907int
908aspath_firstas_check (struct aspath *aspath, as_t asno)
909{
paulfe69a502005-09-10 16:55:02 +0000910 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +0000911 return 0;
paulfe69a502005-09-10 16:55:02 +0000912
913 if (aspath->segments
914 && (aspath->segments->type == AS_SEQUENCE)
915 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +0000916 return 1;
917
918 return 0;
919}
920
921/* AS path loop check. If aspath contains asno then return 1. */
922int
923aspath_loop_check (struct aspath *aspath, as_t asno)
924{
paulfe69a502005-09-10 16:55:02 +0000925 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +0000926 int count = 0;
927
paulfe69a502005-09-10 16:55:02 +0000928 if ( (aspath == NULL) || (aspath->segments) )
paul718e3742002-12-13 20:15:29 +0000929 return 0;
paulfe69a502005-09-10 16:55:02 +0000930
931 seg = aspath->segments;
932
933 while (seg)
paul718e3742002-12-13 20:15:29 +0000934 {
935 int i;
paul718e3742002-12-13 20:15:29 +0000936
paulfe69a502005-09-10 16:55:02 +0000937 for (i = 0; i < seg->length; i++)
938 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +0000939 count++;
paulfe69a502005-09-10 16:55:02 +0000940
941 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000942 }
943 return count;
944}
945
946/* When all of AS path is private AS return 1. */
947int
948aspath_private_as_check (struct aspath *aspath)
949{
paulfe69a502005-09-10 16:55:02 +0000950 struct assegment *seg;
951
952 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +0000953 return 0;
paulfe69a502005-09-10 16:55:02 +0000954
955 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +0000956
paulfe69a502005-09-10 16:55:02 +0000957 while (seg)
paul718e3742002-12-13 20:15:29 +0000958 {
959 int i;
paul718e3742002-12-13 20:15:29 +0000960
paulfe69a502005-09-10 16:55:02 +0000961 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +0000962 {
paulfe69a502005-09-10 16:55:02 +0000963 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
964 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +0000965 return 0;
966 }
paulfe69a502005-09-10 16:55:02 +0000967 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000968 }
969 return 1;
970}
971
972/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +0000973static struct aspath *
paul718e3742002-12-13 20:15:29 +0000974aspath_merge (struct aspath *as1, struct aspath *as2)
975{
paulfe69a502005-09-10 16:55:02 +0000976 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +0000977
978 if (! as1 || ! as2)
979 return NULL;
980
paulfe69a502005-09-10 16:55:02 +0000981 last = new = assegment_dup_all (as1->segments);
982
983 /* find the last valid segment */
984 while (last && last->next)
985 last = last->next;
986
987 last->next = as2->segments;
988 as2->segments = new;
989 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +0000990 return as2;
991}
992
993/* Prepend as1 to as2. as2 should be uninterned aspath. */
994struct aspath *
995aspath_prepend (struct aspath *as1, struct aspath *as2)
996{
paulfe69a502005-09-10 16:55:02 +0000997 struct assegment *seg1;
998 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +0000999
1000 if (! as1 || ! as2)
1001 return NULL;
paulfe69a502005-09-10 16:55:02 +00001002
1003 seg1 = as1->segments;
1004 seg2 = as2->segments;
1005
1006 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001007 if (seg2 == NULL)
1008 {
paulfe69a502005-09-10 16:55:02 +00001009 as2->segments = assegment_dup_all (as1->segments);
1010 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001011 return as2;
1012 }
paulfe69a502005-09-10 16:55:02 +00001013
1014 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001015 if (seg1 == NULL)
1016 return as2;
paulfe69a502005-09-10 16:55:02 +00001017
1018 /* find the tail as1's segment chain. */
1019 while (seg1 && seg1->next)
1020 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001021
1022 /* Compare last segment type of as1 and first segment type of as2. */
1023 if (seg1->type != seg2->type)
1024 return aspath_merge (as1, as2);
1025
1026 if (seg1->type == AS_SEQUENCE)
1027 {
paulfe69a502005-09-10 16:55:02 +00001028 /* We have two chains of segments, as1->segments and seg2,
1029 * and we have to attach them together, merging the attaching
1030 * segments together into one.
1031 *
1032 * 1. dupe as1->segments onto head of as2
1033 * 2. merge seg2's asns onto last segment of this new chain
1034 * 3. attach chain after seg2
1035 */
paul718e3742002-12-13 20:15:29 +00001036
paulfe69a502005-09-10 16:55:02 +00001037 /* dupe as1 onto as2's head */
1038 seg1 = as2->segments = assegment_dup_all (as1->segments);
1039
1040 /* refind the tail of as2, reusing seg1 */
1041 while (seg1 && seg1->next)
1042 seg1 = seg1->next;
1043
1044 /* merge the old head, seg2, into tail, seg1 */
1045 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1046
1047 /* bypass the merged seg2, and attach any chain after it to
1048 * chain descending from as2's head
1049 */
1050 seg1->next = seg2->next;
1051
1052 /* seg2 is now referenceless and useless*/
1053 assegment_free (seg2);
1054
1055 /* we've now prepended as1's segment chain to as2, merging
1056 * the inbetween AS_SEQUENCE of seg2 in the process
1057 */
1058 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001059 return as2;
1060 }
1061 else
1062 {
1063 /* AS_SET merge code is needed at here. */
1064 return aspath_merge (as1, as2);
1065 }
paulfe69a502005-09-10 16:55:02 +00001066 /* XXX: Ermmm, what if as1 has multiple segments?? */
1067
paul718e3742002-12-13 20:15:29 +00001068 /* Not reached */
1069}
1070
1071/* Add specified AS to the leftmost of aspath. */
1072static struct aspath *
1073aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1074{
paulfe69a502005-09-10 16:55:02 +00001075 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001076
1077 /* In case of empty aspath. */
1078 if (assegment == NULL || assegment->length == 0)
1079 {
paulfe69a502005-09-10 16:55:02 +00001080 aspath->segments = assegment_new (type, 1);
1081 aspath->segments->as[0] = asno;
1082
paul718e3742002-12-13 20:15:29 +00001083 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001084 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001085
1086 return aspath;
1087 }
1088
1089 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001090 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1091 else
paul718e3742002-12-13 20:15:29 +00001092 {
paulfe69a502005-09-10 16:55:02 +00001093 /* create new segment
1094 * push it onto head of aspath's segment chain
1095 */
paul718e3742002-12-13 20:15:29 +00001096 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001097
1098 newsegment = assegment_new (type, 1);
1099 newsegment->as[0] = asno;
1100
1101 newsegment->next = assegment;
1102 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001103 }
1104
1105 return aspath;
1106}
1107
1108/* Add specified AS to the leftmost of aspath. */
1109struct aspath *
1110aspath_add_seq (struct aspath *aspath, as_t asno)
1111{
1112 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1113}
1114
1115/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1116 as2's leftmost AS is same return 1. */
1117int
1118aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
1119{
paulfe69a502005-09-10 16:55:02 +00001120 struct assegment *seg1 = NULL;
1121 struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001122
paulfe69a502005-09-10 16:55:02 +00001123 if (!(aspath1 && aspath2))
1124 return 0;
paul718e3742002-12-13 20:15:29 +00001125
paulfe69a502005-09-10 16:55:02 +00001126 seg1 = aspath1->segments;
1127 seg2 = aspath2->segments;
1128
1129 /* find first non-confed segments for each */
1130 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1131 || (seg1->type == AS_CONFED_SET)))
1132 seg1 = seg1->next;
1133
1134 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1135 || (seg2->type == AS_CONFED_SET)))
1136 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001137
1138 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001139 if (!(seg1 && seg2
1140 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001141 return 0;
paulfe69a502005-09-10 16:55:02 +00001142
1143 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001144 return 1;
1145
1146 return 0;
1147}
1148
1149/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1150 as2's leftmost AS is same return 1. (confederation as-path
1151 only). */
1152int
1153aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2)
1154{
paulfe69a502005-09-10 16:55:02 +00001155 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001156 return 0;
paulfe69a502005-09-10 16:55:02 +00001157
paulad727402005-11-23 02:47:02 +00001158 if ( !(aspath1->segments && aspath2->segments) )
1159 return 0;
1160
paulfe69a502005-09-10 16:55:02 +00001161 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1162 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001163 return 0;
paulfe69a502005-09-10 16:55:02 +00001164
1165 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001166 return 1;
1167
1168 return 0;
1169}
1170
paulfe69a502005-09-10 16:55:02 +00001171/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1172 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001173struct aspath *
1174aspath_delete_confed_seq (struct aspath *aspath)
1175{
paulfe69a502005-09-10 16:55:02 +00001176 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001177
paulfe69a502005-09-10 16:55:02 +00001178 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001179 return aspath;
1180
paulfe69a502005-09-10 16:55:02 +00001181 seg = aspath->segments;
1182
1183 /* "if the first path segment of the AS_PATH is
1184 * of type AS_CONFED_SEQUENCE,"
1185 */
1186 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1187 return aspath;
paul718e3742002-12-13 20:15:29 +00001188
paulfe69a502005-09-10 16:55:02 +00001189 /* "... that segment and any immediately following segments
1190 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1191 * from the AS_PATH attribute,"
1192 */
1193 while (seg &&
1194 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001195 {
paulfe69a502005-09-10 16:55:02 +00001196 aspath->segments = seg->next;
1197 assegment_free (seg);
1198 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001199 }
paulfe69a502005-09-10 16:55:02 +00001200 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001201 return aspath;
1202}
1203
1204/* Add new AS number to the leftmost part of the aspath as
1205 AS_CONFED_SEQUENCE. */
1206struct aspath*
1207aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1208{
1209 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1210}
1211
1212/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001213static void
paul718e3742002-12-13 20:15:29 +00001214aspath_as_add (struct aspath *as, as_t asno)
1215{
paulfe69a502005-09-10 16:55:02 +00001216 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001217
1218 /* Last segment search procedure. */
paulfe69a502005-09-10 16:55:02 +00001219 while (seg && seg->next)
1220 seg = seg->next;
1221
1222 if (!seg)
1223 return;
1224
1225 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001226}
1227
1228/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001229static void
paul718e3742002-12-13 20:15:29 +00001230aspath_segment_add (struct aspath *as, int type)
1231{
paulfe69a502005-09-10 16:55:02 +00001232 struct assegment *seg = as->segments;
1233 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001234
paulfe69a502005-09-10 16:55:02 +00001235 while (seg && seg->next)
1236 seg = seg->next;
1237
1238 if (seg == NULL)
1239 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001240 else
paulfe69a502005-09-10 16:55:02 +00001241 seg->next = new;
paul718e3742002-12-13 20:15:29 +00001242}
1243
1244struct aspath *
paul94f2b392005-06-28 12:44:16 +00001245aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001246{
1247 return aspath_parse (NULL, 0);
1248}
1249
1250struct aspath *
paul94f2b392005-06-28 12:44:16 +00001251aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001252{
1253 struct aspath *aspath;
1254
1255 aspath = aspath_new ();
1256 aspath->str = aspath_make_str_count (aspath);
1257 return aspath;
1258}
1259
1260unsigned long
paulfe69a502005-09-10 16:55:02 +00001261aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001262{
1263 return ashash->count;
1264}
1265
1266/*
1267 Theoretically, one as path can have:
1268
1269 One BGP packet size should be less than 4096.
1270 One BGP attribute size should be less than 4096 - BGP header size.
1271 One BGP aspath size should be less than 4096 - BGP header size -
1272 BGP mandantry attribute size.
1273*/
1274
1275/* AS path string lexical token enum. */
1276enum as_token
1277{
1278 as_token_asval,
1279 as_token_set_start,
1280 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001281 as_token_confed_seq_start,
1282 as_token_confed_seq_end,
1283 as_token_confed_set_start,
1284 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001285 as_token_unknown
1286};
1287
1288/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001289static const char *
paulfd79ac92004-10-13 05:06:08 +00001290aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
paul718e3742002-12-13 20:15:29 +00001291{
paulfd79ac92004-10-13 05:06:08 +00001292 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001293
paulfe69a502005-09-10 16:55:02 +00001294 /* Skip seperators (space for sequences, ',' for sets). */
1295 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001296 p++;
1297
1298 /* Check the end of the string and type specify characters
1299 (e.g. {}()). */
1300 switch (*p)
1301 {
1302 case '\0':
1303 return NULL;
1304 break;
1305 case '{':
1306 *token = as_token_set_start;
1307 p++;
1308 return p;
1309 break;
1310 case '}':
1311 *token = as_token_set_end;
1312 p++;
1313 return p;
1314 break;
1315 case '(':
paulfe69a502005-09-10 16:55:02 +00001316 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001317 p++;
1318 return p;
1319 break;
1320 case ')':
paulfe69a502005-09-10 16:55:02 +00001321 *token = as_token_confed_seq_end;
1322 p++;
1323 return p;
1324 break;
1325 case '[':
1326 *token = as_token_confed_set_start;
1327 p++;
1328 return p;
1329 break;
1330 case ']':
1331 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001332 p++;
1333 return p;
1334 break;
1335 }
1336
1337 /* Check actual AS value. */
1338 if (isdigit ((int) *p))
1339 {
1340 u_short asval;
1341
1342 *token = as_token_asval;
1343 asval = (*p - '0');
1344 p++;
1345 while (isdigit ((int) *p))
1346 {
1347 asval *= 10;
1348 asval += (*p - '0');
1349 p++;
1350 }
1351 *asno = asval;
1352 return p;
1353 }
1354
1355 /* There is no match then return unknown token. */
1356 *token = as_token_unknown;
1357 return p++;
1358}
1359
1360struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001361aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001362{
1363 enum as_token token;
1364 u_short as_type;
1365 u_short asno;
1366 struct aspath *aspath;
1367 int needtype;
1368
1369 aspath = aspath_new ();
1370
1371 /* We start default type as AS_SEQUENCE. */
1372 as_type = AS_SEQUENCE;
1373 needtype = 1;
1374
1375 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1376 {
1377 switch (token)
1378 {
1379 case as_token_asval:
1380 if (needtype)
1381 {
1382 aspath_segment_add (aspath, as_type);
1383 needtype = 0;
1384 }
1385 aspath_as_add (aspath, asno);
1386 break;
1387 case as_token_set_start:
1388 as_type = AS_SET;
1389 aspath_segment_add (aspath, as_type);
1390 needtype = 0;
1391 break;
1392 case as_token_set_end:
1393 as_type = AS_SEQUENCE;
1394 needtype = 1;
1395 break;
paulfe69a502005-09-10 16:55:02 +00001396 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001397 as_type = AS_CONFED_SEQUENCE;
1398 aspath_segment_add (aspath, as_type);
1399 needtype = 0;
1400 break;
paulfe69a502005-09-10 16:55:02 +00001401 case as_token_confed_seq_end:
1402 as_type = AS_SEQUENCE;
1403 needtype = 1;
1404 break;
1405 case as_token_confed_set_start:
1406 as_type = AS_CONFED_SET;
1407 aspath_segment_add (aspath, as_type);
1408 needtype = 0;
1409 break;
1410 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001411 as_type = AS_SEQUENCE;
1412 needtype = 1;
1413 break;
1414 case as_token_unknown:
1415 default:
paulfe69a502005-09-10 16:55:02 +00001416 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001417 return NULL;
1418 break;
1419 }
1420 }
1421
1422 aspath->str = aspath_make_str_count (aspath);
1423
1424 return aspath;
1425}
1426
1427/* Make hash value by raw aspath data. */
1428unsigned int
1429aspath_key_make (struct aspath *aspath)
1430{
1431 unsigned int key = 0;
paulfe69a502005-09-10 16:55:02 +00001432 unsigned int i;
1433 struct assegment *seg = aspath->segments;
1434 struct assegment *prev = NULL;
paul718e3742002-12-13 20:15:29 +00001435
paulfe69a502005-09-10 16:55:02 +00001436 while (seg)
paul718e3742002-12-13 20:15:29 +00001437 {
paulfe69a502005-09-10 16:55:02 +00001438 /* segment types should be part of the hash
1439 * otherwise seq(1) and set(1) will hash to same value
1440 */
1441 if (!(prev && seg->type == AS_SEQUENCE && seg->type == prev->type))
1442 key += seg->type;
1443
1444 for (i = 0; i < seg->length; i++)
1445 key += seg->as[i];
1446
1447 prev = seg;
1448 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001449 }
1450
1451 return key;
1452}
1453
1454/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001455static int
paulfe69a502005-09-10 16:55:02 +00001456aspath_cmp (void *arg1, void *arg2)
paul718e3742002-12-13 20:15:29 +00001457{
paulfe69a502005-09-10 16:55:02 +00001458 struct assegment *seg1 = ((struct aspath *)arg1)->segments;
1459 struct assegment *seg2 = ((struct aspath *)arg2)->segments;
1460
1461 while (seg1 || seg2)
1462 {
1463 int i;
1464 if ((!seg1 && seg2) || (seg1 && !seg2))
1465 return 0;
1466 if (seg1->type != seg2->type)
1467 return 0;
1468 if (seg1->length != seg2->length)
1469 return 0;
1470 for (i = 0; i < seg1->length; i++)
1471 if (seg1->as[i] != seg2->as[i])
1472 return 0;
1473 seg1 = seg1->next;
1474 seg2 = seg2->next;
1475 }
1476 return 1;
paul718e3742002-12-13 20:15:29 +00001477}
1478
1479/* AS path hash initialize. */
1480void
paul94f2b392005-06-28 12:44:16 +00001481aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001482{
1483 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1484}
1485
1486/* return and as path value */
1487const char *
1488aspath_print (struct aspath *as)
1489{
paulfe69a502005-09-10 16:55:02 +00001490 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001491}
1492
1493/* Printing functions */
1494void
1495aspath_print_vty (struct vty *vty, struct aspath *as)
1496{
1497 vty_out (vty, "%s", as->str);
1498}
1499
paul94f2b392005-06-28 12:44:16 +00001500static void
paul718e3742002-12-13 20:15:29 +00001501aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1502{
1503 struct aspath *as;
1504
1505 as = (struct aspath *) backet->data;
1506
paulefa9f832002-12-13 21:47:59 +00001507 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001508 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1509}
1510
1511/* Print all aspath and hash information. This function is used from
1512 `show ip bgp paths' command. */
1513void
1514aspath_print_all_vty (struct vty *vty)
1515{
1516 hash_iterate (ashash,
1517 (void (*) (struct hash_backet *, void *))
1518 aspath_show_all_iterator,
1519 vty);
1520}