blob: 9fce6e3144c87f8c13f56e72de20e325580f1f6e [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;
paul8fdc32a2006-01-16 12:01:29 +000081
82/* Stream for SNMP. See aspath_snmp_pathseg */
83static struct stream *snmp_stream;
paul718e3742002-12-13 20:15:29 +000084
paulfe69a502005-09-10 16:55:02 +000085static inline as_t *
86assegment_data_new (int num)
87{
88 return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num)));
89}
90
91static inline void
92assegment_data_free (as_t *asdata)
93{
94 XFREE (MTYPE_AS_SEG_DATA,asdata);
95}
96
97/* Get a new segment. Note that 0 is an allowed length,
98 * and will result in a segment with no allocated data segment.
99 * the caller should immediately assign data to the segment, as the segment
100 * otherwise is not generally valid
101 */
102static struct assegment *
103assegment_new (u_char type, u_short length)
104{
105 struct assegment *new;
106
107 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
108
109 if (length)
110 new->as = assegment_data_new (length);
111
112 new->length = length;
113 new->type = type;
114
115 return new;
116}
117
118static void
119assegment_free (struct assegment *seg)
120{
121 if (!seg)
122 return;
123
124 if (seg->as)
125 XFREE (MTYPE_AS_SEG_DATA, seg->as);
126 memset (seg, 0xfe, sizeof(struct assegment));
127 XFREE (MTYPE_AS_SEG, seg);
128
129 return;
130}
131
132/* free entire chain of segments */
133static void
134assegment_free_all (struct assegment *seg)
135{
136 struct assegment *prev;
137
138 while (seg)
139 {
140 prev = seg;
141 seg = seg->next;
142 assegment_free (prev);
143 }
144}
145
146/* Duplicate just the given assegment and its data */
147static struct assegment *
148assegment_dup (struct assegment *seg)
149{
150 struct assegment *new;
151
152 new = assegment_new (seg->type, seg->length);
153 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length) );
154
155 return new;
156}
157
158/* Duplicate entire chain of assegments, return the head */
159static struct assegment *
160assegment_dup_all (struct assegment *seg)
161{
162 struct assegment *new = NULL;
163 struct assegment *head = NULL;
164
165 while (seg)
166 {
167 if (head)
168 {
169 new->next = assegment_dup (seg);
170 new = new->next;
171 }
172 else
173 head = new = assegment_dup (seg);
174
175 seg = seg->next;
176 }
177 return head;
178}
179
180/* prepend the as number to given segment, given num of times */
181static struct assegment *
182assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
183{
184 as_t *newas;
185
186 if (!num)
187 return seg;
188
189 if (num >= AS_SEGMENT_MAX)
190 return seg; /* we don't do huge prepends */
191
192 newas = assegment_data_new (seg->length + num);
193
194 if (newas)
195 {
196 int i;
197 for (i = 0; i < num; i++)
198 newas[i] = asnum;
199
200 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length));
201 XFREE (MTYPE_AS_SEG_DATA, seg->as);
202 seg->as = newas;
203 seg->length += num;
204 return seg;
205 }
206
207 assegment_free_all (seg);
208 return NULL;
209}
210
211/* append given array of as numbers to the segment */
212static struct assegment *
213assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
214{
paul02335422006-01-16 11:13:27 +0000215 as_t *newas;
216
217 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
paulfe69a502005-09-10 16:55:02 +0000218 ASSEGMENT_DATA_SIZE (seg->length + num));
219
paul02335422006-01-16 11:13:27 +0000220 if (newas)
paulfe69a502005-09-10 16:55:02 +0000221 {
paul02335422006-01-16 11:13:27 +0000222 seg->as = newas;
paulfe69a502005-09-10 16:55:02 +0000223 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num));
224 seg->length += num;
225 return seg;
226 }
227
228 assegment_free_all (seg);
229 return NULL;
230}
231
232static int
233int_cmp (const void *p1, const void *p2)
234{
235 const as_t *as1 = p1;
236 const as_t *as2 = p2;
237
238 return (*as1 == *as2)
239 ? 0 : ( (*as1 > *as2) ? 1 : -1);
240}
241
242/* normalise the segment.
243 * In particular, merge runs of AS_SEQUENCEs into one segment
244 * Internally, we do not care about the wire segment length limit, and
245 * we want each distinct AS_PATHs to have the exact same internal
246 * representation - eg, so that our hashing actually works..
247 */
248static struct assegment *
249assegment_normalise (struct assegment *head)
250{
251 struct assegment *seg = head, *pin;
252 struct assegment *tmp;
253
254 if (!head)
255 return head;
256
257 while (seg)
258 {
259 pin = seg;
260
261 /* Sort values SET segments, for determinism in paths to aid
262 * creation of hash values / path comparisons
263 * and because it helps other lesser implementations ;)
264 */
265 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
266 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
267
268 /* read ahead from the current, pinned segment while the segments
269 * are packable/mergeable. Append all following packable segments
270 * to the segment we have pinned and remove these appended
271 * segments.
272 */
273 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
274 {
275 tmp = pin->next;
276 seg = pin->next;
277
278 /* append the next sequence to the pinned sequence */
279 pin = assegment_append_asns (pin, seg->as, seg->length);
280
281 /* bypass the next sequence */
282 pin->next = seg->next;
283
284 /* get rid of the now referenceless segment */
285 assegment_free (tmp);
286
287 }
288
289 seg = pin->next;
290 }
291 return head;
292}
293
paul718e3742002-12-13 20:15:29 +0000294static struct aspath *
paulfe69a502005-09-10 16:55:02 +0000295aspath_new (void)
paul718e3742002-12-13 20:15:29 +0000296{
297 struct aspath *aspath;
298
299 aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
300 memset (aspath, 0, sizeof (struct aspath));
301 return aspath;
302}
303
304/* Free AS path structure. */
305void
306aspath_free (struct aspath *aspath)
307{
308 if (!aspath)
309 return;
paulfe69a502005-09-10 16:55:02 +0000310 if (aspath->segments)
311 assegment_free_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000312 if (aspath->str)
313 XFREE (MTYPE_AS_STR, aspath->str);
314 XFREE (MTYPE_AS_PATH, aspath);
315}
316
317/* Unintern aspath from AS path bucket. */
318void
319aspath_unintern (struct aspath *aspath)
320{
321 struct aspath *ret;
322
323 if (aspath->refcnt)
324 aspath->refcnt--;
325
326 if (aspath->refcnt == 0)
327 {
328 /* This aspath must exist in aspath hash table. */
329 ret = hash_release (ashash, aspath);
330 assert (ret != NULL);
331 aspath_free (aspath);
332 }
333}
334
335/* Return the start or end delimiters for a particular Segment type */
336#define AS_SEG_START 0
337#define AS_SEG_END 1
338static char
339aspath_delimiter_char (u_char type, u_char which)
340{
341 int i;
342 struct
343 {
344 int type;
345 char start;
346 char end;
347 } aspath_delim_char [] =
348 {
349 { AS_SET, '{', '}' },
paul718e3742002-12-13 20:15:29 +0000350 { AS_CONFED_SET, '[', ']' },
351 { AS_CONFED_SEQUENCE, '(', ')' },
352 { 0 }
353 };
354
355 for (i = 0; aspath_delim_char[i].type != 0; i++)
356 {
357 if (aspath_delim_char[i].type == type)
358 {
359 if (which == AS_SEG_START)
360 return aspath_delim_char[i].start;
361 else if (which == AS_SEG_END)
362 return aspath_delim_char[i].end;
363 }
364 }
365 return ' ';
366}
367
paulfe69a502005-09-10 16:55:02 +0000368/* countup asns from this segment and index onward */
369static int
370assegment_count_asns (struct assegment *seg, int from)
371{
372 int count = 0;
373 while (seg)
374 {
375 if (!from)
376 count += seg->length;
377 else
378 {
379 count += (seg->length - from);
380 from = 0;
381 }
382 seg = seg->next;
383 }
384 return count;
385}
386
387unsigned int
388aspath_count_confeds (struct aspath *aspath)
389{
390 int count = 0;
391 struct assegment *seg = aspath->segments;
392
393 while (seg)
394 {
395 if (seg->type == AS_CONFED_SEQUENCE)
396 count += seg->length;
397 else if (seg->type == AS_CONFED_SET)
398 count++;
399
400 seg = seg->next;
401 }
402 return count;
403}
404
405unsigned int
406aspath_count_hops (struct aspath *aspath)
407{
408 int count = 0;
409 struct assegment *seg = aspath->segments;
410
411 while (seg)
412 {
413 if (seg->type == AS_SEQUENCE)
414 count += seg->length;
415 else if (seg->type == AS_SET)
416 count++;
417
418 seg = seg->next;
419 }
420 return count;
421}
422
423unsigned int
424aspath_size (struct aspath *aspath)
425{
426 int size = 0;
427 struct assegment *seg = aspath->segments;
428
429 while (seg)
430 {
431 size += ASSEGMENT_SIZE(seg->length);
432 seg = seg->next;
433 }
434 return size;
435}
436
paul718e3742002-12-13 20:15:29 +0000437/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000438static char *
paul718e3742002-12-13 20:15:29 +0000439aspath_make_str_count (struct aspath *as)
440{
paulfe69a502005-09-10 16:55:02 +0000441 struct assegment *seg;
442 int str_size;
443 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000444 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000445
446 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000447 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000448 {
449 str_buf = XMALLOC (MTYPE_AS_STR, 1);
450 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000451 return str_buf;
452 }
paulfe69a502005-09-10 16:55:02 +0000453
454 seg = as->segments;
455
456 /* ASN takes 5 chars at least, plus seperator, see below.
457 * If there is one differing segment type, we need an additional
458 * 2 chars for segment delimiters, and the final '\0'.
459 * Hopefully this is large enough to avoid hitting the realloc
460 * code below for most common sequences.
461 */
462#define ASN_STR_LEN (5 + 1)
463 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
464 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000465 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000466
paulfe69a502005-09-10 16:55:02 +0000467 while (seg)
paul718e3742002-12-13 20:15:29 +0000468 {
469 int i;
paulfe69a502005-09-10 16:55:02 +0000470 char seperator;
paul718e3742002-12-13 20:15:29 +0000471
paulfe69a502005-09-10 16:55:02 +0000472 /* Check AS type validity. Set seperator for segment */
473 switch (seg->type)
474 {
475 case AS_SET:
476 case AS_CONFED_SET:
477 seperator = ',';
478 break;
479 case AS_SEQUENCE:
480 case AS_CONFED_SEQUENCE:
481 seperator = ' ';
482 break;
483 default:
484 XFREE (MTYPE_AS_STR, str_buf);
485 return NULL;
486 }
487
488 /* We might need to increase str_buf, particularly if path has
489 * differing segments types, our initial guesstimate above will
490 * have been wrong. need 5 chars for ASN, a seperator each and
491 * potentially two segment delimiters, plus a space between each
492 * segment and trailing zero.
493 */
494#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
495 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
496 {
497 str_size = len + SEGMENT_STR_LEN(seg);
498 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
499 }
500#undef ASN_STR_LEN
501#undef SEGMENT_STR_LEN
502
503 if (seg->type != AS_SEQUENCE)
504 len += snprintf (str_buf + len, str_size - len,
505 "%c",
506 aspath_delimiter_char (seg->type, AS_SEG_START));
507
508 /* write out the ASNs, with their seperators, bar the last one*/
509 for (i = 0; i < seg->length; i++)
510 {
511 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
512
513 if (i < (seg->length - 1))
514 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
515 }
516
517 if (seg->type != AS_SEQUENCE)
518 len += snprintf (str_buf + len, str_size - len, "%c",
519 aspath_delimiter_char (seg->type, AS_SEG_END));
520 if (seg->next)
521 len += snprintf (str_buf + len, str_size - len, " ");
522
523 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000524 }
paulfe69a502005-09-10 16:55:02 +0000525
526 assert (len < str_size);
527
528 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000529
530 return str_buf;
531}
532
paulfe69a502005-09-10 16:55:02 +0000533static void
534aspath_str_update (struct aspath *as)
535{
536 if (as->str)
537 XFREE (MTYPE_AS_STR, as->str);
538 as->str = aspath_make_str_count (as);
539}
540
paul718e3742002-12-13 20:15:29 +0000541/* Intern allocated AS path. */
542struct aspath *
543aspath_intern (struct aspath *aspath)
544{
545 struct aspath *find;
546
547 /* Assert this AS path structure is not interned. */
548 assert (aspath->refcnt == 0);
549
550 /* Check AS path hash. */
551 find = hash_get (ashash, aspath, hash_alloc_intern);
552
553 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000554 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000555
556 find->refcnt++;
557
558 if (! find->str)
559 find->str = aspath_make_str_count (find);
560
561 return find;
562}
563
564/* Duplicate aspath structure. Created same aspath structure but
565 reference count and AS path string is cleared. */
566struct aspath *
567aspath_dup (struct aspath *aspath)
568{
569 struct aspath *new;
570
paulfe69a502005-09-10 16:55:02 +0000571 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000572
paulfe69a502005-09-10 16:55:02 +0000573 if (aspath->segments)
574 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000575 else
paulfe69a502005-09-10 16:55:02 +0000576 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000577
paulfe69a502005-09-10 16:55:02 +0000578 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000579
580 return new;
581}
582
paul94f2b392005-06-28 12:44:16 +0000583static void *
paulfe69a502005-09-10 16:55:02 +0000584aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000585{
586 struct aspath *aspath;
587
588 /* New aspath strucutre is needed. */
paulfe69a502005-09-10 16:55:02 +0000589 aspath = aspath_dup (arg);
590
paul718e3742002-12-13 20:15:29 +0000591 /* Malformed AS path value. */
592 if (! aspath->str)
593 {
594 aspath_free (aspath);
595 return NULL;
596 }
597
598 return aspath;
599}
600
paulfe69a502005-09-10 16:55:02 +0000601/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000602static struct assegment *
paulfe69a502005-09-10 16:55:02 +0000603assegments_parse (struct stream *s, size_t length)
604{
605 struct assegment_header segh;
606 struct assegment *seg, *prev = NULL, *head = NULL;
607 size_t bytes = 0;
608
609 /* empty aspath (ie iBGP or somesuch) */
610 if (length == 0)
611 return NULL;
612
613 /* basic checks */
614 if ( (STREAM_READABLE(s) < length)
615 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
616 || (length % AS_VALUE_SIZE))
617 return NULL;
618
619 while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
620 && (bytes < length))
621 {
622 int i;
623
624 /* softly softly, get the header first on its own */
625 segh.type = stream_getc (s);
626 segh.length = stream_getc (s);
627
628 /* check it.. */
629 if ( ((bytes + ASSEGMENT_SIZE(segh.length)) > length)
630 /* 1771bis 4.3b: seg length contains one or more */
631 || (segh.length == 0)
632 /* Paranoia in case someone changes type of segment length */
633 || ((sizeof segh.length > 1) && segh.length > AS_SEGMENT_MAX))
634 {
635 if (head)
636 assegment_free_all (head);
637 return NULL;
638 }
639
640 /* now its safe to trust lengths */
641 seg = assegment_new (segh.type, segh.length);
642
643 if (head)
644 prev->next = seg;
645 else /* it's the first segment */
646 head = prev = seg;
647
648 for (i = 0; i < segh.length; i++)
649 seg->as[i] = stream_getw (s);
650
651 bytes += ASSEGMENT_SIZE(segh.length);
652
653 prev = seg;
654 }
655
656 return assegment_normalise (head);
657}
658
paul718e3742002-12-13 20:15:29 +0000659/* AS path parse function. pnt is a pointer to byte stream and length
660 is length of byte stream. If there is same AS path in the the AS
661 path hash then return it else make new AS path structure. */
662struct aspath *
paulfe69a502005-09-10 16:55:02 +0000663aspath_parse (struct stream *s, size_t length)
paul718e3742002-12-13 20:15:29 +0000664{
665 struct aspath as;
666 struct aspath *find;
667
668 /* If length is odd it's malformed AS path. */
paulfe69a502005-09-10 16:55:02 +0000669 if (length % AS_VALUE_SIZE)
paul718e3742002-12-13 20:15:29 +0000670 return NULL;
671
paulfe69a502005-09-10 16:55:02 +0000672 as.segments = assegments_parse (s, length);
673
paul718e3742002-12-13 20:15:29 +0000674 /* If already same aspath exist then return it. */
675 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000676
677 /* aspath_hash_alloc dupes segments too. that probably could be
678 * optimised out.
679 */
680 assegment_free_all (as.segments);
681
paul718e3742002-12-13 20:15:29 +0000682 if (! find)
683 return NULL;
684 find->refcnt++;
685
686 return find;
687}
688
paulfe69a502005-09-10 16:55:02 +0000689static inline void
690assegment_data_put (struct stream *s, as_t *as, int num)
paul718e3742002-12-13 20:15:29 +0000691{
paulfe69a502005-09-10 16:55:02 +0000692 int i;
693 assert (num <= AS_SEGMENT_MAX);
694
695 for (i = 0; i < num; i++)
696 stream_putw (s, as[i]);
paul718e3742002-12-13 20:15:29 +0000697}
698
paulfe69a502005-09-10 16:55:02 +0000699static inline size_t
700assegment_header_put (struct stream *s, u_char type, int length)
701{
702 size_t lenp;
703 assert (length <= AS_SEGMENT_MAX);
704 stream_putc (s, type);
705 lenp = stream_get_endp (s);
706 stream_putc (s, length);
707 return lenp;
708}
709
710/* write aspath data to stream */
711void
712aspath_put (struct stream *s, struct aspath *as)
713{
714 struct assegment *seg = as->segments;
715
716 if (!seg || seg->length == 0)
717 return;
718
719 if (seg)
720 {
721 while (seg && (ASSEGMENT_LEN (seg) <= STREAM_WRITEABLE(s)))
722 {
723 int written = 0;
724 size_t lenp;
725
726 /* Overlength segments have to be split up */
727 while ( (seg->length - written) > AS_SEGMENT_MAX)
728 {
729 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
730 assegment_data_put (s, seg->as, AS_SEGMENT_MAX);
731 written += AS_SEGMENT_MAX;
732 }
733
734 /* write the final segment, probably is also the first */
735 lenp = assegment_header_put (s, seg->type, seg->length - written);
736 assegment_data_put (s, (seg->as + written), seg->length - written);
737
738 /* Sequence-type segments can be 'packed' together
739 * Case of a segment which was overlength and split up
740 * will be missed here, but that doesn't matter.
741 */
742 if (seg->next && ASSEGMENTS_PACKABLE (seg, seg->next))
743 {
744 /* NB: We should never normally get here given we
745 * normalise aspath data when parse them. However, better
746 * safe than sorry. We potentially could call
747 * assegment_normalise here instead, but it's cheaper and
748 * easier to do it on the fly here rather than go through
749 * the segment list twice every time we write out
750 * aspath's.
751 */
752
753 /* Next segment's data can fit in this one */
754 assegment_data_put (s, seg->next->as, seg->next->length);
755
756 /* update the length of the segment header */
757 stream_putc_at (s, lenp,
758 seg->length - written + seg->next->length);
759 seg = seg->next->next; /* skip to past next */
760 }
761 else
762 seg = seg->next;
763 }
764 }
765}
766
767/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
768 * We have no way to manage the storage, so we use a static stream
769 * wrapper around aspath_put.
770 */
771u_char *
772aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
773{
774#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000775
776 if (!snmp_stream)
777 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000778 else
paul8fdc32a2006-01-16 12:01:29 +0000779 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000780
781 if (!as)
782 {
783 *varlen = 0;
784 return NULL;
785 }
paul8fdc32a2006-01-16 12:01:29 +0000786 aspath_put (snmp_stream, as);
paulfe69a502005-09-10 16:55:02 +0000787
paul8fdc32a2006-01-16 12:01:29 +0000788 *varlen = stream_get_endp (snmp_stream);
789 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000790}
791
792#define min(A,B) ((A) < (B) ? (A) : (B))
793
paul94f2b392005-06-28 12:44:16 +0000794static struct assegment *
paul718e3742002-12-13 20:15:29 +0000795aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
796 as_t as)
797{
798 int i;
799
800 /* If this is first AS set member, create new as-set segment. */
801 if (asset == NULL)
802 {
paulfe69a502005-09-10 16:55:02 +0000803 asset = assegment_new (AS_SET, 1);
804 if (! aspath->segments)
805 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000806 else
paulfe69a502005-09-10 16:55:02 +0000807 {
808 struct assegment *seg = aspath->segments;
809 while (seg->next)
810 seg = seg->next;
811 seg->next = asset;
812 }
paul718e3742002-12-13 20:15:29 +0000813 asset->type = AS_SET;
814 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000815 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000816 }
817 else
818 {
paul718e3742002-12-13 20:15:29 +0000819 /* Check this AS value already exists or not. */
820 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000821 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000822 return asset;
paulfe69a502005-09-10 16:55:02 +0000823
paul718e3742002-12-13 20:15:29 +0000824 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000825 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
826 asset->length * AS_VALUE_SIZE);
827 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000828 }
paulfe69a502005-09-10 16:55:02 +0000829
paul718e3742002-12-13 20:15:29 +0000830
831 return asset;
832}
833
834/* Modify as1 using as2 for aggregation. */
835struct aspath *
836aspath_aggregate (struct aspath *as1, struct aspath *as2)
837{
838 int i;
839 int minlen;
840 int match;
paulfe69a502005-09-10 16:55:02 +0000841 int from;
842 struct assegment *seg1 = as1->segments;
843 struct assegment *seg2 = as2->segments;
paul718e3742002-12-13 20:15:29 +0000844 struct aspath *aspath;
845 struct assegment *asset;
846
847 match = 0;
848 minlen = 0;
849 aspath = NULL;
850 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000851
852 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000853 while (seg1 && seg2)
paul718e3742002-12-13 20:15:29 +0000854 {
855 /* Check segment type. */
856 if (seg1->type != seg2->type)
857 break;
858
859 /* Minimum segment length. */
860 minlen = min (seg1->length, seg2->length);
861
862 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +0000863 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +0000864 break;
865
866 if (match)
867 {
868 if (! aspath)
paulfe69a502005-09-10 16:55:02 +0000869 aspath = aspath_new ();
870 aspath->segments = assegment_new (seg1->type, 0);
871 aspath->segments = assegment_append_asns (aspath->segments,
872 seg1->as, match);
paul718e3742002-12-13 20:15:29 +0000873 }
874
875 if (match != minlen || match != seg1->length
876 || seg1->length != seg2->length)
877 break;
paulfe69a502005-09-10 16:55:02 +0000878
879 seg1 = seg1->next;
880 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +0000881 }
882
883 if (! aspath)
884 aspath = aspath_new();
885
886 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +0000887 from = match;
888 while (seg1)
paul718e3742002-12-13 20:15:29 +0000889 {
paulfe69a502005-09-10 16:55:02 +0000890 for (i = from; i < seg1->length; i++)
891 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
892
893 from = 0;
894 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +0000895 }
896
paulfe69a502005-09-10 16:55:02 +0000897 from = match;
898 while (seg2)
paul718e3742002-12-13 20:15:29 +0000899 {
paulfe69a502005-09-10 16:55:02 +0000900 for (i = from; i < seg2->length; i++)
901 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +0000902
paulfe69a502005-09-10 16:55:02 +0000903 from = 0;
904 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +0000905 }
paulfe69a502005-09-10 16:55:02 +0000906
907 assegment_normalise (aspath->segments);
908 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +0000909 return aspath;
910}
911
912/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
913 attribute, check the leftmost AS number in the AS_PATH attribute is
914 or not the peer's AS number. */
915int
916aspath_firstas_check (struct aspath *aspath, as_t asno)
917{
paulfe69a502005-09-10 16:55:02 +0000918 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +0000919 return 0;
paulfe69a502005-09-10 16:55:02 +0000920
921 if (aspath->segments
922 && (aspath->segments->type == AS_SEQUENCE)
923 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +0000924 return 1;
925
926 return 0;
927}
928
929/* AS path loop check. If aspath contains asno then return 1. */
930int
931aspath_loop_check (struct aspath *aspath, as_t asno)
932{
paulfe69a502005-09-10 16:55:02 +0000933 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +0000934 int count = 0;
935
paulfe69a502005-09-10 16:55:02 +0000936 if ( (aspath == NULL) || (aspath->segments) )
paul718e3742002-12-13 20:15:29 +0000937 return 0;
paulfe69a502005-09-10 16:55:02 +0000938
939 seg = aspath->segments;
940
941 while (seg)
paul718e3742002-12-13 20:15:29 +0000942 {
943 int i;
paul718e3742002-12-13 20:15:29 +0000944
paulfe69a502005-09-10 16:55:02 +0000945 for (i = 0; i < seg->length; i++)
946 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +0000947 count++;
paulfe69a502005-09-10 16:55:02 +0000948
949 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000950 }
951 return count;
952}
953
954/* When all of AS path is private AS return 1. */
955int
956aspath_private_as_check (struct aspath *aspath)
957{
paulfe69a502005-09-10 16:55:02 +0000958 struct assegment *seg;
959
960 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +0000961 return 0;
paulfe69a502005-09-10 16:55:02 +0000962
963 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +0000964
paulfe69a502005-09-10 16:55:02 +0000965 while (seg)
paul718e3742002-12-13 20:15:29 +0000966 {
967 int i;
paul718e3742002-12-13 20:15:29 +0000968
paulfe69a502005-09-10 16:55:02 +0000969 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +0000970 {
paulfe69a502005-09-10 16:55:02 +0000971 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
972 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +0000973 return 0;
974 }
paulfe69a502005-09-10 16:55:02 +0000975 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000976 }
977 return 1;
978}
979
980/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +0000981static struct aspath *
paul718e3742002-12-13 20:15:29 +0000982aspath_merge (struct aspath *as1, struct aspath *as2)
983{
paulfe69a502005-09-10 16:55:02 +0000984 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +0000985
986 if (! as1 || ! as2)
987 return NULL;
988
paulfe69a502005-09-10 16:55:02 +0000989 last = new = assegment_dup_all (as1->segments);
990
991 /* find the last valid segment */
992 while (last && last->next)
993 last = last->next;
994
995 last->next = as2->segments;
996 as2->segments = new;
997 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +0000998 return as2;
999}
1000
1001/* Prepend as1 to as2. as2 should be uninterned aspath. */
1002struct aspath *
1003aspath_prepend (struct aspath *as1, struct aspath *as2)
1004{
paulfe69a502005-09-10 16:55:02 +00001005 struct assegment *seg1;
1006 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001007
1008 if (! as1 || ! as2)
1009 return NULL;
paulfe69a502005-09-10 16:55:02 +00001010
1011 seg1 = as1->segments;
1012 seg2 = as2->segments;
1013
1014 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001015 if (seg2 == NULL)
1016 {
paulfe69a502005-09-10 16:55:02 +00001017 as2->segments = assegment_dup_all (as1->segments);
1018 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001019 return as2;
1020 }
paulfe69a502005-09-10 16:55:02 +00001021
1022 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001023 if (seg1 == NULL)
1024 return as2;
paulfe69a502005-09-10 16:55:02 +00001025
1026 /* find the tail as1's segment chain. */
1027 while (seg1 && seg1->next)
1028 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001029
1030 /* Compare last segment type of as1 and first segment type of as2. */
1031 if (seg1->type != seg2->type)
1032 return aspath_merge (as1, as2);
1033
1034 if (seg1->type == AS_SEQUENCE)
1035 {
paulfe69a502005-09-10 16:55:02 +00001036 /* We have two chains of segments, as1->segments and seg2,
1037 * and we have to attach them together, merging the attaching
1038 * segments together into one.
1039 *
1040 * 1. dupe as1->segments onto head of as2
1041 * 2. merge seg2's asns onto last segment of this new chain
1042 * 3. attach chain after seg2
1043 */
paul718e3742002-12-13 20:15:29 +00001044
paulfe69a502005-09-10 16:55:02 +00001045 /* dupe as1 onto as2's head */
1046 seg1 = as2->segments = assegment_dup_all (as1->segments);
1047
1048 /* refind the tail of as2, reusing seg1 */
1049 while (seg1 && seg1->next)
1050 seg1 = seg1->next;
1051
1052 /* merge the old head, seg2, into tail, seg1 */
1053 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1054
1055 /* bypass the merged seg2, and attach any chain after it to
1056 * chain descending from as2's head
1057 */
1058 seg1->next = seg2->next;
1059
1060 /* seg2 is now referenceless and useless*/
1061 assegment_free (seg2);
1062
1063 /* we've now prepended as1's segment chain to as2, merging
1064 * the inbetween AS_SEQUENCE of seg2 in the process
1065 */
1066 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001067 return as2;
1068 }
1069 else
1070 {
1071 /* AS_SET merge code is needed at here. */
1072 return aspath_merge (as1, as2);
1073 }
paulfe69a502005-09-10 16:55:02 +00001074 /* XXX: Ermmm, what if as1 has multiple segments?? */
1075
paul718e3742002-12-13 20:15:29 +00001076 /* Not reached */
1077}
1078
1079/* Add specified AS to the leftmost of aspath. */
1080static struct aspath *
1081aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1082{
paulfe69a502005-09-10 16:55:02 +00001083 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001084
1085 /* In case of empty aspath. */
1086 if (assegment == NULL || assegment->length == 0)
1087 {
paulfe69a502005-09-10 16:55:02 +00001088 aspath->segments = assegment_new (type, 1);
1089 aspath->segments->as[0] = asno;
1090
paul718e3742002-12-13 20:15:29 +00001091 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001092 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001093
1094 return aspath;
1095 }
1096
1097 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001098 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1099 else
paul718e3742002-12-13 20:15:29 +00001100 {
paulfe69a502005-09-10 16:55:02 +00001101 /* create new segment
1102 * push it onto head of aspath's segment chain
1103 */
paul718e3742002-12-13 20:15:29 +00001104 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001105
1106 newsegment = assegment_new (type, 1);
1107 newsegment->as[0] = asno;
1108
1109 newsegment->next = assegment;
1110 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001111 }
1112
1113 return aspath;
1114}
1115
1116/* Add specified AS to the leftmost of aspath. */
1117struct aspath *
1118aspath_add_seq (struct aspath *aspath, as_t asno)
1119{
1120 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1121}
1122
1123/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1124 as2's leftmost AS is same return 1. */
1125int
1126aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
1127{
paulfe69a502005-09-10 16:55:02 +00001128 struct assegment *seg1 = NULL;
1129 struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001130
paulfe69a502005-09-10 16:55:02 +00001131 if (!(aspath1 && aspath2))
1132 return 0;
paul718e3742002-12-13 20:15:29 +00001133
paulfe69a502005-09-10 16:55:02 +00001134 seg1 = aspath1->segments;
1135 seg2 = aspath2->segments;
1136
1137 /* find first non-confed segments for each */
1138 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1139 || (seg1->type == AS_CONFED_SET)))
1140 seg1 = seg1->next;
1141
1142 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1143 || (seg2->type == AS_CONFED_SET)))
1144 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001145
1146 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001147 if (!(seg1 && seg2
1148 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001149 return 0;
paulfe69a502005-09-10 16:55:02 +00001150
1151 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001152 return 1;
1153
1154 return 0;
1155}
1156
1157/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1158 as2's leftmost AS is same return 1. (confederation as-path
1159 only). */
1160int
1161aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2)
1162{
paulfe69a502005-09-10 16:55:02 +00001163 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001164 return 0;
paulfe69a502005-09-10 16:55:02 +00001165
paulad727402005-11-23 02:47:02 +00001166 if ( !(aspath1->segments && aspath2->segments) )
1167 return 0;
1168
paulfe69a502005-09-10 16:55:02 +00001169 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1170 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001171 return 0;
paulfe69a502005-09-10 16:55:02 +00001172
1173 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001174 return 1;
1175
1176 return 0;
1177}
1178
paulfe69a502005-09-10 16:55:02 +00001179/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1180 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001181struct aspath *
1182aspath_delete_confed_seq (struct aspath *aspath)
1183{
paulfe69a502005-09-10 16:55:02 +00001184 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001185
paulfe69a502005-09-10 16:55:02 +00001186 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001187 return aspath;
1188
paulfe69a502005-09-10 16:55:02 +00001189 seg = aspath->segments;
1190
1191 /* "if the first path segment of the AS_PATH is
1192 * of type AS_CONFED_SEQUENCE,"
1193 */
1194 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1195 return aspath;
paul718e3742002-12-13 20:15:29 +00001196
paulfe69a502005-09-10 16:55:02 +00001197 /* "... that segment and any immediately following segments
1198 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1199 * from the AS_PATH attribute,"
1200 */
1201 while (seg &&
1202 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001203 {
paulfe69a502005-09-10 16:55:02 +00001204 aspath->segments = seg->next;
1205 assegment_free (seg);
1206 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001207 }
paulfe69a502005-09-10 16:55:02 +00001208 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001209 return aspath;
1210}
1211
1212/* Add new AS number to the leftmost part of the aspath as
1213 AS_CONFED_SEQUENCE. */
1214struct aspath*
1215aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1216{
1217 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1218}
1219
1220/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001221static void
paul718e3742002-12-13 20:15:29 +00001222aspath_as_add (struct aspath *as, as_t asno)
1223{
paulfe69a502005-09-10 16:55:02 +00001224 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001225
1226 /* Last segment search procedure. */
paulfe69a502005-09-10 16:55:02 +00001227 while (seg && seg->next)
1228 seg = seg->next;
1229
1230 if (!seg)
1231 return;
1232
1233 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001234}
1235
1236/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001237static void
paul718e3742002-12-13 20:15:29 +00001238aspath_segment_add (struct aspath *as, int type)
1239{
paulfe69a502005-09-10 16:55:02 +00001240 struct assegment *seg = as->segments;
1241 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001242
paulfe69a502005-09-10 16:55:02 +00001243 while (seg && seg->next)
1244 seg = seg->next;
1245
1246 if (seg == NULL)
1247 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001248 else
paulfe69a502005-09-10 16:55:02 +00001249 seg->next = new;
paul718e3742002-12-13 20:15:29 +00001250}
1251
1252struct aspath *
paul94f2b392005-06-28 12:44:16 +00001253aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001254{
1255 return aspath_parse (NULL, 0);
1256}
1257
1258struct aspath *
paul94f2b392005-06-28 12:44:16 +00001259aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001260{
1261 struct aspath *aspath;
1262
1263 aspath = aspath_new ();
1264 aspath->str = aspath_make_str_count (aspath);
1265 return aspath;
1266}
1267
1268unsigned long
paulfe69a502005-09-10 16:55:02 +00001269aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001270{
1271 return ashash->count;
1272}
1273
1274/*
1275 Theoretically, one as path can have:
1276
1277 One BGP packet size should be less than 4096.
1278 One BGP attribute size should be less than 4096 - BGP header size.
1279 One BGP aspath size should be less than 4096 - BGP header size -
1280 BGP mandantry attribute size.
1281*/
1282
1283/* AS path string lexical token enum. */
1284enum as_token
1285{
1286 as_token_asval,
1287 as_token_set_start,
1288 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001289 as_token_confed_seq_start,
1290 as_token_confed_seq_end,
1291 as_token_confed_set_start,
1292 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001293 as_token_unknown
1294};
1295
1296/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001297static const char *
paulfd79ac92004-10-13 05:06:08 +00001298aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
paul718e3742002-12-13 20:15:29 +00001299{
paulfd79ac92004-10-13 05:06:08 +00001300 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001301
paulfe69a502005-09-10 16:55:02 +00001302 /* Skip seperators (space for sequences, ',' for sets). */
1303 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001304 p++;
1305
1306 /* Check the end of the string and type specify characters
1307 (e.g. {}()). */
1308 switch (*p)
1309 {
1310 case '\0':
1311 return NULL;
paul718e3742002-12-13 20:15:29 +00001312 case '{':
1313 *token = as_token_set_start;
1314 p++;
1315 return p;
paul718e3742002-12-13 20:15:29 +00001316 case '}':
1317 *token = as_token_set_end;
1318 p++;
1319 return p;
paul718e3742002-12-13 20:15:29 +00001320 case '(':
paulfe69a502005-09-10 16:55:02 +00001321 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001322 p++;
1323 return p;
paul718e3742002-12-13 20:15:29 +00001324 case ')':
paulfe69a502005-09-10 16:55:02 +00001325 *token = as_token_confed_seq_end;
1326 p++;
1327 return p;
paulfe69a502005-09-10 16:55:02 +00001328 case '[':
1329 *token = as_token_confed_set_start;
1330 p++;
1331 return p;
paulfe69a502005-09-10 16:55:02 +00001332 case ']':
1333 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001334 p++;
1335 return p;
paul718e3742002-12-13 20:15:29 +00001336 }
1337
1338 /* Check actual AS value. */
1339 if (isdigit ((int) *p))
1340 {
1341 u_short asval;
1342
1343 *token = as_token_asval;
1344 asval = (*p - '0');
1345 p++;
1346 while (isdigit ((int) *p))
1347 {
1348 asval *= 10;
1349 asval += (*p - '0');
1350 p++;
1351 }
1352 *asno = asval;
1353 return p;
1354 }
1355
1356 /* There is no match then return unknown token. */
1357 *token = as_token_unknown;
1358 return p++;
1359}
1360
1361struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001362aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001363{
paul3fff6ff2006-02-05 17:55:35 +00001364 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001365 u_short as_type;
paul3fff6ff2006-02-05 17:55:35 +00001366 u_short asno = NULL;
paul718e3742002-12-13 20:15:29 +00001367 struct aspath *aspath;
1368 int needtype;
1369
1370 aspath = aspath_new ();
1371
1372 /* We start default type as AS_SEQUENCE. */
1373 as_type = AS_SEQUENCE;
1374 needtype = 1;
1375
1376 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1377 {
1378 switch (token)
1379 {
1380 case as_token_asval:
1381 if (needtype)
1382 {
1383 aspath_segment_add (aspath, as_type);
1384 needtype = 0;
1385 }
1386 aspath_as_add (aspath, asno);
1387 break;
1388 case as_token_set_start:
1389 as_type = AS_SET;
1390 aspath_segment_add (aspath, as_type);
1391 needtype = 0;
1392 break;
1393 case as_token_set_end:
1394 as_type = AS_SEQUENCE;
1395 needtype = 1;
1396 break;
paulfe69a502005-09-10 16:55:02 +00001397 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001398 as_type = AS_CONFED_SEQUENCE;
1399 aspath_segment_add (aspath, as_type);
1400 needtype = 0;
1401 break;
paulfe69a502005-09-10 16:55:02 +00001402 case as_token_confed_seq_end:
1403 as_type = AS_SEQUENCE;
1404 needtype = 1;
1405 break;
1406 case as_token_confed_set_start:
1407 as_type = AS_CONFED_SET;
1408 aspath_segment_add (aspath, as_type);
1409 needtype = 0;
1410 break;
1411 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001412 as_type = AS_SEQUENCE;
1413 needtype = 1;
1414 break;
1415 case as_token_unknown:
1416 default:
paulfe69a502005-09-10 16:55:02 +00001417 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001418 return NULL;
paul718e3742002-12-13 20:15:29 +00001419 }
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}
paul8fdc32a2006-01-16 12:01:29 +00001485
1486void
1487aspath_finish (void)
1488{
1489 hash_free (ashash);
1490
1491 if (snmp_stream)
1492 stream_free (snmp_stream);
1493}
paul718e3742002-12-13 20:15:29 +00001494
1495/* return and as path value */
1496const char *
1497aspath_print (struct aspath *as)
1498{
paulfe69a502005-09-10 16:55:02 +00001499 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001500}
1501
1502/* Printing functions */
1503void
1504aspath_print_vty (struct vty *vty, struct aspath *as)
1505{
1506 vty_out (vty, "%s", as->str);
1507}
1508
paul94f2b392005-06-28 12:44:16 +00001509static void
paul718e3742002-12-13 20:15:29 +00001510aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1511{
1512 struct aspath *as;
1513
1514 as = (struct aspath *) backet->data;
1515
paulefa9f832002-12-13 21:47:59 +00001516 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001517 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1518}
1519
1520/* Print all aspath and hash information. This function is used from
1521 `show ip bgp paths' command. */
1522void
1523aspath_print_all_vty (struct vty *vty)
1524{
1525 hash_iterate (ashash,
1526 (void (*) (struct hash_backet *, void *))
1527 aspath_show_all_iterator,
1528 vty);
1529}