blob: e65541f977d98dabd90f8026d8cc3d1d2e9967a3 [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"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000031#include "jhash.h"
paul718e3742002-12-13 20:15:29 +000032
33#include "bgpd/bgpd.h"
34#include "bgpd/bgp_aspath.h"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000035#include "bgpd/bgp_debug.h"
36#include "bgpd/bgp_attr.h"
paul718e3742002-12-13 20:15:29 +000037
38/* Attr. Flags and Attr. Type Code. */
39#define AS_HEADER_SIZE 2
40
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000041/* Now FOUR octets are used for AS value. */
paul718e3742002-12-13 20:15:29 +000042#define AS_VALUE_SIZE sizeof (as_t)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000043/* This is the old one */
44#define AS16_VALUE_SIZE sizeof (as16_t)
paul718e3742002-12-13 20:15:29 +000045
paulfe69a502005-09-10 16:55:02 +000046/* Maximum protocol segment length value */
47#define AS_SEGMENT_MAX 255
paul718e3742002-12-13 20:15:29 +000048
paulfe69a502005-09-10 16:55:02 +000049/* The following length and size macros relate specifically to Quagga's
50 * internal representation of AS-Segments, not per se to the on-wire
51 * sizes and lengths. At present (200508) they sort of match, however
52 * the ONLY functions which should now about the on-wire syntax are
53 * aspath_put, assegment_put and assegment_parse.
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000054 *
55 * aspath_put returns bytes written, the only definitive record of
56 * size of wire-format attribute..
paulfe69a502005-09-10 16:55:02 +000057 */
58
59/* Calculated size in bytes of ASN segment data to hold N ASN's */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000060#define ASSEGMENT_DATA_SIZE(N,S) \
61 ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )
paulfe69a502005-09-10 16:55:02 +000062
63/* Calculated size of segment struct to hold N ASN's */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000064#define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
paulfe69a502005-09-10 16:55:02 +000065
66/* AS segment octet length. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000067#define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
paulfe69a502005-09-10 16:55:02 +000068
69/* AS_SEQUENCE segments can be packed together */
70/* Can the types of X and Y be considered for packing? */
71#define ASSEGMENT_TYPES_PACKABLE(X,Y) \
72 ( ((X)->type == (Y)->type) \
73 && ((X)->type == AS_SEQUENCE))
74/* Types and length of X,Y suitable for packing? */
75#define ASSEGMENTS_PACKABLE(X,Y) \
76 ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \
77 && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) )
78
79/* As segment header - the on-wire representation
80 * NOT the internal representation!
81 */
82struct assegment_header
paul718e3742002-12-13 20:15:29 +000083{
84 u_char type;
85 u_char length;
paul718e3742002-12-13 20:15:29 +000086};
87
88/* Hash for aspath. This is the top level structure of AS path. */
89struct hash *ashash;
paul8fdc32a2006-01-16 12:01:29 +000090
91/* Stream for SNMP. See aspath_snmp_pathseg */
92static struct stream *snmp_stream;
paul718e3742002-12-13 20:15:29 +000093
paulfe69a502005-09-10 16:55:02 +000094static inline as_t *
95assegment_data_new (int num)
96{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000097 return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
paulfe69a502005-09-10 16:55:02 +000098}
99
100static inline void
101assegment_data_free (as_t *asdata)
102{
103 XFREE (MTYPE_AS_SEG_DATA,asdata);
104}
105
106/* Get a new segment. Note that 0 is an allowed length,
107 * and will result in a segment with no allocated data segment.
108 * the caller should immediately assign data to the segment, as the segment
109 * otherwise is not generally valid
110 */
111static struct assegment *
112assegment_new (u_char type, u_short length)
113{
114 struct assegment *new;
115
116 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
117
118 if (length)
119 new->as = assegment_data_new (length);
120
121 new->length = length;
122 new->type = type;
123
124 return new;
125}
126
127static void
128assegment_free (struct assegment *seg)
129{
130 if (!seg)
131 return;
132
133 if (seg->as)
134 XFREE (MTYPE_AS_SEG_DATA, seg->as);
135 memset (seg, 0xfe, sizeof(struct assegment));
136 XFREE (MTYPE_AS_SEG, seg);
137
138 return;
139}
140
141/* free entire chain of segments */
142static void
143assegment_free_all (struct assegment *seg)
144{
145 struct assegment *prev;
146
147 while (seg)
148 {
149 prev = seg;
150 seg = seg->next;
151 assegment_free (prev);
152 }
153}
154
155/* Duplicate just the given assegment and its data */
156static struct assegment *
157assegment_dup (struct assegment *seg)
158{
159 struct assegment *new;
160
161 new = assegment_new (seg->type, seg->length);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000162 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );
paulfe69a502005-09-10 16:55:02 +0000163
164 return new;
165}
166
167/* Duplicate entire chain of assegments, return the head */
168static struct assegment *
169assegment_dup_all (struct assegment *seg)
170{
171 struct assegment *new = NULL;
172 struct assegment *head = NULL;
173
174 while (seg)
175 {
176 if (head)
177 {
178 new->next = assegment_dup (seg);
179 new = new->next;
180 }
181 else
182 head = new = assegment_dup (seg);
183
184 seg = seg->next;
185 }
186 return head;
187}
188
189/* prepend the as number to given segment, given num of times */
190static struct assegment *
191assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
192{
193 as_t *newas;
194
195 if (!num)
196 return seg;
197
198 if (num >= AS_SEGMENT_MAX)
199 return seg; /* we don't do huge prepends */
200
201 newas = assegment_data_new (seg->length + num);
202
203 if (newas)
204 {
205 int i;
206 for (i = 0; i < num; i++)
207 newas[i] = asnum;
208
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000209 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
paulfe69a502005-09-10 16:55:02 +0000210 XFREE (MTYPE_AS_SEG_DATA, seg->as);
211 seg->as = newas;
212 seg->length += num;
213 return seg;
214 }
215
216 assegment_free_all (seg);
217 return NULL;
218}
219
220/* append given array of as numbers to the segment */
221static struct assegment *
222assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
223{
paul02335422006-01-16 11:13:27 +0000224 as_t *newas;
225
226 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000227 ASSEGMENT_DATA_SIZE (seg->length + num, 1));
paulfe69a502005-09-10 16:55:02 +0000228
paul02335422006-01-16 11:13:27 +0000229 if (newas)
paulfe69a502005-09-10 16:55:02 +0000230 {
paul02335422006-01-16 11:13:27 +0000231 seg->as = newas;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000232 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));
paulfe69a502005-09-10 16:55:02 +0000233 seg->length += num;
234 return seg;
235 }
236
237 assegment_free_all (seg);
238 return NULL;
239}
240
241static int
242int_cmp (const void *p1, const void *p2)
243{
244 const as_t *as1 = p1;
245 const as_t *as2 = p2;
246
247 return (*as1 == *as2)
248 ? 0 : ( (*as1 > *as2) ? 1 : -1);
249}
250
251/* normalise the segment.
252 * In particular, merge runs of AS_SEQUENCEs into one segment
253 * Internally, we do not care about the wire segment length limit, and
254 * we want each distinct AS_PATHs to have the exact same internal
255 * representation - eg, so that our hashing actually works..
256 */
257static struct assegment *
258assegment_normalise (struct assegment *head)
259{
260 struct assegment *seg = head, *pin;
261 struct assegment *tmp;
262
263 if (!head)
264 return head;
265
266 while (seg)
267 {
268 pin = seg;
269
270 /* Sort values SET segments, for determinism in paths to aid
271 * creation of hash values / path comparisons
272 * and because it helps other lesser implementations ;)
273 */
274 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000275 {
276 int tail = 0;
277 int i;
278
279 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
280
281 /* weed out dupes */
282 for (i=1; i < seg->length; i++)
283 {
284 if (seg->as[tail] == seg->as[i])
285 continue;
286
287 tail++;
288 if (tail < i)
289 seg->as[tail] = seg->as[i];
290 }
291 /* seg->length can be 0.. */
292 if (seg->length)
293 seg->length = tail + 1;
294 }
paulfe69a502005-09-10 16:55:02 +0000295
296 /* read ahead from the current, pinned segment while the segments
297 * are packable/mergeable. Append all following packable segments
298 * to the segment we have pinned and remove these appended
299 * segments.
300 */
301 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
302 {
303 tmp = pin->next;
304 seg = pin->next;
305
306 /* append the next sequence to the pinned sequence */
307 pin = assegment_append_asns (pin, seg->as, seg->length);
308
309 /* bypass the next sequence */
310 pin->next = seg->next;
311
312 /* get rid of the now referenceless segment */
313 assegment_free (tmp);
314
315 }
316
317 seg = pin->next;
318 }
319 return head;
320}
321
paul718e3742002-12-13 20:15:29 +0000322static struct aspath *
paulfe69a502005-09-10 16:55:02 +0000323aspath_new (void)
paul718e3742002-12-13 20:15:29 +0000324{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700325 return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000326}
327
328/* Free AS path structure. */
329void
330aspath_free (struct aspath *aspath)
331{
332 if (!aspath)
333 return;
paulfe69a502005-09-10 16:55:02 +0000334 if (aspath->segments)
335 assegment_free_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000336 if (aspath->str)
337 XFREE (MTYPE_AS_STR, aspath->str);
338 XFREE (MTYPE_AS_PATH, aspath);
339}
340
341/* Unintern aspath from AS path bucket. */
342void
343aspath_unintern (struct aspath *aspath)
344{
345 struct aspath *ret;
346
347 if (aspath->refcnt)
348 aspath->refcnt--;
349
350 if (aspath->refcnt == 0)
351 {
352 /* This aspath must exist in aspath hash table. */
353 ret = hash_release (ashash, aspath);
354 assert (ret != NULL);
355 aspath_free (aspath);
356 }
357}
358
359/* Return the start or end delimiters for a particular Segment type */
360#define AS_SEG_START 0
361#define AS_SEG_END 1
362static char
363aspath_delimiter_char (u_char type, u_char which)
364{
365 int i;
366 struct
367 {
368 int type;
369 char start;
370 char end;
371 } aspath_delim_char [] =
372 {
373 { AS_SET, '{', '}' },
paul718e3742002-12-13 20:15:29 +0000374 { AS_CONFED_SET, '[', ']' },
375 { AS_CONFED_SEQUENCE, '(', ')' },
376 { 0 }
377 };
378
379 for (i = 0; aspath_delim_char[i].type != 0; i++)
380 {
381 if (aspath_delim_char[i].type == type)
382 {
383 if (which == AS_SEG_START)
384 return aspath_delim_char[i].start;
385 else if (which == AS_SEG_END)
386 return aspath_delim_char[i].end;
387 }
388 }
389 return ' ';
390}
391
Denis Ovsienko014b6702009-06-23 21:10:45 +0400392/* countup asns from this segment and index onward */
393static int
394assegment_count_asns (struct assegment *seg, int from)
395{
396 int count = 0;
397 while (seg)
398 {
399 if (!from)
400 count += seg->length;
401 else
402 {
403 count += (seg->length - from);
404 from = 0;
405 }
406 seg = seg->next;
407 }
408 return count;
409}
410
paulfe69a502005-09-10 16:55:02 +0000411unsigned int
412aspath_count_confeds (struct aspath *aspath)
413{
414 int count = 0;
415 struct assegment *seg = aspath->segments;
416
417 while (seg)
418 {
419 if (seg->type == AS_CONFED_SEQUENCE)
420 count += seg->length;
421 else if (seg->type == AS_CONFED_SET)
422 count++;
423
424 seg = seg->next;
425 }
426 return count;
427}
428
429unsigned int
430aspath_count_hops (struct aspath *aspath)
431{
432 int count = 0;
433 struct assegment *seg = aspath->segments;
434
435 while (seg)
436 {
437 if (seg->type == AS_SEQUENCE)
438 count += seg->length;
439 else if (seg->type == AS_SET)
440 count++;
441
442 seg = seg->next;
443 }
444 return count;
445}
446
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000447/* Estimate size aspath /might/ take if encoded into an
448 * ASPATH attribute.
449 *
450 * This is a quick estimate, not definitive! aspath_put()
451 * may return a different number!!
452 */
paulfe69a502005-09-10 16:55:02 +0000453unsigned int
454aspath_size (struct aspath *aspath)
455{
456 int size = 0;
457 struct assegment *seg = aspath->segments;
458
459 while (seg)
460 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000461 size += ASSEGMENT_SIZE(seg->length, 1);
paulfe69a502005-09-10 16:55:02 +0000462 seg = seg->next;
463 }
464 return size;
465}
466
Paul Jakma2815e612006-09-14 02:56:07 +0000467/* Return highest public ASN in path */
468as_t
469aspath_highest (struct aspath *aspath)
470{
471 struct assegment *seg = aspath->segments;
472 as_t highest = 0;
473 unsigned int i;
474
475 while (seg)
476 {
477 for (i = 0; i < seg->length; i++)
478 if (seg->as[i] > highest
479 && (seg->as[i] < BGP_PRIVATE_AS_MIN
480 || seg->as[i] > BGP_PRIVATE_AS_MAX))
481 highest = seg->as[i];
482 seg = seg->next;
483 }
484 return highest;
485}
486
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000487/* Return 1 if there are any 4-byte ASes in the path */
488unsigned int
489aspath_has_as4 (struct aspath *aspath)
490{
491 struct assegment *seg = aspath->segments;
492 unsigned int i;
493
494 while (seg)
495 {
496 for (i = 0; i < seg->length; i++)
497 if (seg->as[i] > BGP_AS_MAX)
498 return 1;
499 seg = seg->next;
500 }
501 return 0;
502}
503
504/* Return number of as numbers in in path */
505unsigned int
506aspath_count_numas (struct aspath *aspath)
507{
508 struct assegment *seg = aspath->segments;
509 unsigned int num;
510
511 num=0;
512 while (seg)
513 {
514 num += seg->length;
515 seg = seg->next;
516 }
517 return num;
518}
519
paul718e3742002-12-13 20:15:29 +0000520/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000521static char *
paul718e3742002-12-13 20:15:29 +0000522aspath_make_str_count (struct aspath *as)
523{
paulfe69a502005-09-10 16:55:02 +0000524 struct assegment *seg;
525 int str_size;
526 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000527 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000528
529 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000530 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000531 {
532 str_buf = XMALLOC (MTYPE_AS_STR, 1);
533 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000534 return str_buf;
535 }
paulfe69a502005-09-10 16:55:02 +0000536
537 seg = as->segments;
538
Denis Ovsienko014b6702009-06-23 21:10:45 +0400539 /* ASN takes 5 to 10 chars plus seperator, see below.
540 * If there is one differing segment type, we need an additional
541 * 2 chars for segment delimiters, and the final '\0'.
542 * Hopefully this is large enough to avoid hitting the realloc
543 * code below for most common sequences.
544 *
545 * This was changed to 10 after the well-known BGP assertion, which
546 * had hit some parts of the Internet in May of 2009.
547 */
548#define ASN_STR_LEN (10 + 1)
549 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
550 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000551 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000552
paulfe69a502005-09-10 16:55:02 +0000553 while (seg)
paul718e3742002-12-13 20:15:29 +0000554 {
555 int i;
paulfe69a502005-09-10 16:55:02 +0000556 char seperator;
paul718e3742002-12-13 20:15:29 +0000557
paulfe69a502005-09-10 16:55:02 +0000558 /* Check AS type validity. Set seperator for segment */
559 switch (seg->type)
560 {
561 case AS_SET:
562 case AS_CONFED_SET:
563 seperator = ',';
564 break;
565 case AS_SEQUENCE:
566 case AS_CONFED_SEQUENCE:
567 seperator = ' ';
568 break;
569 default:
570 XFREE (MTYPE_AS_STR, str_buf);
571 return NULL;
572 }
573
Denis Ovsienko014b6702009-06-23 21:10:45 +0400574 /* We might need to increase str_buf, particularly if path has
575 * differing segments types, our initial guesstimate above will
576 * have been wrong. Need 10 chars for ASN, a seperator each and
577 * potentially two segment delimiters, plus a space between each
578 * segment and trailing zero.
579 *
580 * This definitely didn't work with the value of 5 bytes and
581 * 32-bit ASNs.
582 */
583#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
584 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
585 {
586 str_size = len + SEGMENT_STR_LEN(seg);
587 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
588 }
589#undef ASN_STR_LEN
590#undef SEGMENT_STR_LEN
591
paulfe69a502005-09-10 16:55:02 +0000592 if (seg->type != AS_SEQUENCE)
Denis Ovsienko014b6702009-06-23 21:10:45 +0400593 len += snprintf (str_buf + len, str_size - len,
594 "%c",
595 aspath_delimiter_char (seg->type, AS_SEG_START));
paulfe69a502005-09-10 16:55:02 +0000596
597 /* write out the ASNs, with their seperators, bar the last one*/
598 for (i = 0; i < seg->length; i++)
599 {
600 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
601
602 if (i < (seg->length - 1))
603 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
604 }
605
606 if (seg->type != AS_SEQUENCE)
607 len += snprintf (str_buf + len, str_size - len, "%c",
608 aspath_delimiter_char (seg->type, AS_SEG_END));
609 if (seg->next)
610 len += snprintf (str_buf + len, str_size - len, " ");
611
612 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000613 }
paulfe69a502005-09-10 16:55:02 +0000614
615 assert (len < str_size);
616
617 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000618
619 return str_buf;
620}
621
paulfe69a502005-09-10 16:55:02 +0000622static void
623aspath_str_update (struct aspath *as)
624{
625 if (as->str)
626 XFREE (MTYPE_AS_STR, as->str);
627 as->str = aspath_make_str_count (as);
628}
629
paul718e3742002-12-13 20:15:29 +0000630/* Intern allocated AS path. */
631struct aspath *
632aspath_intern (struct aspath *aspath)
633{
634 struct aspath *find;
635
636 /* Assert this AS path structure is not interned. */
637 assert (aspath->refcnt == 0);
638
639 /* Check AS path hash. */
640 find = hash_get (ashash, aspath, hash_alloc_intern);
641
642 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000643 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000644
645 find->refcnt++;
646
647 if (! find->str)
648 find->str = aspath_make_str_count (find);
649
650 return find;
651}
652
653/* Duplicate aspath structure. Created same aspath structure but
654 reference count and AS path string is cleared. */
655struct aspath *
656aspath_dup (struct aspath *aspath)
657{
658 struct aspath *new;
659
paulfe69a502005-09-10 16:55:02 +0000660 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000661
paulfe69a502005-09-10 16:55:02 +0000662 if (aspath->segments)
663 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000664 else
paulfe69a502005-09-10 16:55:02 +0000665 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000666
paulfe69a502005-09-10 16:55:02 +0000667 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000668
669 return new;
670}
671
paul94f2b392005-06-28 12:44:16 +0000672static void *
paulfe69a502005-09-10 16:55:02 +0000673aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000674{
675 struct aspath *aspath;
676
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000677 /* New aspath structure is needed. */
paulfe69a502005-09-10 16:55:02 +0000678 aspath = aspath_dup (arg);
679
paul718e3742002-12-13 20:15:29 +0000680 /* Malformed AS path value. */
681 if (! aspath->str)
682 {
683 aspath_free (aspath);
684 return NULL;
685 }
686
687 return aspath;
688}
689
paulfe69a502005-09-10 16:55:02 +0000690/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000691static struct assegment *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000692assegments_parse (struct stream *s, size_t length, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000693{
694 struct assegment_header segh;
695 struct assegment *seg, *prev = NULL, *head = NULL;
696 size_t bytes = 0;
697
698 /* empty aspath (ie iBGP or somesuch) */
699 if (length == 0)
700 return NULL;
701
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000702 if (BGP_DEBUG (as4, AS4_SEGMENT))
703 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
704 (unsigned long) length);
paulfe69a502005-09-10 16:55:02 +0000705 /* basic checks */
706 if ( (STREAM_READABLE(s) < length)
707 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000708 || (length % AS16_VALUE_SIZE ))
paulfe69a502005-09-10 16:55:02 +0000709 return NULL;
710
711 while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
712 && (bytes < length))
713 {
714 int i;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000715 int seg_size;
paulfe69a502005-09-10 16:55:02 +0000716
717 /* softly softly, get the header first on its own */
718 segh.type = stream_getc (s);
719 segh.length = stream_getc (s);
720
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000721 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
722
723 if (BGP_DEBUG (as4, AS4_SEGMENT))
724 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
725 segh.type, segh.length);
726
paulfe69a502005-09-10 16:55:02 +0000727 /* check it.. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000728 if ( ((bytes + seg_size) > length)
paulfe69a502005-09-10 16:55:02 +0000729 /* 1771bis 4.3b: seg length contains one or more */
730 || (segh.length == 0)
731 /* Paranoia in case someone changes type of segment length */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000732 || ((sizeof segh.length > 1) && (segh.length > AS_SEGMENT_MAX)) )
paulfe69a502005-09-10 16:55:02 +0000733 {
734 if (head)
735 assegment_free_all (head);
736 return NULL;
737 }
738
739 /* now its safe to trust lengths */
740 seg = assegment_new (segh.type, segh.length);
741
742 if (head)
743 prev->next = seg;
744 else /* it's the first segment */
745 head = prev = seg;
746
747 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000748 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
749
750 bytes += seg_size;
paulfe69a502005-09-10 16:55:02 +0000751
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000752 if (BGP_DEBUG (as4, AS4_SEGMENT))
753 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
754 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000755
756 prev = seg;
757 }
758
759 return assegment_normalise (head);
760}
761
paul718e3742002-12-13 20:15:29 +0000762/* AS path parse function. pnt is a pointer to byte stream and length
763 is length of byte stream. If there is same AS path in the the AS
764 path hash then return it else make new AS path structure. */
765struct aspath *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000766aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000767{
768 struct aspath as;
769 struct aspath *find;
770
771 /* If length is odd it's malformed AS path. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000772 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
773 * otherwise its malformed when length is larger than 2 and (length-2)
774 * is not dividable by 4.
775 * But... this time we're lazy
776 */
777 if (length % AS16_VALUE_SIZE )
paul718e3742002-12-13 20:15:29 +0000778 return NULL;
779
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000780 memset (&as, 0, sizeof (struct aspath));
781 as.segments = assegments_parse (s, length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000782
paul718e3742002-12-13 20:15:29 +0000783 /* If already same aspath exist then return it. */
784 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000785
786 /* aspath_hash_alloc dupes segments too. that probably could be
787 * optimised out.
788 */
789 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000790 if (as.str)
791 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000792
paul718e3742002-12-13 20:15:29 +0000793 if (! find)
794 return NULL;
795 find->refcnt++;
796
797 return find;
798}
799
paulfe69a502005-09-10 16:55:02 +0000800static inline void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000801assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000802{
paulfe69a502005-09-10 16:55:02 +0000803 int i;
804 assert (num <= AS_SEGMENT_MAX);
805
806 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000807 if ( use32bit )
808 stream_putl (s, as[i]);
809 else
810 {
811 if ( as[i] <= BGP_AS_MAX )
812 stream_putw(s, as[i]);
813 else
814 stream_putw(s, BGP_AS_TRANS);
815 }
paul718e3742002-12-13 20:15:29 +0000816}
817
paulfe69a502005-09-10 16:55:02 +0000818static inline size_t
819assegment_header_put (struct stream *s, u_char type, int length)
820{
821 size_t lenp;
822 assert (length <= AS_SEGMENT_MAX);
823 stream_putc (s, type);
824 lenp = stream_get_endp (s);
825 stream_putc (s, length);
826 return lenp;
827}
828
829/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000830size_t
831aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000832{
833 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000834 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000835
836 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000837 return 0;
paulfe69a502005-09-10 16:55:02 +0000838
839 if (seg)
840 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000841 /*
842 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
843 * At the moment, we would write out a partial aspath, and our peer
844 * will complain and drop the session :-/
845 *
846 * The general assumption here is that many things tested will
847 * never happen. And, in real live, up to now, they have not.
848 */
849 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000850 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000851 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000852 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000853 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000854 size_t lenp;
855
856 /* Overlength segments have to be split up */
857 while ( (seg->length - written) > AS_SEGMENT_MAX)
858 {
859 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000860 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000861 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000862 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000863 }
864
865 /* write the final segment, probably is also the first */
866 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000867 assegment_data_put (s, (seg->as + written), seg->length - written,
868 use32bit);
paulfe69a502005-09-10 16:55:02 +0000869
870 /* Sequence-type segments can be 'packed' together
871 * Case of a segment which was overlength and split up
872 * will be missed here, but that doesn't matter.
873 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000874 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000875 {
876 /* NB: We should never normally get here given we
877 * normalise aspath data when parse them. However, better
878 * safe than sorry. We potentially could call
879 * assegment_normalise here instead, but it's cheaper and
880 * easier to do it on the fly here rather than go through
881 * the segment list twice every time we write out
882 * aspath's.
883 */
884
885 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000886 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000887
888 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000889 stream_putc_at (s, lenp, seg->length - written + next->length);
890 asns_packed += next->length;
891
892 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000893 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000894
895 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
896 use32bit);
897 seg = next;
paulfe69a502005-09-10 16:55:02 +0000898 }
899 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000900 return bytes;
paulfe69a502005-09-10 16:55:02 +0000901}
902
903/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
904 * We have no way to manage the storage, so we use a static stream
905 * wrapper around aspath_put.
906 */
907u_char *
908aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
909{
910#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000911
912 if (!snmp_stream)
913 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000914 else
paul8fdc32a2006-01-16 12:01:29 +0000915 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000916
917 if (!as)
918 {
919 *varlen = 0;
920 return NULL;
921 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000922 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000923
paul8fdc32a2006-01-16 12:01:29 +0000924 *varlen = stream_get_endp (snmp_stream);
925 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000926}
927
928#define min(A,B) ((A) < (B) ? (A) : (B))
929
paul94f2b392005-06-28 12:44:16 +0000930static struct assegment *
paul718e3742002-12-13 20:15:29 +0000931aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
932 as_t as)
933{
934 int i;
935
936 /* If this is first AS set member, create new as-set segment. */
937 if (asset == NULL)
938 {
paulfe69a502005-09-10 16:55:02 +0000939 asset = assegment_new (AS_SET, 1);
940 if (! aspath->segments)
941 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000942 else
paulfe69a502005-09-10 16:55:02 +0000943 {
944 struct assegment *seg = aspath->segments;
945 while (seg->next)
946 seg = seg->next;
947 seg->next = asset;
948 }
paul718e3742002-12-13 20:15:29 +0000949 asset->type = AS_SET;
950 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000951 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000952 }
953 else
954 {
paul718e3742002-12-13 20:15:29 +0000955 /* Check this AS value already exists or not. */
956 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000957 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000958 return asset;
paulfe69a502005-09-10 16:55:02 +0000959
paul718e3742002-12-13 20:15:29 +0000960 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000961 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
962 asset->length * AS_VALUE_SIZE);
963 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000964 }
paulfe69a502005-09-10 16:55:02 +0000965
paul718e3742002-12-13 20:15:29 +0000966
967 return asset;
968}
969
970/* Modify as1 using as2 for aggregation. */
971struct aspath *
972aspath_aggregate (struct aspath *as1, struct aspath *as2)
973{
974 int i;
975 int minlen;
976 int match;
paulfe69a502005-09-10 16:55:02 +0000977 int from;
978 struct assegment *seg1 = as1->segments;
979 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000980 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000981 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000982 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +0000983
984 match = 0;
985 minlen = 0;
986 aspath = NULL;
987 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000988
989 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000990 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000991 {
paul718e3742002-12-13 20:15:29 +0000992 /* Check segment type. */
993 if (seg1->type != seg2->type)
994 break;
995
996 /* Minimum segment length. */
997 minlen = min (seg1->length, seg2->length);
998
999 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001000 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001001 break;
1002
1003 if (match)
1004 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001005 struct assegment *seg = assegment_new (seg1->type, 0);
1006
1007 seg = assegment_append_asns (seg, seg1->as, match);
1008
paul718e3742002-12-13 20:15:29 +00001009 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001010 {
1011 aspath = aspath_new ();
1012 aspath->segments = seg;
1013 }
1014 else
1015 prevseg->next = seg;
1016
1017 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001018 }
1019
1020 if (match != minlen || match != seg1->length
1021 || seg1->length != seg2->length)
1022 break;
paulfe69a502005-09-10 16:55:02 +00001023
1024 seg1 = seg1->next;
1025 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001026 }
1027
1028 if (! aspath)
1029 aspath = aspath_new();
1030
1031 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001032 from = match;
1033 while (seg1)
paul718e3742002-12-13 20:15:29 +00001034 {
paulfe69a502005-09-10 16:55:02 +00001035 for (i = from; i < seg1->length; i++)
1036 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1037
1038 from = 0;
1039 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001040 }
1041
paulfe69a502005-09-10 16:55:02 +00001042 from = match;
1043 while (seg2)
paul718e3742002-12-13 20:15:29 +00001044 {
paulfe69a502005-09-10 16:55:02 +00001045 for (i = from; i < seg2->length; i++)
1046 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001047
paulfe69a502005-09-10 16:55:02 +00001048 from = 0;
1049 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001050 }
paulfe69a502005-09-10 16:55:02 +00001051
1052 assegment_normalise (aspath->segments);
1053 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001054 return aspath;
1055}
1056
1057/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1058 attribute, check the leftmost AS number in the AS_PATH attribute is
1059 or not the peer's AS number. */
1060int
1061aspath_firstas_check (struct aspath *aspath, as_t asno)
1062{
paulfe69a502005-09-10 16:55:02 +00001063 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001064 return 0;
paulfe69a502005-09-10 16:55:02 +00001065
1066 if (aspath->segments
1067 && (aspath->segments->type == AS_SEQUENCE)
1068 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001069 return 1;
1070
1071 return 0;
1072}
1073
Paul Jakma1f742f22006-08-06 15:52:11 +00001074/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001075int
1076aspath_loop_check (struct aspath *aspath, as_t asno)
1077{
paulfe69a502005-09-10 16:55:02 +00001078 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001079 int count = 0;
1080
Paul Jakma1f742f22006-08-06 15:52:11 +00001081 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001082 return 0;
paulfe69a502005-09-10 16:55:02 +00001083
1084 seg = aspath->segments;
1085
1086 while (seg)
paul718e3742002-12-13 20:15:29 +00001087 {
1088 int i;
paul718e3742002-12-13 20:15:29 +00001089
paulfe69a502005-09-10 16:55:02 +00001090 for (i = 0; i < seg->length; i++)
1091 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001092 count++;
paulfe69a502005-09-10 16:55:02 +00001093
1094 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001095 }
1096 return count;
1097}
1098
1099/* When all of AS path is private AS return 1. */
1100int
1101aspath_private_as_check (struct aspath *aspath)
1102{
paulfe69a502005-09-10 16:55:02 +00001103 struct assegment *seg;
1104
1105 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001106 return 0;
paulfe69a502005-09-10 16:55:02 +00001107
1108 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001109
paulfe69a502005-09-10 16:55:02 +00001110 while (seg)
paul718e3742002-12-13 20:15:29 +00001111 {
1112 int i;
paul718e3742002-12-13 20:15:29 +00001113
paulfe69a502005-09-10 16:55:02 +00001114 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001115 {
paulfe69a502005-09-10 16:55:02 +00001116 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1117 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001118 return 0;
1119 }
paulfe69a502005-09-10 16:55:02 +00001120 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001121 }
1122 return 1;
1123}
1124
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001125/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1126int
1127aspath_confed_check (struct aspath *aspath)
1128{
1129 struct assegment *seg;
1130
1131 if ( !(aspath && aspath->segments) )
1132 return 0;
1133
1134 seg = aspath->segments;
1135
1136 while (seg)
1137 {
1138 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1139 return 1;
1140 seg = seg->next;
1141 }
1142 return 0;
1143}
1144
1145/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1146 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1147int
1148aspath_left_confed_check (struct aspath *aspath)
1149{
1150
1151 if ( !(aspath && aspath->segments) )
1152 return 0;
1153
1154 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1155 || (aspath->segments->type == AS_CONFED_SET) )
1156 return 1;
1157
1158 return 0;
1159}
1160
paul718e3742002-12-13 20:15:29 +00001161/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001162static struct aspath *
paul718e3742002-12-13 20:15:29 +00001163aspath_merge (struct aspath *as1, struct aspath *as2)
1164{
paulfe69a502005-09-10 16:55:02 +00001165 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001166
1167 if (! as1 || ! as2)
1168 return NULL;
1169
paulfe69a502005-09-10 16:55:02 +00001170 last = new = assegment_dup_all (as1->segments);
1171
1172 /* find the last valid segment */
1173 while (last && last->next)
1174 last = last->next;
1175
1176 last->next = as2->segments;
1177 as2->segments = new;
1178 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001179 return as2;
1180}
1181
1182/* Prepend as1 to as2. as2 should be uninterned aspath. */
1183struct aspath *
1184aspath_prepend (struct aspath *as1, struct aspath *as2)
1185{
paulfe69a502005-09-10 16:55:02 +00001186 struct assegment *seg1;
1187 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001188
1189 if (! as1 || ! as2)
1190 return NULL;
paulfe69a502005-09-10 16:55:02 +00001191
1192 seg1 = as1->segments;
1193 seg2 = as2->segments;
1194
1195 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001196 if (seg2 == NULL)
1197 {
paulfe69a502005-09-10 16:55:02 +00001198 as2->segments = assegment_dup_all (as1->segments);
1199 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001200 return as2;
1201 }
paulfe69a502005-09-10 16:55:02 +00001202
1203 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001204 if (seg1 == NULL)
1205 return as2;
paulfe69a502005-09-10 16:55:02 +00001206
1207 /* find the tail as1's segment chain. */
1208 while (seg1 && seg1->next)
1209 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001210
1211 /* Compare last segment type of as1 and first segment type of as2. */
1212 if (seg1->type != seg2->type)
1213 return aspath_merge (as1, as2);
1214
1215 if (seg1->type == AS_SEQUENCE)
1216 {
paulfe69a502005-09-10 16:55:02 +00001217 /* We have two chains of segments, as1->segments and seg2,
1218 * and we have to attach them together, merging the attaching
1219 * segments together into one.
1220 *
1221 * 1. dupe as1->segments onto head of as2
1222 * 2. merge seg2's asns onto last segment of this new chain
1223 * 3. attach chain after seg2
1224 */
paul718e3742002-12-13 20:15:29 +00001225
paulfe69a502005-09-10 16:55:02 +00001226 /* dupe as1 onto as2's head */
1227 seg1 = as2->segments = assegment_dup_all (as1->segments);
1228
1229 /* refind the tail of as2, reusing seg1 */
1230 while (seg1 && seg1->next)
1231 seg1 = seg1->next;
1232
1233 /* merge the old head, seg2, into tail, seg1 */
1234 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1235
1236 /* bypass the merged seg2, and attach any chain after it to
1237 * chain descending from as2's head
1238 */
1239 seg1->next = seg2->next;
1240
1241 /* seg2 is now referenceless and useless*/
1242 assegment_free (seg2);
1243
1244 /* we've now prepended as1's segment chain to as2, merging
1245 * the inbetween AS_SEQUENCE of seg2 in the process
1246 */
1247 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001248 return as2;
1249 }
1250 else
1251 {
1252 /* AS_SET merge code is needed at here. */
1253 return aspath_merge (as1, as2);
1254 }
paulfe69a502005-09-10 16:55:02 +00001255 /* XXX: Ermmm, what if as1 has multiple segments?? */
1256
paul718e3742002-12-13 20:15:29 +00001257 /* Not reached */
1258}
1259
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001260/* Iterate over AS_PATH segments and wipe all occurences of the
1261 * listed AS numbers. Hence some segments may lose some or even
1262 * all data on the way, the operation is implemented as a smarter
1263 * version of aspath_dup(), which allocates memory to hold the new
1264 * data, not the original. The new AS path is returned.
1265 */
1266struct aspath *
1267aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1268{
1269 struct assegment * srcseg, * exclseg, * lastseg;
1270 struct aspath * newpath;
1271
1272 newpath = aspath_new();
1273 lastseg = NULL;
1274
1275 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1276 {
1277 unsigned i, y, newlen = 0, done = 0, skip_as;
1278 struct assegment * newseg;
1279
1280 /* Find out, how much ASns are we going to pick from this segment.
1281 * We can't perform filtering right inline, because the size of
1282 * the new segment isn't known at the moment yet.
1283 */
1284 for (i = 0; i < srcseg->length; i++)
1285 {
1286 skip_as = 0;
1287 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1288 for (y = 0; y < exclseg->length; y++)
1289 if (srcseg->as[i] == exclseg->as[y])
1290 {
1291 skip_as = 1;
1292 // There's no sense in testing the rest of exclusion list, bail out.
1293 break;
1294 }
1295 if (!skip_as)
1296 newlen++;
1297 }
1298 /* newlen is now the number of ASns to copy */
1299 if (!newlen)
1300 continue;
1301
1302 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1303 newseg = assegment_new (srcseg->type, newlen);
1304 for (i = 0; i < srcseg->length; i++)
1305 {
1306 skip_as = 0;
1307 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1308 for (y = 0; y < exclseg->length; y++)
1309 if (srcseg->as[i] == exclseg->as[y])
1310 {
1311 skip_as = 1;
1312 break;
1313 }
1314 if (skip_as)
1315 continue;
1316 newseg->as[done++] = srcseg->as[i];
1317 }
1318 /* At his point newlen must be equal to done, and both must be positive. Append
1319 * the filtered segment to the gross result. */
1320 if (!lastseg)
1321 newpath->segments = newseg;
1322 else
1323 lastseg->next = newseg;
1324 lastseg = newseg;
1325 }
1326 aspath_str_update (newpath);
1327 /* We are happy returning even an empty AS_PATH, because the administrator
1328 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1329 * by having a match rule against certain AS_PATH regexps in the route-map index.
1330 */
1331 aspath_free (source);
1332 return newpath;
1333}
1334
paul718e3742002-12-13 20:15:29 +00001335/* Add specified AS to the leftmost of aspath. */
1336static struct aspath *
1337aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1338{
paulfe69a502005-09-10 16:55:02 +00001339 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001340
1341 /* In case of empty aspath. */
1342 if (assegment == NULL || assegment->length == 0)
1343 {
paulfe69a502005-09-10 16:55:02 +00001344 aspath->segments = assegment_new (type, 1);
1345 aspath->segments->as[0] = asno;
1346
paul718e3742002-12-13 20:15:29 +00001347 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001348 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001349
1350 return aspath;
1351 }
1352
1353 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001354 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1355 else
paul718e3742002-12-13 20:15:29 +00001356 {
paulfe69a502005-09-10 16:55:02 +00001357 /* create new segment
1358 * push it onto head of aspath's segment chain
1359 */
paul718e3742002-12-13 20:15:29 +00001360 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001361
1362 newsegment = assegment_new (type, 1);
1363 newsegment->as[0] = asno;
1364
1365 newsegment->next = assegment;
1366 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001367 }
1368
1369 return aspath;
1370}
1371
1372/* Add specified AS to the leftmost of aspath. */
1373struct aspath *
1374aspath_add_seq (struct aspath *aspath, as_t asno)
1375{
1376 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1377}
1378
1379/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1380 as2's leftmost AS is same return 1. */
1381int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001382aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001383{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001384 const struct assegment *seg1 = NULL;
1385 const struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001386
paulfe69a502005-09-10 16:55:02 +00001387 if (!(aspath1 && aspath2))
1388 return 0;
paul718e3742002-12-13 20:15:29 +00001389
paulfe69a502005-09-10 16:55:02 +00001390 seg1 = aspath1->segments;
1391 seg2 = aspath2->segments;
1392
1393 /* find first non-confed segments for each */
1394 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1395 || (seg1->type == AS_CONFED_SET)))
1396 seg1 = seg1->next;
1397
1398 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1399 || (seg2->type == AS_CONFED_SET)))
1400 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001401
1402 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001403 if (!(seg1 && seg2
1404 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001405 return 0;
paulfe69a502005-09-10 16:55:02 +00001406
1407 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001408 return 1;
1409
1410 return 0;
1411}
1412
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001413/* Truncate an aspath after a number of hops, and put the hops remaining
1414 * at the front of another aspath. Needed for AS4 compat.
1415 *
1416 * Returned aspath is a /new/ aspath, which should either by free'd or
1417 * interned by the caller, as desired.
1418 */
1419struct aspath *
1420aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1421{
1422 struct assegment *seg, *newseg, *prevseg = NULL;
1423 struct aspath *newpath = NULL, *mergedpath;
1424 int hops, cpasns = 0;
1425
1426 if (!aspath)
1427 return NULL;
1428
1429 seg = aspath->segments;
1430
1431 /* CONFEDs should get reconciled too.. */
1432 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1433 - aspath_count_hops (as4path);
1434
1435 if (hops < 0)
1436 {
1437 if (BGP_DEBUG (as4, AS4))
1438 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1439 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1440 * which is daft behaviour - it contains vital loop-detection
1441 * information which must have been removed from AS_PATH.
1442 */
1443 hops = aspath_count_hops (aspath);
1444 }
1445
1446 if (!hops)
1447 return aspath_dup (as4path);
1448
1449 if ( BGP_DEBUG(as4, AS4))
1450 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1451 aspath->str, as4path->str);
1452
1453 while (seg && hops > 0)
1454 {
1455 switch (seg->type)
1456 {
1457 case AS_SET:
1458 case AS_CONFED_SET:
1459 hops--;
1460 cpasns = seg->length;
1461 break;
1462 case AS_CONFED_SEQUENCE:
1463 /* Should never split a confed-sequence, if hop-count
1464 * suggests we must then something's gone wrong somewhere.
1465 *
1466 * Most important goal is to preserve AS_PATHs prime function
1467 * as loop-detector, so we fudge the numbers so that the entire
1468 * confed-sequence is merged in.
1469 */
1470 if (hops < seg->length)
1471 {
1472 if (BGP_DEBUG (as4, AS4))
1473 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1474 " across 2/4 ASN boundary somewhere, broken..");
1475 hops = seg->length;
1476 }
1477 case AS_SEQUENCE:
1478 cpasns = MIN(seg->length, hops);
1479 hops -= seg->length;
1480 }
1481
1482 assert (cpasns <= seg->length);
1483
1484 newseg = assegment_new (seg->type, 0);
1485 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1486
1487 if (!newpath)
1488 {
1489 newpath = aspath_new ();
1490 newpath->segments = newseg;
1491 }
1492 else
1493 prevseg->next = newseg;
1494
1495 prevseg = newseg;
1496 seg = seg->next;
1497 }
1498
1499 /* We may be able to join some segments here, and we must
1500 * do this because... we want normalised aspaths in out hash
1501 * and we do not want to stumble in aspath_put.
1502 */
1503 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1504 aspath_free (newpath);
1505 mergedpath->segments = assegment_normalise (mergedpath->segments);
1506 aspath_str_update (mergedpath);
1507
1508 if ( BGP_DEBUG(as4, AS4))
1509 zlog_debug ("[AS4] result of synthesizing is %s",
1510 mergedpath->str);
1511
1512 return mergedpath;
1513}
1514
paul718e3742002-12-13 20:15:29 +00001515/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1516 as2's leftmost AS is same return 1. (confederation as-path
1517 only). */
1518int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001519aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001520{
paulfe69a502005-09-10 16:55:02 +00001521 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001522 return 0;
paulfe69a502005-09-10 16:55:02 +00001523
paulad727402005-11-23 02:47:02 +00001524 if ( !(aspath1->segments && aspath2->segments) )
1525 return 0;
1526
paulfe69a502005-09-10 16:55:02 +00001527 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1528 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001529 return 0;
paulfe69a502005-09-10 16:55:02 +00001530
1531 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001532 return 1;
1533
1534 return 0;
1535}
1536
paulfe69a502005-09-10 16:55:02 +00001537/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1538 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001539struct aspath *
1540aspath_delete_confed_seq (struct aspath *aspath)
1541{
paulfe69a502005-09-10 16:55:02 +00001542 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001543
paulfe69a502005-09-10 16:55:02 +00001544 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001545 return aspath;
1546
paulfe69a502005-09-10 16:55:02 +00001547 seg = aspath->segments;
1548
1549 /* "if the first path segment of the AS_PATH is
1550 * of type AS_CONFED_SEQUENCE,"
1551 */
1552 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1553 return aspath;
paul718e3742002-12-13 20:15:29 +00001554
paulfe69a502005-09-10 16:55:02 +00001555 /* "... that segment and any immediately following segments
1556 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1557 * from the AS_PATH attribute,"
1558 */
1559 while (seg &&
1560 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001561 {
paulfe69a502005-09-10 16:55:02 +00001562 aspath->segments = seg->next;
1563 assegment_free (seg);
1564 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001565 }
paulfe69a502005-09-10 16:55:02 +00001566 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001567 return aspath;
1568}
1569
1570/* Add new AS number to the leftmost part of the aspath as
1571 AS_CONFED_SEQUENCE. */
1572struct aspath*
1573aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1574{
1575 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1576}
1577
1578/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001579static void
paul718e3742002-12-13 20:15:29 +00001580aspath_as_add (struct aspath *as, as_t asno)
1581{
paulfe69a502005-09-10 16:55:02 +00001582 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001583
paulfe69a502005-09-10 16:55:02 +00001584 if (!seg)
1585 return;
1586
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001587 /* Last segment search procedure. */
1588 while (seg->next)
1589 seg = seg->next;
1590
paulfe69a502005-09-10 16:55:02 +00001591 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001592}
1593
1594/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001595static void
paul718e3742002-12-13 20:15:29 +00001596aspath_segment_add (struct aspath *as, int type)
1597{
paulfe69a502005-09-10 16:55:02 +00001598 struct assegment *seg = as->segments;
1599 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001600
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001601 if (seg)
1602 {
1603 while (seg->next)
1604 seg = seg->next;
1605 seg->next = new;
1606 }
paul718e3742002-12-13 20:15:29 +00001607 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001608 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001609}
1610
1611struct aspath *
paul94f2b392005-06-28 12:44:16 +00001612aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001613{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001614 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001615}
1616
1617struct aspath *
paul94f2b392005-06-28 12:44:16 +00001618aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001619{
1620 struct aspath *aspath;
1621
1622 aspath = aspath_new ();
1623 aspath->str = aspath_make_str_count (aspath);
1624 return aspath;
1625}
1626
1627unsigned long
paulfe69a502005-09-10 16:55:02 +00001628aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001629{
1630 return ashash->count;
1631}
1632
1633/*
1634 Theoretically, one as path can have:
1635
1636 One BGP packet size should be less than 4096.
1637 One BGP attribute size should be less than 4096 - BGP header size.
1638 One BGP aspath size should be less than 4096 - BGP header size -
1639 BGP mandantry attribute size.
1640*/
1641
1642/* AS path string lexical token enum. */
1643enum as_token
1644{
1645 as_token_asval,
1646 as_token_set_start,
1647 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001648 as_token_confed_seq_start,
1649 as_token_confed_seq_end,
1650 as_token_confed_set_start,
1651 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001652 as_token_unknown
1653};
1654
1655/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001656static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001657aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001658{
paulfd79ac92004-10-13 05:06:08 +00001659 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001660
paulfe69a502005-09-10 16:55:02 +00001661 /* Skip seperators (space for sequences, ',' for sets). */
1662 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001663 p++;
1664
1665 /* Check the end of the string and type specify characters
1666 (e.g. {}()). */
1667 switch (*p)
1668 {
1669 case '\0':
1670 return NULL;
paul718e3742002-12-13 20:15:29 +00001671 case '{':
1672 *token = as_token_set_start;
1673 p++;
1674 return p;
paul718e3742002-12-13 20:15:29 +00001675 case '}':
1676 *token = as_token_set_end;
1677 p++;
1678 return p;
paul718e3742002-12-13 20:15:29 +00001679 case '(':
paulfe69a502005-09-10 16:55:02 +00001680 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001681 p++;
1682 return p;
paul718e3742002-12-13 20:15:29 +00001683 case ')':
paulfe69a502005-09-10 16:55:02 +00001684 *token = as_token_confed_seq_end;
1685 p++;
1686 return p;
paulfe69a502005-09-10 16:55:02 +00001687 case '[':
1688 *token = as_token_confed_set_start;
1689 p++;
1690 return p;
paulfe69a502005-09-10 16:55:02 +00001691 case ']':
1692 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001693 p++;
1694 return p;
paul718e3742002-12-13 20:15:29 +00001695 }
1696
1697 /* Check actual AS value. */
1698 if (isdigit ((int) *p))
1699 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001700 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001701
paul718e3742002-12-13 20:15:29 +00001702 *token = as_token_asval;
1703 asval = (*p - '0');
1704 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001705
paul718e3742002-12-13 20:15:29 +00001706 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001707 {
1708 asval *= 10;
1709 asval += (*p - '0');
1710 p++;
1711 }
paul718e3742002-12-13 20:15:29 +00001712 *asno = asval;
1713 return p;
1714 }
1715
1716 /* There is no match then return unknown token. */
1717 *token = as_token_unknown;
1718 return p++;
1719}
1720
1721struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001722aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001723{
paul3fff6ff2006-02-05 17:55:35 +00001724 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001725 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001726 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001727 struct aspath *aspath;
1728 int needtype;
1729
1730 aspath = aspath_new ();
1731
1732 /* We start default type as AS_SEQUENCE. */
1733 as_type = AS_SEQUENCE;
1734 needtype = 1;
1735
1736 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1737 {
1738 switch (token)
1739 {
1740 case as_token_asval:
1741 if (needtype)
1742 {
1743 aspath_segment_add (aspath, as_type);
1744 needtype = 0;
1745 }
1746 aspath_as_add (aspath, asno);
1747 break;
1748 case as_token_set_start:
1749 as_type = AS_SET;
1750 aspath_segment_add (aspath, as_type);
1751 needtype = 0;
1752 break;
1753 case as_token_set_end:
1754 as_type = AS_SEQUENCE;
1755 needtype = 1;
1756 break;
paulfe69a502005-09-10 16:55:02 +00001757 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001758 as_type = AS_CONFED_SEQUENCE;
1759 aspath_segment_add (aspath, as_type);
1760 needtype = 0;
1761 break;
paulfe69a502005-09-10 16:55:02 +00001762 case as_token_confed_seq_end:
1763 as_type = AS_SEQUENCE;
1764 needtype = 1;
1765 break;
1766 case as_token_confed_set_start:
1767 as_type = AS_CONFED_SET;
1768 aspath_segment_add (aspath, as_type);
1769 needtype = 0;
1770 break;
1771 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001772 as_type = AS_SEQUENCE;
1773 needtype = 1;
1774 break;
1775 case as_token_unknown:
1776 default:
paulfe69a502005-09-10 16:55:02 +00001777 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001778 return NULL;
paul718e3742002-12-13 20:15:29 +00001779 }
1780 }
1781
1782 aspath->str = aspath_make_str_count (aspath);
1783
1784 return aspath;
1785}
1786
1787/* Make hash value by raw aspath data. */
1788unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001789aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001790{
Paul Jakma923de652007-04-29 18:25:17 +00001791 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001792 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001793
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001794 if (!aspath->str)
1795 aspath_str_update (aspath);
1796
1797 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001798
1799 return key;
1800}
1801
1802/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001803static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001804aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001805{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001806 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1807 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001808
1809 while (seg1 || seg2)
1810 {
1811 int i;
1812 if ((!seg1 && seg2) || (seg1 && !seg2))
1813 return 0;
1814 if (seg1->type != seg2->type)
1815 return 0;
1816 if (seg1->length != seg2->length)
1817 return 0;
1818 for (i = 0; i < seg1->length; i++)
1819 if (seg1->as[i] != seg2->as[i])
1820 return 0;
1821 seg1 = seg1->next;
1822 seg2 = seg2->next;
1823 }
1824 return 1;
paul718e3742002-12-13 20:15:29 +00001825}
1826
1827/* AS path hash initialize. */
1828void
paul94f2b392005-06-28 12:44:16 +00001829aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001830{
1831 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1832}
paul8fdc32a2006-01-16 12:01:29 +00001833
1834void
1835aspath_finish (void)
1836{
1837 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00001838 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00001839
1840 if (snmp_stream)
1841 stream_free (snmp_stream);
1842}
paul718e3742002-12-13 20:15:29 +00001843
1844/* return and as path value */
1845const char *
1846aspath_print (struct aspath *as)
1847{
paulfe69a502005-09-10 16:55:02 +00001848 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001849}
1850
1851/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001852/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1853 * AS_PATH wasn't empty.
1854 */
paul718e3742002-12-13 20:15:29 +00001855void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001856aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001857{
Paul Jakmab2518c12006-05-12 23:48:40 +00001858 assert (format);
1859 vty_out (vty, format, as->str);
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001860 if (strlen (as->str) && strlen (suffix))
1861 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001862}
1863
paul94f2b392005-06-28 12:44:16 +00001864static void
paul718e3742002-12-13 20:15:29 +00001865aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1866{
1867 struct aspath *as;
1868
1869 as = (struct aspath *) backet->data;
1870
paulefa9f832002-12-13 21:47:59 +00001871 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001872 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1873}
1874
1875/* Print all aspath and hash information. This function is used from
1876 `show ip bgp paths' command. */
1877void
1878aspath_print_all_vty (struct vty *vty)
1879{
1880 hash_iterate (ashash,
1881 (void (*) (struct hash_backet *, void *))
1882 aspath_show_all_iterator,
1883 vty);
1884}