blob: 3c8032f8d1f3065bba3c5c07fb4c830b9a6e3857 [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)
Denis Ovsienko2eb445e2009-12-04 17:32:54 +0300731 /* Paranoia in case someone changes type of segment length.
732 * Shift both values by 0x10 to make the comparison operate
733 * on more, than 8 bits (otherwise it's a warning, bug #564).
734 */
735 || ((sizeof segh.length > 1) && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)) )
paulfe69a502005-09-10 16:55:02 +0000736 {
737 if (head)
738 assegment_free_all (head);
739 return NULL;
740 }
741
742 /* now its safe to trust lengths */
743 seg = assegment_new (segh.type, segh.length);
744
745 if (head)
746 prev->next = seg;
747 else /* it's the first segment */
748 head = prev = seg;
749
750 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000751 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
752
753 bytes += seg_size;
paulfe69a502005-09-10 16:55:02 +0000754
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000755 if (BGP_DEBUG (as4, AS4_SEGMENT))
756 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
757 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000758
759 prev = seg;
760 }
761
762 return assegment_normalise (head);
763}
764
paul718e3742002-12-13 20:15:29 +0000765/* AS path parse function. pnt is a pointer to byte stream and length
766 is length of byte stream. If there is same AS path in the the AS
767 path hash then return it else make new AS path structure. */
768struct aspath *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000769aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000770{
771 struct aspath as;
772 struct aspath *find;
773
774 /* If length is odd it's malformed AS path. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000775 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
776 * otherwise its malformed when length is larger than 2 and (length-2)
777 * is not dividable by 4.
778 * But... this time we're lazy
779 */
780 if (length % AS16_VALUE_SIZE )
paul718e3742002-12-13 20:15:29 +0000781 return NULL;
782
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000783 memset (&as, 0, sizeof (struct aspath));
784 as.segments = assegments_parse (s, length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000785
paul718e3742002-12-13 20:15:29 +0000786 /* If already same aspath exist then return it. */
787 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000788
789 /* aspath_hash_alloc dupes segments too. that probably could be
790 * optimised out.
791 */
792 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000793 if (as.str)
794 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000795
paul718e3742002-12-13 20:15:29 +0000796 if (! find)
797 return NULL;
798 find->refcnt++;
799
800 return find;
801}
802
paulfe69a502005-09-10 16:55:02 +0000803static inline void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000804assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000805{
paulfe69a502005-09-10 16:55:02 +0000806 int i;
807 assert (num <= AS_SEGMENT_MAX);
808
809 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000810 if ( use32bit )
811 stream_putl (s, as[i]);
812 else
813 {
814 if ( as[i] <= BGP_AS_MAX )
815 stream_putw(s, as[i]);
816 else
817 stream_putw(s, BGP_AS_TRANS);
818 }
paul718e3742002-12-13 20:15:29 +0000819}
820
paulfe69a502005-09-10 16:55:02 +0000821static inline size_t
822assegment_header_put (struct stream *s, u_char type, int length)
823{
824 size_t lenp;
825 assert (length <= AS_SEGMENT_MAX);
826 stream_putc (s, type);
827 lenp = stream_get_endp (s);
828 stream_putc (s, length);
829 return lenp;
830}
831
832/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000833size_t
834aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000835{
836 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000837 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000838
839 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000840 return 0;
paulfe69a502005-09-10 16:55:02 +0000841
842 if (seg)
843 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000844 /*
845 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
846 * At the moment, we would write out a partial aspath, and our peer
847 * will complain and drop the session :-/
848 *
849 * The general assumption here is that many things tested will
850 * never happen. And, in real live, up to now, they have not.
851 */
852 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000853 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000854 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000855 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000856 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000857 size_t lenp;
858
859 /* Overlength segments have to be split up */
860 while ( (seg->length - written) > AS_SEGMENT_MAX)
861 {
862 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000863 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000864 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000865 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000866 }
867
868 /* write the final segment, probably is also the first */
869 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000870 assegment_data_put (s, (seg->as + written), seg->length - written,
871 use32bit);
paulfe69a502005-09-10 16:55:02 +0000872
873 /* Sequence-type segments can be 'packed' together
874 * Case of a segment which was overlength and split up
875 * will be missed here, but that doesn't matter.
876 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000877 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000878 {
879 /* NB: We should never normally get here given we
880 * normalise aspath data when parse them. However, better
881 * safe than sorry. We potentially could call
882 * assegment_normalise here instead, but it's cheaper and
883 * easier to do it on the fly here rather than go through
884 * the segment list twice every time we write out
885 * aspath's.
886 */
887
888 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000889 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000890
891 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000892 stream_putc_at (s, lenp, seg->length - written + next->length);
893 asns_packed += next->length;
894
895 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000896 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000897
898 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
899 use32bit);
900 seg = next;
paulfe69a502005-09-10 16:55:02 +0000901 }
902 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000903 return bytes;
paulfe69a502005-09-10 16:55:02 +0000904}
905
906/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
907 * We have no way to manage the storage, so we use a static stream
908 * wrapper around aspath_put.
909 */
910u_char *
911aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
912{
913#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000914
915 if (!snmp_stream)
916 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000917 else
paul8fdc32a2006-01-16 12:01:29 +0000918 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000919
920 if (!as)
921 {
922 *varlen = 0;
923 return NULL;
924 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000925 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000926
paul8fdc32a2006-01-16 12:01:29 +0000927 *varlen = stream_get_endp (snmp_stream);
928 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000929}
930
931#define min(A,B) ((A) < (B) ? (A) : (B))
932
paul94f2b392005-06-28 12:44:16 +0000933static struct assegment *
paul718e3742002-12-13 20:15:29 +0000934aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
935 as_t as)
936{
937 int i;
938
939 /* If this is first AS set member, create new as-set segment. */
940 if (asset == NULL)
941 {
paulfe69a502005-09-10 16:55:02 +0000942 asset = assegment_new (AS_SET, 1);
943 if (! aspath->segments)
944 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000945 else
paulfe69a502005-09-10 16:55:02 +0000946 {
947 struct assegment *seg = aspath->segments;
948 while (seg->next)
949 seg = seg->next;
950 seg->next = asset;
951 }
paul718e3742002-12-13 20:15:29 +0000952 asset->type = AS_SET;
953 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000954 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000955 }
956 else
957 {
paul718e3742002-12-13 20:15:29 +0000958 /* Check this AS value already exists or not. */
959 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000960 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000961 return asset;
paulfe69a502005-09-10 16:55:02 +0000962
paul718e3742002-12-13 20:15:29 +0000963 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000964 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
965 asset->length * AS_VALUE_SIZE);
966 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000967 }
paulfe69a502005-09-10 16:55:02 +0000968
paul718e3742002-12-13 20:15:29 +0000969
970 return asset;
971}
972
973/* Modify as1 using as2 for aggregation. */
974struct aspath *
975aspath_aggregate (struct aspath *as1, struct aspath *as2)
976{
977 int i;
978 int minlen;
979 int match;
paulfe69a502005-09-10 16:55:02 +0000980 int from;
981 struct assegment *seg1 = as1->segments;
982 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000983 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000984 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000985 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +0000986
987 match = 0;
988 minlen = 0;
989 aspath = NULL;
990 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000991
992 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000993 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000994 {
paul718e3742002-12-13 20:15:29 +0000995 /* Check segment type. */
996 if (seg1->type != seg2->type)
997 break;
998
999 /* Minimum segment length. */
1000 minlen = min (seg1->length, seg2->length);
1001
1002 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001003 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001004 break;
1005
1006 if (match)
1007 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001008 struct assegment *seg = assegment_new (seg1->type, 0);
1009
1010 seg = assegment_append_asns (seg, seg1->as, match);
1011
paul718e3742002-12-13 20:15:29 +00001012 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001013 {
1014 aspath = aspath_new ();
1015 aspath->segments = seg;
1016 }
1017 else
1018 prevseg->next = seg;
1019
1020 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001021 }
1022
1023 if (match != minlen || match != seg1->length
1024 || seg1->length != seg2->length)
1025 break;
paulfe69a502005-09-10 16:55:02 +00001026
1027 seg1 = seg1->next;
1028 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001029 }
1030
1031 if (! aspath)
1032 aspath = aspath_new();
1033
1034 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001035 from = match;
1036 while (seg1)
paul718e3742002-12-13 20:15:29 +00001037 {
paulfe69a502005-09-10 16:55:02 +00001038 for (i = from; i < seg1->length; i++)
1039 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1040
1041 from = 0;
1042 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001043 }
1044
paulfe69a502005-09-10 16:55:02 +00001045 from = match;
1046 while (seg2)
paul718e3742002-12-13 20:15:29 +00001047 {
paulfe69a502005-09-10 16:55:02 +00001048 for (i = from; i < seg2->length; i++)
1049 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001050
paulfe69a502005-09-10 16:55:02 +00001051 from = 0;
1052 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001053 }
paulfe69a502005-09-10 16:55:02 +00001054
1055 assegment_normalise (aspath->segments);
1056 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001057 return aspath;
1058}
1059
1060/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1061 attribute, check the leftmost AS number in the AS_PATH attribute is
1062 or not the peer's AS number. */
1063int
1064aspath_firstas_check (struct aspath *aspath, as_t asno)
1065{
paulfe69a502005-09-10 16:55:02 +00001066 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001067 return 0;
paulfe69a502005-09-10 16:55:02 +00001068
1069 if (aspath->segments
1070 && (aspath->segments->type == AS_SEQUENCE)
1071 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001072 return 1;
1073
1074 return 0;
1075}
1076
Paul Jakma1f742f22006-08-06 15:52:11 +00001077/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001078int
1079aspath_loop_check (struct aspath *aspath, as_t asno)
1080{
paulfe69a502005-09-10 16:55:02 +00001081 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001082 int count = 0;
1083
Paul Jakma1f742f22006-08-06 15:52:11 +00001084 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001085 return 0;
paulfe69a502005-09-10 16:55:02 +00001086
1087 seg = aspath->segments;
1088
1089 while (seg)
paul718e3742002-12-13 20:15:29 +00001090 {
1091 int i;
paul718e3742002-12-13 20:15:29 +00001092
paulfe69a502005-09-10 16:55:02 +00001093 for (i = 0; i < seg->length; i++)
1094 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001095 count++;
paulfe69a502005-09-10 16:55:02 +00001096
1097 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001098 }
1099 return count;
1100}
1101
1102/* When all of AS path is private AS return 1. */
1103int
1104aspath_private_as_check (struct aspath *aspath)
1105{
paulfe69a502005-09-10 16:55:02 +00001106 struct assegment *seg;
1107
1108 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001109 return 0;
paulfe69a502005-09-10 16:55:02 +00001110
1111 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001112
paulfe69a502005-09-10 16:55:02 +00001113 while (seg)
paul718e3742002-12-13 20:15:29 +00001114 {
1115 int i;
paul718e3742002-12-13 20:15:29 +00001116
paulfe69a502005-09-10 16:55:02 +00001117 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001118 {
paulfe69a502005-09-10 16:55:02 +00001119 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1120 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001121 return 0;
1122 }
paulfe69a502005-09-10 16:55:02 +00001123 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001124 }
1125 return 1;
1126}
1127
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001128/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1129int
1130aspath_confed_check (struct aspath *aspath)
1131{
1132 struct assegment *seg;
1133
1134 if ( !(aspath && aspath->segments) )
1135 return 0;
1136
1137 seg = aspath->segments;
1138
1139 while (seg)
1140 {
1141 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1142 return 1;
1143 seg = seg->next;
1144 }
1145 return 0;
1146}
1147
1148/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1149 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1150int
1151aspath_left_confed_check (struct aspath *aspath)
1152{
1153
1154 if ( !(aspath && aspath->segments) )
1155 return 0;
1156
1157 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1158 || (aspath->segments->type == AS_CONFED_SET) )
1159 return 1;
1160
1161 return 0;
1162}
1163
paul718e3742002-12-13 20:15:29 +00001164/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001165static struct aspath *
paul718e3742002-12-13 20:15:29 +00001166aspath_merge (struct aspath *as1, struct aspath *as2)
1167{
paulfe69a502005-09-10 16:55:02 +00001168 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001169
1170 if (! as1 || ! as2)
1171 return NULL;
1172
paulfe69a502005-09-10 16:55:02 +00001173 last = new = assegment_dup_all (as1->segments);
1174
1175 /* find the last valid segment */
1176 while (last && last->next)
1177 last = last->next;
1178
1179 last->next = as2->segments;
1180 as2->segments = new;
1181 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001182 return as2;
1183}
1184
1185/* Prepend as1 to as2. as2 should be uninterned aspath. */
1186struct aspath *
1187aspath_prepend (struct aspath *as1, struct aspath *as2)
1188{
paulfe69a502005-09-10 16:55:02 +00001189 struct assegment *seg1;
1190 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001191
1192 if (! as1 || ! as2)
1193 return NULL;
paulfe69a502005-09-10 16:55:02 +00001194
1195 seg1 = as1->segments;
1196 seg2 = as2->segments;
1197
1198 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001199 if (seg2 == NULL)
1200 {
paulfe69a502005-09-10 16:55:02 +00001201 as2->segments = assegment_dup_all (as1->segments);
1202 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001203 return as2;
1204 }
paulfe69a502005-09-10 16:55:02 +00001205
1206 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001207 if (seg1 == NULL)
1208 return as2;
paulfe69a502005-09-10 16:55:02 +00001209
1210 /* find the tail as1's segment chain. */
1211 while (seg1 && seg1->next)
1212 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001213
Vasilis Tsiligiannis736d4402009-07-20 01:59:10 +03001214 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1215 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1216 as2 = aspath_delete_confed_seq (as2);
1217
paul718e3742002-12-13 20:15:29 +00001218 /* Compare last segment type of as1 and first segment type of as2. */
1219 if (seg1->type != seg2->type)
1220 return aspath_merge (as1, as2);
1221
1222 if (seg1->type == AS_SEQUENCE)
1223 {
paulfe69a502005-09-10 16:55:02 +00001224 /* We have two chains of segments, as1->segments and seg2,
1225 * and we have to attach them together, merging the attaching
1226 * segments together into one.
1227 *
1228 * 1. dupe as1->segments onto head of as2
1229 * 2. merge seg2's asns onto last segment of this new chain
1230 * 3. attach chain after seg2
1231 */
paul718e3742002-12-13 20:15:29 +00001232
paulfe69a502005-09-10 16:55:02 +00001233 /* dupe as1 onto as2's head */
1234 seg1 = as2->segments = assegment_dup_all (as1->segments);
1235
1236 /* refind the tail of as2, reusing seg1 */
1237 while (seg1 && seg1->next)
1238 seg1 = seg1->next;
1239
1240 /* merge the old head, seg2, into tail, seg1 */
1241 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1242
1243 /* bypass the merged seg2, and attach any chain after it to
1244 * chain descending from as2's head
1245 */
1246 seg1->next = seg2->next;
1247
1248 /* seg2 is now referenceless and useless*/
1249 assegment_free (seg2);
1250
1251 /* we've now prepended as1's segment chain to as2, merging
1252 * the inbetween AS_SEQUENCE of seg2 in the process
1253 */
1254 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001255 return as2;
1256 }
1257 else
1258 {
1259 /* AS_SET merge code is needed at here. */
1260 return aspath_merge (as1, as2);
1261 }
paulfe69a502005-09-10 16:55:02 +00001262 /* XXX: Ermmm, what if as1 has multiple segments?? */
1263
paul718e3742002-12-13 20:15:29 +00001264 /* Not reached */
1265}
1266
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001267/* Iterate over AS_PATH segments and wipe all occurences of the
1268 * listed AS numbers. Hence some segments may lose some or even
1269 * all data on the way, the operation is implemented as a smarter
1270 * version of aspath_dup(), which allocates memory to hold the new
1271 * data, not the original. The new AS path is returned.
1272 */
1273struct aspath *
1274aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1275{
1276 struct assegment * srcseg, * exclseg, * lastseg;
1277 struct aspath * newpath;
1278
1279 newpath = aspath_new();
1280 lastseg = NULL;
1281
1282 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1283 {
1284 unsigned i, y, newlen = 0, done = 0, skip_as;
1285 struct assegment * newseg;
1286
1287 /* Find out, how much ASns are we going to pick from this segment.
1288 * We can't perform filtering right inline, because the size of
1289 * the new segment isn't known at the moment yet.
1290 */
1291 for (i = 0; i < srcseg->length; i++)
1292 {
1293 skip_as = 0;
1294 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1295 for (y = 0; y < exclseg->length; y++)
1296 if (srcseg->as[i] == exclseg->as[y])
1297 {
1298 skip_as = 1;
1299 // There's no sense in testing the rest of exclusion list, bail out.
1300 break;
1301 }
1302 if (!skip_as)
1303 newlen++;
1304 }
1305 /* newlen is now the number of ASns to copy */
1306 if (!newlen)
1307 continue;
1308
1309 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1310 newseg = assegment_new (srcseg->type, newlen);
1311 for (i = 0; i < srcseg->length; i++)
1312 {
1313 skip_as = 0;
1314 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1315 for (y = 0; y < exclseg->length; y++)
1316 if (srcseg->as[i] == exclseg->as[y])
1317 {
1318 skip_as = 1;
1319 break;
1320 }
1321 if (skip_as)
1322 continue;
1323 newseg->as[done++] = srcseg->as[i];
1324 }
1325 /* At his point newlen must be equal to done, and both must be positive. Append
1326 * the filtered segment to the gross result. */
1327 if (!lastseg)
1328 newpath->segments = newseg;
1329 else
1330 lastseg->next = newseg;
1331 lastseg = newseg;
1332 }
1333 aspath_str_update (newpath);
1334 /* We are happy returning even an empty AS_PATH, because the administrator
1335 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1336 * by having a match rule against certain AS_PATH regexps in the route-map index.
1337 */
1338 aspath_free (source);
1339 return newpath;
1340}
1341
paul718e3742002-12-13 20:15:29 +00001342/* Add specified AS to the leftmost of aspath. */
1343static struct aspath *
1344aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1345{
paulfe69a502005-09-10 16:55:02 +00001346 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001347
1348 /* In case of empty aspath. */
1349 if (assegment == NULL || assegment->length == 0)
1350 {
paulfe69a502005-09-10 16:55:02 +00001351 aspath->segments = assegment_new (type, 1);
1352 aspath->segments->as[0] = asno;
1353
paul718e3742002-12-13 20:15:29 +00001354 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001355 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001356
1357 return aspath;
1358 }
1359
1360 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001361 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1362 else
paul718e3742002-12-13 20:15:29 +00001363 {
paulfe69a502005-09-10 16:55:02 +00001364 /* create new segment
1365 * push it onto head of aspath's segment chain
1366 */
paul718e3742002-12-13 20:15:29 +00001367 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001368
1369 newsegment = assegment_new (type, 1);
1370 newsegment->as[0] = asno;
1371
1372 newsegment->next = assegment;
1373 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001374 }
1375
1376 return aspath;
1377}
1378
1379/* Add specified AS to the leftmost of aspath. */
1380struct aspath *
1381aspath_add_seq (struct aspath *aspath, as_t asno)
1382{
1383 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1384}
1385
1386/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1387 as2's leftmost AS is same return 1. */
1388int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001389aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001390{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001391 const struct assegment *seg1 = NULL;
1392 const struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001393
paulfe69a502005-09-10 16:55:02 +00001394 if (!(aspath1 && aspath2))
1395 return 0;
paul718e3742002-12-13 20:15:29 +00001396
paulfe69a502005-09-10 16:55:02 +00001397 seg1 = aspath1->segments;
1398 seg2 = aspath2->segments;
1399
1400 /* find first non-confed segments for each */
1401 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1402 || (seg1->type == AS_CONFED_SET)))
1403 seg1 = seg1->next;
1404
1405 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1406 || (seg2->type == AS_CONFED_SET)))
1407 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001408
1409 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001410 if (!(seg1 && seg2
1411 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001412 return 0;
paulfe69a502005-09-10 16:55:02 +00001413
1414 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001415 return 1;
1416
1417 return 0;
1418}
1419
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001420/* Truncate an aspath after a number of hops, and put the hops remaining
1421 * at the front of another aspath. Needed for AS4 compat.
1422 *
1423 * Returned aspath is a /new/ aspath, which should either by free'd or
1424 * interned by the caller, as desired.
1425 */
1426struct aspath *
1427aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1428{
1429 struct assegment *seg, *newseg, *prevseg = NULL;
1430 struct aspath *newpath = NULL, *mergedpath;
1431 int hops, cpasns = 0;
1432
1433 if (!aspath)
1434 return NULL;
1435
1436 seg = aspath->segments;
1437
1438 /* CONFEDs should get reconciled too.. */
1439 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1440 - aspath_count_hops (as4path);
1441
1442 if (hops < 0)
1443 {
1444 if (BGP_DEBUG (as4, AS4))
1445 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1446 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1447 * which is daft behaviour - it contains vital loop-detection
1448 * information which must have been removed from AS_PATH.
1449 */
1450 hops = aspath_count_hops (aspath);
1451 }
1452
1453 if (!hops)
1454 return aspath_dup (as4path);
1455
1456 if ( BGP_DEBUG(as4, AS4))
1457 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1458 aspath->str, as4path->str);
1459
1460 while (seg && hops > 0)
1461 {
1462 switch (seg->type)
1463 {
1464 case AS_SET:
1465 case AS_CONFED_SET:
1466 hops--;
1467 cpasns = seg->length;
1468 break;
1469 case AS_CONFED_SEQUENCE:
1470 /* Should never split a confed-sequence, if hop-count
1471 * suggests we must then something's gone wrong somewhere.
1472 *
1473 * Most important goal is to preserve AS_PATHs prime function
1474 * as loop-detector, so we fudge the numbers so that the entire
1475 * confed-sequence is merged in.
1476 */
1477 if (hops < seg->length)
1478 {
1479 if (BGP_DEBUG (as4, AS4))
1480 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1481 " across 2/4 ASN boundary somewhere, broken..");
1482 hops = seg->length;
1483 }
1484 case AS_SEQUENCE:
1485 cpasns = MIN(seg->length, hops);
1486 hops -= seg->length;
1487 }
1488
1489 assert (cpasns <= seg->length);
1490
1491 newseg = assegment_new (seg->type, 0);
1492 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1493
1494 if (!newpath)
1495 {
1496 newpath = aspath_new ();
1497 newpath->segments = newseg;
1498 }
1499 else
1500 prevseg->next = newseg;
1501
1502 prevseg = newseg;
1503 seg = seg->next;
1504 }
1505
1506 /* We may be able to join some segments here, and we must
1507 * do this because... we want normalised aspaths in out hash
1508 * and we do not want to stumble in aspath_put.
1509 */
1510 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1511 aspath_free (newpath);
1512 mergedpath->segments = assegment_normalise (mergedpath->segments);
1513 aspath_str_update (mergedpath);
1514
1515 if ( BGP_DEBUG(as4, AS4))
1516 zlog_debug ("[AS4] result of synthesizing is %s",
1517 mergedpath->str);
1518
1519 return mergedpath;
1520}
1521
paul718e3742002-12-13 20:15:29 +00001522/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1523 as2's leftmost AS is same return 1. (confederation as-path
1524 only). */
1525int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001526aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001527{
paulfe69a502005-09-10 16:55:02 +00001528 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001529 return 0;
paulfe69a502005-09-10 16:55:02 +00001530
paulad727402005-11-23 02:47:02 +00001531 if ( !(aspath1->segments && aspath2->segments) )
1532 return 0;
1533
paulfe69a502005-09-10 16:55:02 +00001534 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1535 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001536 return 0;
paulfe69a502005-09-10 16:55:02 +00001537
1538 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001539 return 1;
1540
1541 return 0;
1542}
1543
paulfe69a502005-09-10 16:55:02 +00001544/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1545 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001546struct aspath *
1547aspath_delete_confed_seq (struct aspath *aspath)
1548{
paulfe69a502005-09-10 16:55:02 +00001549 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001550
paulfe69a502005-09-10 16:55:02 +00001551 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001552 return aspath;
1553
paulfe69a502005-09-10 16:55:02 +00001554 seg = aspath->segments;
1555
1556 /* "if the first path segment of the AS_PATH is
1557 * of type AS_CONFED_SEQUENCE,"
1558 */
1559 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1560 return aspath;
paul718e3742002-12-13 20:15:29 +00001561
paulfe69a502005-09-10 16:55:02 +00001562 /* "... that segment and any immediately following segments
1563 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1564 * from the AS_PATH attribute,"
1565 */
1566 while (seg &&
1567 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001568 {
paulfe69a502005-09-10 16:55:02 +00001569 aspath->segments = seg->next;
1570 assegment_free (seg);
1571 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001572 }
paulfe69a502005-09-10 16:55:02 +00001573 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001574 return aspath;
1575}
1576
1577/* Add new AS number to the leftmost part of the aspath as
1578 AS_CONFED_SEQUENCE. */
1579struct aspath*
1580aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1581{
1582 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1583}
1584
1585/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001586static void
paul718e3742002-12-13 20:15:29 +00001587aspath_as_add (struct aspath *as, as_t asno)
1588{
paulfe69a502005-09-10 16:55:02 +00001589 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001590
paulfe69a502005-09-10 16:55:02 +00001591 if (!seg)
1592 return;
1593
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001594 /* Last segment search procedure. */
1595 while (seg->next)
1596 seg = seg->next;
1597
paulfe69a502005-09-10 16:55:02 +00001598 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001599}
1600
1601/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001602static void
paul718e3742002-12-13 20:15:29 +00001603aspath_segment_add (struct aspath *as, int type)
1604{
paulfe69a502005-09-10 16:55:02 +00001605 struct assegment *seg = as->segments;
1606 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001607
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001608 if (seg)
1609 {
1610 while (seg->next)
1611 seg = seg->next;
1612 seg->next = new;
1613 }
paul718e3742002-12-13 20:15:29 +00001614 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001615 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001616}
1617
1618struct aspath *
paul94f2b392005-06-28 12:44:16 +00001619aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001620{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001621 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001622}
1623
1624struct aspath *
paul94f2b392005-06-28 12:44:16 +00001625aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001626{
1627 struct aspath *aspath;
1628
1629 aspath = aspath_new ();
1630 aspath->str = aspath_make_str_count (aspath);
1631 return aspath;
1632}
1633
1634unsigned long
paulfe69a502005-09-10 16:55:02 +00001635aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001636{
1637 return ashash->count;
1638}
1639
1640/*
1641 Theoretically, one as path can have:
1642
1643 One BGP packet size should be less than 4096.
1644 One BGP attribute size should be less than 4096 - BGP header size.
1645 One BGP aspath size should be less than 4096 - BGP header size -
1646 BGP mandantry attribute size.
1647*/
1648
1649/* AS path string lexical token enum. */
1650enum as_token
1651{
1652 as_token_asval,
1653 as_token_set_start,
1654 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001655 as_token_confed_seq_start,
1656 as_token_confed_seq_end,
1657 as_token_confed_set_start,
1658 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001659 as_token_unknown
1660};
1661
1662/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001663static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001664aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001665{
paulfd79ac92004-10-13 05:06:08 +00001666 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001667
paulfe69a502005-09-10 16:55:02 +00001668 /* Skip seperators (space for sequences, ',' for sets). */
1669 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001670 p++;
1671
1672 /* Check the end of the string and type specify characters
1673 (e.g. {}()). */
1674 switch (*p)
1675 {
1676 case '\0':
1677 return NULL;
paul718e3742002-12-13 20:15:29 +00001678 case '{':
1679 *token = as_token_set_start;
1680 p++;
1681 return p;
paul718e3742002-12-13 20:15:29 +00001682 case '}':
1683 *token = as_token_set_end;
1684 p++;
1685 return p;
paul718e3742002-12-13 20:15:29 +00001686 case '(':
paulfe69a502005-09-10 16:55:02 +00001687 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001688 p++;
1689 return p;
paul718e3742002-12-13 20:15:29 +00001690 case ')':
paulfe69a502005-09-10 16:55:02 +00001691 *token = as_token_confed_seq_end;
1692 p++;
1693 return p;
paulfe69a502005-09-10 16:55:02 +00001694 case '[':
1695 *token = as_token_confed_set_start;
1696 p++;
1697 return p;
paulfe69a502005-09-10 16:55:02 +00001698 case ']':
1699 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001700 p++;
1701 return p;
paul718e3742002-12-13 20:15:29 +00001702 }
1703
1704 /* Check actual AS value. */
1705 if (isdigit ((int) *p))
1706 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001707 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001708
paul718e3742002-12-13 20:15:29 +00001709 *token = as_token_asval;
1710 asval = (*p - '0');
1711 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001712
paul718e3742002-12-13 20:15:29 +00001713 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001714 {
1715 asval *= 10;
1716 asval += (*p - '0');
1717 p++;
1718 }
paul718e3742002-12-13 20:15:29 +00001719 *asno = asval;
1720 return p;
1721 }
1722
1723 /* There is no match then return unknown token. */
1724 *token = as_token_unknown;
1725 return p++;
1726}
1727
1728struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001729aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001730{
paul3fff6ff2006-02-05 17:55:35 +00001731 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001732 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001733 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001734 struct aspath *aspath;
1735 int needtype;
1736
1737 aspath = aspath_new ();
1738
1739 /* We start default type as AS_SEQUENCE. */
1740 as_type = AS_SEQUENCE;
1741 needtype = 1;
1742
1743 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1744 {
1745 switch (token)
1746 {
1747 case as_token_asval:
1748 if (needtype)
1749 {
1750 aspath_segment_add (aspath, as_type);
1751 needtype = 0;
1752 }
1753 aspath_as_add (aspath, asno);
1754 break;
1755 case as_token_set_start:
1756 as_type = AS_SET;
1757 aspath_segment_add (aspath, as_type);
1758 needtype = 0;
1759 break;
1760 case as_token_set_end:
1761 as_type = AS_SEQUENCE;
1762 needtype = 1;
1763 break;
paulfe69a502005-09-10 16:55:02 +00001764 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001765 as_type = AS_CONFED_SEQUENCE;
1766 aspath_segment_add (aspath, as_type);
1767 needtype = 0;
1768 break;
paulfe69a502005-09-10 16:55:02 +00001769 case as_token_confed_seq_end:
1770 as_type = AS_SEQUENCE;
1771 needtype = 1;
1772 break;
1773 case as_token_confed_set_start:
1774 as_type = AS_CONFED_SET;
1775 aspath_segment_add (aspath, as_type);
1776 needtype = 0;
1777 break;
1778 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001779 as_type = AS_SEQUENCE;
1780 needtype = 1;
1781 break;
1782 case as_token_unknown:
1783 default:
paulfe69a502005-09-10 16:55:02 +00001784 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001785 return NULL;
paul718e3742002-12-13 20:15:29 +00001786 }
1787 }
1788
1789 aspath->str = aspath_make_str_count (aspath);
1790
1791 return aspath;
1792}
1793
1794/* Make hash value by raw aspath data. */
1795unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001796aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001797{
Paul Jakma923de652007-04-29 18:25:17 +00001798 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001799 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001800
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001801 if (!aspath->str)
1802 aspath_str_update (aspath);
1803
1804 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001805
1806 return key;
1807}
1808
1809/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001810static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001811aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001812{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001813 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1814 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001815
1816 while (seg1 || seg2)
1817 {
1818 int i;
1819 if ((!seg1 && seg2) || (seg1 && !seg2))
1820 return 0;
1821 if (seg1->type != seg2->type)
1822 return 0;
1823 if (seg1->length != seg2->length)
1824 return 0;
1825 for (i = 0; i < seg1->length; i++)
1826 if (seg1->as[i] != seg2->as[i])
1827 return 0;
1828 seg1 = seg1->next;
1829 seg2 = seg2->next;
1830 }
1831 return 1;
paul718e3742002-12-13 20:15:29 +00001832}
1833
1834/* AS path hash initialize. */
1835void
paul94f2b392005-06-28 12:44:16 +00001836aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001837{
1838 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1839}
paul8fdc32a2006-01-16 12:01:29 +00001840
1841void
1842aspath_finish (void)
1843{
1844 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00001845 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00001846
1847 if (snmp_stream)
1848 stream_free (snmp_stream);
1849}
paul718e3742002-12-13 20:15:29 +00001850
1851/* return and as path value */
1852const char *
1853aspath_print (struct aspath *as)
1854{
paulfe69a502005-09-10 16:55:02 +00001855 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001856}
1857
1858/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001859/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1860 * AS_PATH wasn't empty.
1861 */
paul718e3742002-12-13 20:15:29 +00001862void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001863aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001864{
Paul Jakmab2518c12006-05-12 23:48:40 +00001865 assert (format);
1866 vty_out (vty, format, as->str);
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001867 if (strlen (as->str) && strlen (suffix))
1868 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001869}
1870
paul94f2b392005-06-28 12:44:16 +00001871static void
paul718e3742002-12-13 20:15:29 +00001872aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1873{
1874 struct aspath *as;
1875
1876 as = (struct aspath *) backet->data;
1877
paulefa9f832002-12-13 21:47:59 +00001878 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001879 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1880}
1881
1882/* Print all aspath and hash information. This function is used from
1883 `show ip bgp paths' command. */
1884void
1885aspath_print_all_vty (struct vty *vty)
1886{
1887 hash_iterate (ashash,
1888 (void (*) (struct hash_backet *, void *))
1889 aspath_show_all_iterator,
1890 vty);
1891}