blob: b328e38a5b2c324327ab96dd54c1be363ad38570 [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
Paul Jakma2815e612006-09-14 02:56:07 +0000437/* Return highest public ASN in path */
438as_t
439aspath_highest (struct aspath *aspath)
440{
441 struct assegment *seg = aspath->segments;
442 as_t highest = 0;
443 unsigned int i;
444
445 while (seg)
446 {
447 for (i = 0; i < seg->length; i++)
448 if (seg->as[i] > highest
449 && (seg->as[i] < BGP_PRIVATE_AS_MIN
450 || seg->as[i] > BGP_PRIVATE_AS_MAX))
451 highest = seg->as[i];
452 seg = seg->next;
453 }
454 return highest;
455}
456
paul718e3742002-12-13 20:15:29 +0000457/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000458static char *
paul718e3742002-12-13 20:15:29 +0000459aspath_make_str_count (struct aspath *as)
460{
paulfe69a502005-09-10 16:55:02 +0000461 struct assegment *seg;
462 int str_size;
463 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000464 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000465
466 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000467 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000468 {
469 str_buf = XMALLOC (MTYPE_AS_STR, 1);
470 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000471 return str_buf;
472 }
paulfe69a502005-09-10 16:55:02 +0000473
474 seg = as->segments;
475
476 /* ASN takes 5 chars at least, plus seperator, see below.
477 * If there is one differing segment type, we need an additional
478 * 2 chars for segment delimiters, and the final '\0'.
479 * Hopefully this is large enough to avoid hitting the realloc
480 * code below for most common sequences.
481 */
482#define ASN_STR_LEN (5 + 1)
483 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
484 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000485 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000486
paulfe69a502005-09-10 16:55:02 +0000487 while (seg)
paul718e3742002-12-13 20:15:29 +0000488 {
489 int i;
paulfe69a502005-09-10 16:55:02 +0000490 char seperator;
paul718e3742002-12-13 20:15:29 +0000491
paulfe69a502005-09-10 16:55:02 +0000492 /* Check AS type validity. Set seperator for segment */
493 switch (seg->type)
494 {
495 case AS_SET:
496 case AS_CONFED_SET:
497 seperator = ',';
498 break;
499 case AS_SEQUENCE:
500 case AS_CONFED_SEQUENCE:
501 seperator = ' ';
502 break;
503 default:
504 XFREE (MTYPE_AS_STR, str_buf);
505 return NULL;
506 }
507
508 /* We might need to increase str_buf, particularly if path has
509 * differing segments types, our initial guesstimate above will
510 * have been wrong. need 5 chars for ASN, a seperator each and
511 * potentially two segment delimiters, plus a space between each
512 * segment and trailing zero.
513 */
514#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
515 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
516 {
517 str_size = len + SEGMENT_STR_LEN(seg);
518 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
519 }
520#undef ASN_STR_LEN
521#undef SEGMENT_STR_LEN
522
523 if (seg->type != AS_SEQUENCE)
524 len += snprintf (str_buf + len, str_size - len,
525 "%c",
526 aspath_delimiter_char (seg->type, AS_SEG_START));
527
528 /* write out the ASNs, with their seperators, bar the last one*/
529 for (i = 0; i < seg->length; i++)
530 {
531 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
532
533 if (i < (seg->length - 1))
534 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
535 }
536
537 if (seg->type != AS_SEQUENCE)
538 len += snprintf (str_buf + len, str_size - len, "%c",
539 aspath_delimiter_char (seg->type, AS_SEG_END));
540 if (seg->next)
541 len += snprintf (str_buf + len, str_size - len, " ");
542
543 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000544 }
paulfe69a502005-09-10 16:55:02 +0000545
546 assert (len < str_size);
547
548 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000549
550 return str_buf;
551}
552
paulfe69a502005-09-10 16:55:02 +0000553static void
554aspath_str_update (struct aspath *as)
555{
556 if (as->str)
557 XFREE (MTYPE_AS_STR, as->str);
558 as->str = aspath_make_str_count (as);
559}
560
paul718e3742002-12-13 20:15:29 +0000561/* Intern allocated AS path. */
562struct aspath *
563aspath_intern (struct aspath *aspath)
564{
565 struct aspath *find;
566
567 /* Assert this AS path structure is not interned. */
568 assert (aspath->refcnt == 0);
569
570 /* Check AS path hash. */
571 find = hash_get (ashash, aspath, hash_alloc_intern);
572
573 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000574 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000575
576 find->refcnt++;
577
578 if (! find->str)
579 find->str = aspath_make_str_count (find);
580
581 return find;
582}
583
584/* Duplicate aspath structure. Created same aspath structure but
585 reference count and AS path string is cleared. */
586struct aspath *
587aspath_dup (struct aspath *aspath)
588{
589 struct aspath *new;
590
paulfe69a502005-09-10 16:55:02 +0000591 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000592
paulfe69a502005-09-10 16:55:02 +0000593 if (aspath->segments)
594 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000595 else
paulfe69a502005-09-10 16:55:02 +0000596 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000597
paulfe69a502005-09-10 16:55:02 +0000598 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000599
600 return new;
601}
602
paul94f2b392005-06-28 12:44:16 +0000603static void *
paulfe69a502005-09-10 16:55:02 +0000604aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000605{
606 struct aspath *aspath;
607
608 /* New aspath strucutre is needed. */
paulfe69a502005-09-10 16:55:02 +0000609 aspath = aspath_dup (arg);
610
paul718e3742002-12-13 20:15:29 +0000611 /* Malformed AS path value. */
612 if (! aspath->str)
613 {
614 aspath_free (aspath);
615 return NULL;
616 }
617
618 return aspath;
619}
620
paulfe69a502005-09-10 16:55:02 +0000621/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000622static struct assegment *
paulfe69a502005-09-10 16:55:02 +0000623assegments_parse (struct stream *s, size_t length)
624{
625 struct assegment_header segh;
626 struct assegment *seg, *prev = NULL, *head = NULL;
627 size_t bytes = 0;
628
629 /* empty aspath (ie iBGP or somesuch) */
630 if (length == 0)
631 return NULL;
632
633 /* basic checks */
634 if ( (STREAM_READABLE(s) < length)
635 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
636 || (length % AS_VALUE_SIZE))
637 return NULL;
638
639 while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
640 && (bytes < length))
641 {
642 int i;
643
644 /* softly softly, get the header first on its own */
645 segh.type = stream_getc (s);
646 segh.length = stream_getc (s);
647
648 /* check it.. */
649 if ( ((bytes + ASSEGMENT_SIZE(segh.length)) > length)
650 /* 1771bis 4.3b: seg length contains one or more */
651 || (segh.length == 0)
652 /* Paranoia in case someone changes type of segment length */
653 || ((sizeof segh.length > 1) && segh.length > AS_SEGMENT_MAX))
654 {
655 if (head)
656 assegment_free_all (head);
657 return NULL;
658 }
659
660 /* now its safe to trust lengths */
661 seg = assegment_new (segh.type, segh.length);
662
663 if (head)
664 prev->next = seg;
665 else /* it's the first segment */
666 head = prev = seg;
667
668 for (i = 0; i < segh.length; i++)
669 seg->as[i] = stream_getw (s);
670
671 bytes += ASSEGMENT_SIZE(segh.length);
672
673 prev = seg;
674 }
675
676 return assegment_normalise (head);
677}
678
paul718e3742002-12-13 20:15:29 +0000679/* AS path parse function. pnt is a pointer to byte stream and length
680 is length of byte stream. If there is same AS path in the the AS
681 path hash then return it else make new AS path structure. */
682struct aspath *
paulfe69a502005-09-10 16:55:02 +0000683aspath_parse (struct stream *s, size_t length)
paul718e3742002-12-13 20:15:29 +0000684{
685 struct aspath as;
686 struct aspath *find;
687
688 /* If length is odd it's malformed AS path. */
paulfe69a502005-09-10 16:55:02 +0000689 if (length % AS_VALUE_SIZE)
paul718e3742002-12-13 20:15:29 +0000690 return NULL;
691
paulfe69a502005-09-10 16:55:02 +0000692 as.segments = assegments_parse (s, length);
693
paul718e3742002-12-13 20:15:29 +0000694 /* If already same aspath exist then return it. */
695 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000696
697 /* aspath_hash_alloc dupes segments too. that probably could be
698 * optimised out.
699 */
700 assegment_free_all (as.segments);
701
paul718e3742002-12-13 20:15:29 +0000702 if (! find)
703 return NULL;
704 find->refcnt++;
705
706 return find;
707}
708
paulfe69a502005-09-10 16:55:02 +0000709static inline void
710assegment_data_put (struct stream *s, as_t *as, int num)
paul718e3742002-12-13 20:15:29 +0000711{
paulfe69a502005-09-10 16:55:02 +0000712 int i;
713 assert (num <= AS_SEGMENT_MAX);
714
715 for (i = 0; i < num; i++)
716 stream_putw (s, as[i]);
paul718e3742002-12-13 20:15:29 +0000717}
718
paulfe69a502005-09-10 16:55:02 +0000719static inline size_t
720assegment_header_put (struct stream *s, u_char type, int length)
721{
722 size_t lenp;
723 assert (length <= AS_SEGMENT_MAX);
724 stream_putc (s, type);
725 lenp = stream_get_endp (s);
726 stream_putc (s, length);
727 return lenp;
728}
729
730/* write aspath data to stream */
731void
732aspath_put (struct stream *s, struct aspath *as)
733{
734 struct assegment *seg = as->segments;
735
736 if (!seg || seg->length == 0)
737 return;
738
739 if (seg)
740 {
741 while (seg && (ASSEGMENT_LEN (seg) <= STREAM_WRITEABLE(s)))
742 {
743 int written = 0;
744 size_t lenp;
745
746 /* Overlength segments have to be split up */
747 while ( (seg->length - written) > AS_SEGMENT_MAX)
748 {
749 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
750 assegment_data_put (s, seg->as, AS_SEGMENT_MAX);
751 written += AS_SEGMENT_MAX;
752 }
753
754 /* write the final segment, probably is also the first */
755 lenp = assegment_header_put (s, seg->type, seg->length - written);
756 assegment_data_put (s, (seg->as + written), seg->length - written);
757
758 /* Sequence-type segments can be 'packed' together
759 * Case of a segment which was overlength and split up
760 * will be missed here, but that doesn't matter.
761 */
762 if (seg->next && ASSEGMENTS_PACKABLE (seg, seg->next))
763 {
764 /* NB: We should never normally get here given we
765 * normalise aspath data when parse them. However, better
766 * safe than sorry. We potentially could call
767 * assegment_normalise here instead, but it's cheaper and
768 * easier to do it on the fly here rather than go through
769 * the segment list twice every time we write out
770 * aspath's.
771 */
772
773 /* Next segment's data can fit in this one */
774 assegment_data_put (s, seg->next->as, seg->next->length);
775
776 /* update the length of the segment header */
777 stream_putc_at (s, lenp,
778 seg->length - written + seg->next->length);
779 seg = seg->next->next; /* skip to past next */
780 }
781 else
782 seg = seg->next;
783 }
784 }
785}
786
787/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
788 * We have no way to manage the storage, so we use a static stream
789 * wrapper around aspath_put.
790 */
791u_char *
792aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
793{
794#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000795
796 if (!snmp_stream)
797 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000798 else
paul8fdc32a2006-01-16 12:01:29 +0000799 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000800
801 if (!as)
802 {
803 *varlen = 0;
804 return NULL;
805 }
paul8fdc32a2006-01-16 12:01:29 +0000806 aspath_put (snmp_stream, as);
paulfe69a502005-09-10 16:55:02 +0000807
paul8fdc32a2006-01-16 12:01:29 +0000808 *varlen = stream_get_endp (snmp_stream);
809 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000810}
811
812#define min(A,B) ((A) < (B) ? (A) : (B))
813
paul94f2b392005-06-28 12:44:16 +0000814static struct assegment *
paul718e3742002-12-13 20:15:29 +0000815aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
816 as_t as)
817{
818 int i;
819
820 /* If this is first AS set member, create new as-set segment. */
821 if (asset == NULL)
822 {
paulfe69a502005-09-10 16:55:02 +0000823 asset = assegment_new (AS_SET, 1);
824 if (! aspath->segments)
825 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000826 else
paulfe69a502005-09-10 16:55:02 +0000827 {
828 struct assegment *seg = aspath->segments;
829 while (seg->next)
830 seg = seg->next;
831 seg->next = asset;
832 }
paul718e3742002-12-13 20:15:29 +0000833 asset->type = AS_SET;
834 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000835 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000836 }
837 else
838 {
paul718e3742002-12-13 20:15:29 +0000839 /* Check this AS value already exists or not. */
840 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000841 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000842 return asset;
paulfe69a502005-09-10 16:55:02 +0000843
paul718e3742002-12-13 20:15:29 +0000844 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000845 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
846 asset->length * AS_VALUE_SIZE);
847 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000848 }
paulfe69a502005-09-10 16:55:02 +0000849
paul718e3742002-12-13 20:15:29 +0000850
851 return asset;
852}
853
854/* Modify as1 using as2 for aggregation. */
855struct aspath *
856aspath_aggregate (struct aspath *as1, struct aspath *as2)
857{
858 int i;
859 int minlen;
860 int match;
paulfe69a502005-09-10 16:55:02 +0000861 int from;
862 struct assegment *seg1 = as1->segments;
863 struct assegment *seg2 = as2->segments;
paul718e3742002-12-13 20:15:29 +0000864 struct aspath *aspath;
865 struct assegment *asset;
866
867 match = 0;
868 minlen = 0;
869 aspath = NULL;
870 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000871
872 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000873 while (seg1 && seg2)
paul718e3742002-12-13 20:15:29 +0000874 {
875 /* Check segment type. */
876 if (seg1->type != seg2->type)
877 break;
878
879 /* Minimum segment length. */
880 minlen = min (seg1->length, seg2->length);
881
882 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +0000883 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +0000884 break;
885
886 if (match)
887 {
888 if (! aspath)
paulfe69a502005-09-10 16:55:02 +0000889 aspath = aspath_new ();
890 aspath->segments = assegment_new (seg1->type, 0);
891 aspath->segments = assegment_append_asns (aspath->segments,
892 seg1->as, match);
paul718e3742002-12-13 20:15:29 +0000893 }
894
895 if (match != minlen || match != seg1->length
896 || seg1->length != seg2->length)
897 break;
paulfe69a502005-09-10 16:55:02 +0000898
899 seg1 = seg1->next;
900 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +0000901 }
902
903 if (! aspath)
904 aspath = aspath_new();
905
906 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +0000907 from = match;
908 while (seg1)
paul718e3742002-12-13 20:15:29 +0000909 {
paulfe69a502005-09-10 16:55:02 +0000910 for (i = from; i < seg1->length; i++)
911 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
912
913 from = 0;
914 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +0000915 }
916
paulfe69a502005-09-10 16:55:02 +0000917 from = match;
918 while (seg2)
paul718e3742002-12-13 20:15:29 +0000919 {
paulfe69a502005-09-10 16:55:02 +0000920 for (i = from; i < seg2->length; i++)
921 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +0000922
paulfe69a502005-09-10 16:55:02 +0000923 from = 0;
924 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +0000925 }
paulfe69a502005-09-10 16:55:02 +0000926
927 assegment_normalise (aspath->segments);
928 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +0000929 return aspath;
930}
931
932/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
933 attribute, check the leftmost AS number in the AS_PATH attribute is
934 or not the peer's AS number. */
935int
936aspath_firstas_check (struct aspath *aspath, as_t asno)
937{
paulfe69a502005-09-10 16:55:02 +0000938 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +0000939 return 0;
paulfe69a502005-09-10 16:55:02 +0000940
941 if (aspath->segments
942 && (aspath->segments->type == AS_SEQUENCE)
943 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +0000944 return 1;
945
946 return 0;
947}
948
Paul Jakma1f742f22006-08-06 15:52:11 +0000949/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +0000950int
951aspath_loop_check (struct aspath *aspath, as_t asno)
952{
paulfe69a502005-09-10 16:55:02 +0000953 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +0000954 int count = 0;
955
Paul Jakma1f742f22006-08-06 15:52:11 +0000956 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +0000957 return 0;
paulfe69a502005-09-10 16:55:02 +0000958
959 seg = aspath->segments;
960
961 while (seg)
paul718e3742002-12-13 20:15:29 +0000962 {
963 int i;
paul718e3742002-12-13 20:15:29 +0000964
paulfe69a502005-09-10 16:55:02 +0000965 for (i = 0; i < seg->length; i++)
966 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +0000967 count++;
paulfe69a502005-09-10 16:55:02 +0000968
969 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000970 }
971 return count;
972}
973
974/* When all of AS path is private AS return 1. */
975int
976aspath_private_as_check (struct aspath *aspath)
977{
paulfe69a502005-09-10 16:55:02 +0000978 struct assegment *seg;
979
980 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +0000981 return 0;
paulfe69a502005-09-10 16:55:02 +0000982
983 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +0000984
paulfe69a502005-09-10 16:55:02 +0000985 while (seg)
paul718e3742002-12-13 20:15:29 +0000986 {
987 int i;
paul718e3742002-12-13 20:15:29 +0000988
paulfe69a502005-09-10 16:55:02 +0000989 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +0000990 {
paulfe69a502005-09-10 16:55:02 +0000991 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
992 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +0000993 return 0;
994 }
paulfe69a502005-09-10 16:55:02 +0000995 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000996 }
997 return 1;
998}
999
1000/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001001static struct aspath *
paul718e3742002-12-13 20:15:29 +00001002aspath_merge (struct aspath *as1, struct aspath *as2)
1003{
paulfe69a502005-09-10 16:55:02 +00001004 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001005
1006 if (! as1 || ! as2)
1007 return NULL;
1008
paulfe69a502005-09-10 16:55:02 +00001009 last = new = assegment_dup_all (as1->segments);
1010
1011 /* find the last valid segment */
1012 while (last && last->next)
1013 last = last->next;
1014
1015 last->next = as2->segments;
1016 as2->segments = new;
1017 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001018 return as2;
1019}
1020
1021/* Prepend as1 to as2. as2 should be uninterned aspath. */
1022struct aspath *
1023aspath_prepend (struct aspath *as1, struct aspath *as2)
1024{
paulfe69a502005-09-10 16:55:02 +00001025 struct assegment *seg1;
1026 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001027
1028 if (! as1 || ! as2)
1029 return NULL;
paulfe69a502005-09-10 16:55:02 +00001030
1031 seg1 = as1->segments;
1032 seg2 = as2->segments;
1033
1034 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001035 if (seg2 == NULL)
1036 {
paulfe69a502005-09-10 16:55:02 +00001037 as2->segments = assegment_dup_all (as1->segments);
1038 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001039 return as2;
1040 }
paulfe69a502005-09-10 16:55:02 +00001041
1042 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001043 if (seg1 == NULL)
1044 return as2;
paulfe69a502005-09-10 16:55:02 +00001045
1046 /* find the tail as1's segment chain. */
1047 while (seg1 && seg1->next)
1048 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001049
1050 /* Compare last segment type of as1 and first segment type of as2. */
1051 if (seg1->type != seg2->type)
1052 return aspath_merge (as1, as2);
1053
1054 if (seg1->type == AS_SEQUENCE)
1055 {
paulfe69a502005-09-10 16:55:02 +00001056 /* We have two chains of segments, as1->segments and seg2,
1057 * and we have to attach them together, merging the attaching
1058 * segments together into one.
1059 *
1060 * 1. dupe as1->segments onto head of as2
1061 * 2. merge seg2's asns onto last segment of this new chain
1062 * 3. attach chain after seg2
1063 */
paul718e3742002-12-13 20:15:29 +00001064
paulfe69a502005-09-10 16:55:02 +00001065 /* dupe as1 onto as2's head */
1066 seg1 = as2->segments = assegment_dup_all (as1->segments);
1067
1068 /* refind the tail of as2, reusing seg1 */
1069 while (seg1 && seg1->next)
1070 seg1 = seg1->next;
1071
1072 /* merge the old head, seg2, into tail, seg1 */
1073 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1074
1075 /* bypass the merged seg2, and attach any chain after it to
1076 * chain descending from as2's head
1077 */
1078 seg1->next = seg2->next;
1079
1080 /* seg2 is now referenceless and useless*/
1081 assegment_free (seg2);
1082
1083 /* we've now prepended as1's segment chain to as2, merging
1084 * the inbetween AS_SEQUENCE of seg2 in the process
1085 */
1086 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001087 return as2;
1088 }
1089 else
1090 {
1091 /* AS_SET merge code is needed at here. */
1092 return aspath_merge (as1, as2);
1093 }
paulfe69a502005-09-10 16:55:02 +00001094 /* XXX: Ermmm, what if as1 has multiple segments?? */
1095
paul718e3742002-12-13 20:15:29 +00001096 /* Not reached */
1097}
1098
1099/* Add specified AS to the leftmost of aspath. */
1100static struct aspath *
1101aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1102{
paulfe69a502005-09-10 16:55:02 +00001103 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001104
1105 /* In case of empty aspath. */
1106 if (assegment == NULL || assegment->length == 0)
1107 {
paulfe69a502005-09-10 16:55:02 +00001108 aspath->segments = assegment_new (type, 1);
1109 aspath->segments->as[0] = asno;
1110
paul718e3742002-12-13 20:15:29 +00001111 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001112 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001113
1114 return aspath;
1115 }
1116
1117 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001118 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1119 else
paul718e3742002-12-13 20:15:29 +00001120 {
paulfe69a502005-09-10 16:55:02 +00001121 /* create new segment
1122 * push it onto head of aspath's segment chain
1123 */
paul718e3742002-12-13 20:15:29 +00001124 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001125
1126 newsegment = assegment_new (type, 1);
1127 newsegment->as[0] = asno;
1128
1129 newsegment->next = assegment;
1130 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001131 }
1132
1133 return aspath;
1134}
1135
1136/* Add specified AS to the leftmost of aspath. */
1137struct aspath *
1138aspath_add_seq (struct aspath *aspath, as_t asno)
1139{
1140 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1141}
1142
1143/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1144 as2's leftmost AS is same return 1. */
1145int
1146aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
1147{
paulfe69a502005-09-10 16:55:02 +00001148 struct assegment *seg1 = NULL;
1149 struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001150
paulfe69a502005-09-10 16:55:02 +00001151 if (!(aspath1 && aspath2))
1152 return 0;
paul718e3742002-12-13 20:15:29 +00001153
paulfe69a502005-09-10 16:55:02 +00001154 seg1 = aspath1->segments;
1155 seg2 = aspath2->segments;
1156
1157 /* find first non-confed segments for each */
1158 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1159 || (seg1->type == AS_CONFED_SET)))
1160 seg1 = seg1->next;
1161
1162 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1163 || (seg2->type == AS_CONFED_SET)))
1164 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001165
1166 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001167 if (!(seg1 && seg2
1168 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001169 return 0;
paulfe69a502005-09-10 16:55:02 +00001170
1171 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001172 return 1;
1173
1174 return 0;
1175}
1176
1177/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1178 as2's leftmost AS is same return 1. (confederation as-path
1179 only). */
1180int
1181aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2)
1182{
paulfe69a502005-09-10 16:55:02 +00001183 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001184 return 0;
paulfe69a502005-09-10 16:55:02 +00001185
paulad727402005-11-23 02:47:02 +00001186 if ( !(aspath1->segments && aspath2->segments) )
1187 return 0;
1188
paulfe69a502005-09-10 16:55:02 +00001189 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1190 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001191 return 0;
paulfe69a502005-09-10 16:55:02 +00001192
1193 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001194 return 1;
1195
1196 return 0;
1197}
1198
paulfe69a502005-09-10 16:55:02 +00001199/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1200 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001201struct aspath *
1202aspath_delete_confed_seq (struct aspath *aspath)
1203{
paulfe69a502005-09-10 16:55:02 +00001204 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001205
paulfe69a502005-09-10 16:55:02 +00001206 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001207 return aspath;
1208
paulfe69a502005-09-10 16:55:02 +00001209 seg = aspath->segments;
1210
1211 /* "if the first path segment of the AS_PATH is
1212 * of type AS_CONFED_SEQUENCE,"
1213 */
1214 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1215 return aspath;
paul718e3742002-12-13 20:15:29 +00001216
paulfe69a502005-09-10 16:55:02 +00001217 /* "... that segment and any immediately following segments
1218 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1219 * from the AS_PATH attribute,"
1220 */
1221 while (seg &&
1222 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001223 {
paulfe69a502005-09-10 16:55:02 +00001224 aspath->segments = seg->next;
1225 assegment_free (seg);
1226 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001227 }
paulfe69a502005-09-10 16:55:02 +00001228 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001229 return aspath;
1230}
1231
1232/* Add new AS number to the leftmost part of the aspath as
1233 AS_CONFED_SEQUENCE. */
1234struct aspath*
1235aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1236{
1237 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1238}
1239
1240/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001241static void
paul718e3742002-12-13 20:15:29 +00001242aspath_as_add (struct aspath *as, as_t asno)
1243{
paulfe69a502005-09-10 16:55:02 +00001244 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001245
paulfe69a502005-09-10 16:55:02 +00001246 if (!seg)
1247 return;
1248
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001249 /* Last segment search procedure. */
1250 while (seg->next)
1251 seg = seg->next;
1252
paulfe69a502005-09-10 16:55:02 +00001253 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001254}
1255
1256/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001257static void
paul718e3742002-12-13 20:15:29 +00001258aspath_segment_add (struct aspath *as, int type)
1259{
paulfe69a502005-09-10 16:55:02 +00001260 struct assegment *seg = as->segments;
1261 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001262
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001263 if (seg)
1264 {
1265 while (seg->next)
1266 seg = seg->next;
1267 seg->next = new;
1268 }
paul718e3742002-12-13 20:15:29 +00001269 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001270 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001271}
1272
1273struct aspath *
paul94f2b392005-06-28 12:44:16 +00001274aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001275{
1276 return aspath_parse (NULL, 0);
1277}
1278
1279struct aspath *
paul94f2b392005-06-28 12:44:16 +00001280aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001281{
1282 struct aspath *aspath;
1283
1284 aspath = aspath_new ();
1285 aspath->str = aspath_make_str_count (aspath);
1286 return aspath;
1287}
1288
1289unsigned long
paulfe69a502005-09-10 16:55:02 +00001290aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001291{
1292 return ashash->count;
1293}
1294
1295/*
1296 Theoretically, one as path can have:
1297
1298 One BGP packet size should be less than 4096.
1299 One BGP attribute size should be less than 4096 - BGP header size.
1300 One BGP aspath size should be less than 4096 - BGP header size -
1301 BGP mandantry attribute size.
1302*/
1303
1304/* AS path string lexical token enum. */
1305enum as_token
1306{
1307 as_token_asval,
1308 as_token_set_start,
1309 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001310 as_token_confed_seq_start,
1311 as_token_confed_seq_end,
1312 as_token_confed_set_start,
1313 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001314 as_token_unknown
1315};
1316
1317/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001318static const char *
paulfd79ac92004-10-13 05:06:08 +00001319aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
paul718e3742002-12-13 20:15:29 +00001320{
paulfd79ac92004-10-13 05:06:08 +00001321 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001322
paulfe69a502005-09-10 16:55:02 +00001323 /* Skip seperators (space for sequences, ',' for sets). */
1324 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001325 p++;
1326
1327 /* Check the end of the string and type specify characters
1328 (e.g. {}()). */
1329 switch (*p)
1330 {
1331 case '\0':
1332 return NULL;
paul718e3742002-12-13 20:15:29 +00001333 case '{':
1334 *token = as_token_set_start;
1335 p++;
1336 return p;
paul718e3742002-12-13 20:15:29 +00001337 case '}':
1338 *token = as_token_set_end;
1339 p++;
1340 return p;
paul718e3742002-12-13 20:15:29 +00001341 case '(':
paulfe69a502005-09-10 16:55:02 +00001342 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001343 p++;
1344 return p;
paul718e3742002-12-13 20:15:29 +00001345 case ')':
paulfe69a502005-09-10 16:55:02 +00001346 *token = as_token_confed_seq_end;
1347 p++;
1348 return p;
paulfe69a502005-09-10 16:55:02 +00001349 case '[':
1350 *token = as_token_confed_set_start;
1351 p++;
1352 return p;
paulfe69a502005-09-10 16:55:02 +00001353 case ']':
1354 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001355 p++;
1356 return p;
paul718e3742002-12-13 20:15:29 +00001357 }
1358
1359 /* Check actual AS value. */
1360 if (isdigit ((int) *p))
1361 {
1362 u_short asval;
1363
1364 *token = as_token_asval;
1365 asval = (*p - '0');
1366 p++;
1367 while (isdigit ((int) *p))
1368 {
1369 asval *= 10;
1370 asval += (*p - '0');
1371 p++;
1372 }
1373 *asno = asval;
1374 return p;
1375 }
1376
1377 /* There is no match then return unknown token. */
1378 *token = as_token_unknown;
1379 return p++;
1380}
1381
1382struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001383aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001384{
paul3fff6ff2006-02-05 17:55:35 +00001385 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001386 u_short as_type;
Paul Jakma1f742f22006-08-06 15:52:11 +00001387 u_short asno = 0;
paul718e3742002-12-13 20:15:29 +00001388 struct aspath *aspath;
1389 int needtype;
1390
1391 aspath = aspath_new ();
1392
1393 /* We start default type as AS_SEQUENCE. */
1394 as_type = AS_SEQUENCE;
1395 needtype = 1;
1396
1397 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1398 {
1399 switch (token)
1400 {
1401 case as_token_asval:
1402 if (needtype)
1403 {
1404 aspath_segment_add (aspath, as_type);
1405 needtype = 0;
1406 }
1407 aspath_as_add (aspath, asno);
1408 break;
1409 case as_token_set_start:
1410 as_type = AS_SET;
1411 aspath_segment_add (aspath, as_type);
1412 needtype = 0;
1413 break;
1414 case as_token_set_end:
1415 as_type = AS_SEQUENCE;
1416 needtype = 1;
1417 break;
paulfe69a502005-09-10 16:55:02 +00001418 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001419 as_type = AS_CONFED_SEQUENCE;
1420 aspath_segment_add (aspath, as_type);
1421 needtype = 0;
1422 break;
paulfe69a502005-09-10 16:55:02 +00001423 case as_token_confed_seq_end:
1424 as_type = AS_SEQUENCE;
1425 needtype = 1;
1426 break;
1427 case as_token_confed_set_start:
1428 as_type = AS_CONFED_SET;
1429 aspath_segment_add (aspath, as_type);
1430 needtype = 0;
1431 break;
1432 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001433 as_type = AS_SEQUENCE;
1434 needtype = 1;
1435 break;
1436 case as_token_unknown:
1437 default:
paulfe69a502005-09-10 16:55:02 +00001438 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001439 return NULL;
paul718e3742002-12-13 20:15:29 +00001440 }
1441 }
1442
1443 aspath->str = aspath_make_str_count (aspath);
1444
1445 return aspath;
1446}
1447
1448/* Make hash value by raw aspath data. */
1449unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001450aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001451{
Paul Jakma923de652007-04-29 18:25:17 +00001452 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001453 unsigned int key = 0;
paulfe69a502005-09-10 16:55:02 +00001454 unsigned int i;
1455 struct assegment *seg = aspath->segments;
1456 struct assegment *prev = NULL;
paul718e3742002-12-13 20:15:29 +00001457
paulfe69a502005-09-10 16:55:02 +00001458 while (seg)
paul718e3742002-12-13 20:15:29 +00001459 {
paulfe69a502005-09-10 16:55:02 +00001460 /* segment types should be part of the hash
1461 * otherwise seq(1) and set(1) will hash to same value
1462 */
1463 if (!(prev && seg->type == AS_SEQUENCE && seg->type == prev->type))
1464 key += seg->type;
1465
1466 for (i = 0; i < seg->length; i++)
1467 key += seg->as[i];
1468
1469 prev = seg;
1470 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001471 }
1472
1473 return key;
1474}
1475
1476/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001477static int
paulfe69a502005-09-10 16:55:02 +00001478aspath_cmp (void *arg1, void *arg2)
paul718e3742002-12-13 20:15:29 +00001479{
paulfe69a502005-09-10 16:55:02 +00001480 struct assegment *seg1 = ((struct aspath *)arg1)->segments;
1481 struct assegment *seg2 = ((struct aspath *)arg2)->segments;
1482
1483 while (seg1 || seg2)
1484 {
1485 int i;
1486 if ((!seg1 && seg2) || (seg1 && !seg2))
1487 return 0;
1488 if (seg1->type != seg2->type)
1489 return 0;
1490 if (seg1->length != seg2->length)
1491 return 0;
1492 for (i = 0; i < seg1->length; i++)
1493 if (seg1->as[i] != seg2->as[i])
1494 return 0;
1495 seg1 = seg1->next;
1496 seg2 = seg2->next;
1497 }
1498 return 1;
paul718e3742002-12-13 20:15:29 +00001499}
1500
1501/* AS path hash initialize. */
1502void
paul94f2b392005-06-28 12:44:16 +00001503aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001504{
1505 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1506}
paul8fdc32a2006-01-16 12:01:29 +00001507
1508void
1509aspath_finish (void)
1510{
1511 hash_free (ashash);
1512
1513 if (snmp_stream)
1514 stream_free (snmp_stream);
1515}
paul718e3742002-12-13 20:15:29 +00001516
1517/* return and as path value */
1518const char *
1519aspath_print (struct aspath *as)
1520{
paulfe69a502005-09-10 16:55:02 +00001521 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001522}
1523
1524/* Printing functions */
1525void
Paul Jakmab2518c12006-05-12 23:48:40 +00001526aspath_print_vty (struct vty *vty, const char *format, struct aspath *as)
paul718e3742002-12-13 20:15:29 +00001527{
Paul Jakmab2518c12006-05-12 23:48:40 +00001528 assert (format);
1529 vty_out (vty, format, as->str);
paul718e3742002-12-13 20:15:29 +00001530}
1531
paul94f2b392005-06-28 12:44:16 +00001532static void
paul718e3742002-12-13 20:15:29 +00001533aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1534{
1535 struct aspath *as;
1536
1537 as = (struct aspath *) backet->data;
1538
paulefa9f832002-12-13 21:47:59 +00001539 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001540 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1541}
1542
1543/* Print all aspath and hash information. This function is used from
1544 `show ip bgp paths' command. */
1545void
1546aspath_print_all_vty (struct vty *vty)
1547{
1548 hash_iterate (ashash,
1549 (void (*) (struct hash_backet *, void *))
1550 aspath_show_all_iterator,
1551 vty);
1552}