blob: 7f85ea10f1b95182f71842a96d3dc0b4078b8c13 [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 */
599struct assegment *
600assegments_parse (struct stream *s, size_t length)
601{
602 struct assegment_header segh;
603 struct assegment *seg, *prev = NULL, *head = NULL;
604 size_t bytes = 0;
605
606 /* empty aspath (ie iBGP or somesuch) */
607 if (length == 0)
608 return NULL;
609
610 /* basic checks */
611 if ( (STREAM_READABLE(s) < length)
612 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
613 || (length % AS_VALUE_SIZE))
614 return NULL;
615
616 while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
617 && (bytes < length))
618 {
619 int i;
620
621 /* softly softly, get the header first on its own */
622 segh.type = stream_getc (s);
623 segh.length = stream_getc (s);
624
625 /* check it.. */
626 if ( ((bytes + ASSEGMENT_SIZE(segh.length)) > length)
627 /* 1771bis 4.3b: seg length contains one or more */
628 || (segh.length == 0)
629 /* Paranoia in case someone changes type of segment length */
630 || ((sizeof segh.length > 1) && segh.length > AS_SEGMENT_MAX))
631 {
632 if (head)
633 assegment_free_all (head);
634 return NULL;
635 }
636
637 /* now its safe to trust lengths */
638 seg = assegment_new (segh.type, segh.length);
639
640 if (head)
641 prev->next = seg;
642 else /* it's the first segment */
643 head = prev = seg;
644
645 for (i = 0; i < segh.length; i++)
646 seg->as[i] = stream_getw (s);
647
648 bytes += ASSEGMENT_SIZE(segh.length);
649
650 prev = seg;
651 }
652
653 return assegment_normalise (head);
654}
655
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
1158 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1159 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001160 return 0;
paulfe69a502005-09-10 16:55:02 +00001161
1162 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001163 return 1;
1164
1165 return 0;
1166}
1167
paulfe69a502005-09-10 16:55:02 +00001168/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1169 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001170struct aspath *
1171aspath_delete_confed_seq (struct aspath *aspath)
1172{
paulfe69a502005-09-10 16:55:02 +00001173 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001174
paulfe69a502005-09-10 16:55:02 +00001175 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001176 return aspath;
1177
paulfe69a502005-09-10 16:55:02 +00001178 seg = aspath->segments;
1179
1180 /* "if the first path segment of the AS_PATH is
1181 * of type AS_CONFED_SEQUENCE,"
1182 */
1183 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1184 return aspath;
paul718e3742002-12-13 20:15:29 +00001185
paulfe69a502005-09-10 16:55:02 +00001186 /* "... that segment and any immediately following segments
1187 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1188 * from the AS_PATH attribute,"
1189 */
1190 while (seg &&
1191 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001192 {
paulfe69a502005-09-10 16:55:02 +00001193 aspath->segments = seg->next;
1194 assegment_free (seg);
1195 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001196 }
paulfe69a502005-09-10 16:55:02 +00001197 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001198 return aspath;
1199}
1200
1201/* Add new AS number to the leftmost part of the aspath as
1202 AS_CONFED_SEQUENCE. */
1203struct aspath*
1204aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1205{
1206 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1207}
1208
1209/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001210static void
paul718e3742002-12-13 20:15:29 +00001211aspath_as_add (struct aspath *as, as_t asno)
1212{
paulfe69a502005-09-10 16:55:02 +00001213 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001214
1215 /* Last segment search procedure. */
paulfe69a502005-09-10 16:55:02 +00001216 while (seg && seg->next)
1217 seg = seg->next;
1218
1219 if (!seg)
1220 return;
1221
1222 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001223}
1224
1225/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001226static void
paul718e3742002-12-13 20:15:29 +00001227aspath_segment_add (struct aspath *as, int type)
1228{
paulfe69a502005-09-10 16:55:02 +00001229 struct assegment *seg = as->segments;
1230 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001231
paulfe69a502005-09-10 16:55:02 +00001232 while (seg && seg->next)
1233 seg = seg->next;
1234
1235 if (seg == NULL)
1236 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001237 else
paulfe69a502005-09-10 16:55:02 +00001238 seg->next = new;
paul718e3742002-12-13 20:15:29 +00001239}
1240
1241struct aspath *
paul94f2b392005-06-28 12:44:16 +00001242aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001243{
1244 return aspath_parse (NULL, 0);
1245}
1246
1247struct aspath *
paul94f2b392005-06-28 12:44:16 +00001248aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001249{
1250 struct aspath *aspath;
1251
1252 aspath = aspath_new ();
1253 aspath->str = aspath_make_str_count (aspath);
1254 return aspath;
1255}
1256
1257unsigned long
paulfe69a502005-09-10 16:55:02 +00001258aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001259{
1260 return ashash->count;
1261}
1262
1263/*
1264 Theoretically, one as path can have:
1265
1266 One BGP packet size should be less than 4096.
1267 One BGP attribute size should be less than 4096 - BGP header size.
1268 One BGP aspath size should be less than 4096 - BGP header size -
1269 BGP mandantry attribute size.
1270*/
1271
1272/* AS path string lexical token enum. */
1273enum as_token
1274{
1275 as_token_asval,
1276 as_token_set_start,
1277 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001278 as_token_confed_seq_start,
1279 as_token_confed_seq_end,
1280 as_token_confed_set_start,
1281 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001282 as_token_unknown
1283};
1284
1285/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001286static const char *
paulfd79ac92004-10-13 05:06:08 +00001287aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
paul718e3742002-12-13 20:15:29 +00001288{
paulfd79ac92004-10-13 05:06:08 +00001289 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001290
paulfe69a502005-09-10 16:55:02 +00001291 /* Skip seperators (space for sequences, ',' for sets). */
1292 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001293 p++;
1294
1295 /* Check the end of the string and type specify characters
1296 (e.g. {}()). */
1297 switch (*p)
1298 {
1299 case '\0':
1300 return NULL;
1301 break;
1302 case '{':
1303 *token = as_token_set_start;
1304 p++;
1305 return p;
1306 break;
1307 case '}':
1308 *token = as_token_set_end;
1309 p++;
1310 return p;
1311 break;
1312 case '(':
paulfe69a502005-09-10 16:55:02 +00001313 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001314 p++;
1315 return p;
1316 break;
1317 case ')':
paulfe69a502005-09-10 16:55:02 +00001318 *token = as_token_confed_seq_end;
1319 p++;
1320 return p;
1321 break;
1322 case '[':
1323 *token = as_token_confed_set_start;
1324 p++;
1325 return p;
1326 break;
1327 case ']':
1328 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001329 p++;
1330 return p;
1331 break;
1332 }
1333
1334 /* Check actual AS value. */
1335 if (isdigit ((int) *p))
1336 {
1337 u_short asval;
1338
1339 *token = as_token_asval;
1340 asval = (*p - '0');
1341 p++;
1342 while (isdigit ((int) *p))
1343 {
1344 asval *= 10;
1345 asval += (*p - '0');
1346 p++;
1347 }
1348 *asno = asval;
1349 return p;
1350 }
1351
1352 /* There is no match then return unknown token. */
1353 *token = as_token_unknown;
1354 return p++;
1355}
1356
1357struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001358aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001359{
1360 enum as_token token;
1361 u_short as_type;
1362 u_short asno;
1363 struct aspath *aspath;
1364 int needtype;
1365
1366 aspath = aspath_new ();
1367
1368 /* We start default type as AS_SEQUENCE. */
1369 as_type = AS_SEQUENCE;
1370 needtype = 1;
1371
1372 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1373 {
1374 switch (token)
1375 {
1376 case as_token_asval:
1377 if (needtype)
1378 {
1379 aspath_segment_add (aspath, as_type);
1380 needtype = 0;
1381 }
1382 aspath_as_add (aspath, asno);
1383 break;
1384 case as_token_set_start:
1385 as_type = AS_SET;
1386 aspath_segment_add (aspath, as_type);
1387 needtype = 0;
1388 break;
1389 case as_token_set_end:
1390 as_type = AS_SEQUENCE;
1391 needtype = 1;
1392 break;
paulfe69a502005-09-10 16:55:02 +00001393 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001394 as_type = AS_CONFED_SEQUENCE;
1395 aspath_segment_add (aspath, as_type);
1396 needtype = 0;
1397 break;
paulfe69a502005-09-10 16:55:02 +00001398 case as_token_confed_seq_end:
1399 as_type = AS_SEQUENCE;
1400 needtype = 1;
1401 break;
1402 case as_token_confed_set_start:
1403 as_type = AS_CONFED_SET;
1404 aspath_segment_add (aspath, as_type);
1405 needtype = 0;
1406 break;
1407 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001408 as_type = AS_SEQUENCE;
1409 needtype = 1;
1410 break;
1411 case as_token_unknown:
1412 default:
paulfe69a502005-09-10 16:55:02 +00001413 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001414 return NULL;
1415 break;
1416 }
1417 }
1418
1419 aspath->str = aspath_make_str_count (aspath);
1420
1421 return aspath;
1422}
1423
1424/* Make hash value by raw aspath data. */
1425unsigned int
1426aspath_key_make (struct aspath *aspath)
1427{
1428 unsigned int key = 0;
paulfe69a502005-09-10 16:55:02 +00001429 unsigned int i;
1430 struct assegment *seg = aspath->segments;
1431 struct assegment *prev = NULL;
paul718e3742002-12-13 20:15:29 +00001432
paulfe69a502005-09-10 16:55:02 +00001433 while (seg)
paul718e3742002-12-13 20:15:29 +00001434 {
paulfe69a502005-09-10 16:55:02 +00001435 /* segment types should be part of the hash
1436 * otherwise seq(1) and set(1) will hash to same value
1437 */
1438 if (!(prev && seg->type == AS_SEQUENCE && seg->type == prev->type))
1439 key += seg->type;
1440
1441 for (i = 0; i < seg->length; i++)
1442 key += seg->as[i];
1443
1444 prev = seg;
1445 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001446 }
1447
1448 return key;
1449}
1450
1451/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001452static int
paulfe69a502005-09-10 16:55:02 +00001453aspath_cmp (void *arg1, void *arg2)
paul718e3742002-12-13 20:15:29 +00001454{
paulfe69a502005-09-10 16:55:02 +00001455 struct assegment *seg1 = ((struct aspath *)arg1)->segments;
1456 struct assegment *seg2 = ((struct aspath *)arg2)->segments;
1457
1458 while (seg1 || seg2)
1459 {
1460 int i;
1461 if ((!seg1 && seg2) || (seg1 && !seg2))
1462 return 0;
1463 if (seg1->type != seg2->type)
1464 return 0;
1465 if (seg1->length != seg2->length)
1466 return 0;
1467 for (i = 0; i < seg1->length; i++)
1468 if (seg1->as[i] != seg2->as[i])
1469 return 0;
1470 seg1 = seg1->next;
1471 seg2 = seg2->next;
1472 }
1473 return 1;
paul718e3742002-12-13 20:15:29 +00001474}
1475
1476/* AS path hash initialize. */
1477void
paul94f2b392005-06-28 12:44:16 +00001478aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001479{
1480 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1481}
1482
1483/* return and as path value */
1484const char *
1485aspath_print (struct aspath *as)
1486{
paulfe69a502005-09-10 16:55:02 +00001487 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001488}
1489
1490/* Printing functions */
1491void
1492aspath_print_vty (struct vty *vty, struct aspath *as)
1493{
1494 vty_out (vty, "%s", as->str);
1495}
1496
paul94f2b392005-06-28 12:44:16 +00001497static void
paul718e3742002-12-13 20:15:29 +00001498aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1499{
1500 struct aspath *as;
1501
1502 as = (struct aspath *) backet->data;
1503
paulefa9f832002-12-13 21:47:59 +00001504 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001505 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1506}
1507
1508/* Print all aspath and hash information. This function is used from
1509 `show ip bgp paths' command. */
1510void
1511aspath_print_all_vty (struct vty *vty)
1512{
1513 hash_iterate (ashash,
1514 (void (*) (struct hash_backet *, void *))
1515 aspath_show_all_iterator,
1516 vty);
1517}