blob: 176a960e1e909e60fad39216517a451cead8bdfe [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. */
Stephen Hemmingerda88ea82009-12-17 13:14:28 +030089static struct 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
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000343aspath_unintern (struct aspath **aspath)
paul718e3742002-12-13 20:15:29 +0000344{
345 struct aspath *ret;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000346 struct aspath *asp = *aspath;
347
348 if (asp->refcnt)
349 asp->refcnt--;
paul718e3742002-12-13 20:15:29 +0000350
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000351 if (asp->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000352 {
353 /* This aspath must exist in aspath hash table. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000354 ret = hash_release (ashash, asp);
paul718e3742002-12-13 20:15:29 +0000355 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000356 aspath_free (asp);
357 *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000358 }
359}
360
361/* Return the start or end delimiters for a particular Segment type */
362#define AS_SEG_START 0
363#define AS_SEG_END 1
364static char
365aspath_delimiter_char (u_char type, u_char which)
366{
367 int i;
368 struct
369 {
370 int type;
371 char start;
372 char end;
373 } aspath_delim_char [] =
374 {
375 { AS_SET, '{', '}' },
paul718e3742002-12-13 20:15:29 +0000376 { AS_CONFED_SET, '[', ']' },
377 { AS_CONFED_SEQUENCE, '(', ')' },
378 { 0 }
379 };
380
381 for (i = 0; aspath_delim_char[i].type != 0; i++)
382 {
383 if (aspath_delim_char[i].type == type)
384 {
385 if (which == AS_SEG_START)
386 return aspath_delim_char[i].start;
387 else if (which == AS_SEG_END)
388 return aspath_delim_char[i].end;
389 }
390 }
391 return ' ';
392}
393
Denis Ovsienko014b6702009-06-23 21:10:45 +0400394/* countup asns from this segment and index onward */
395static int
396assegment_count_asns (struct assegment *seg, int from)
397{
398 int count = 0;
399 while (seg)
400 {
401 if (!from)
402 count += seg->length;
403 else
404 {
405 count += (seg->length - from);
406 from = 0;
407 }
408 seg = seg->next;
409 }
410 return count;
411}
412
paulfe69a502005-09-10 16:55:02 +0000413unsigned int
414aspath_count_confeds (struct aspath *aspath)
415{
416 int count = 0;
417 struct assegment *seg = aspath->segments;
418
419 while (seg)
420 {
421 if (seg->type == AS_CONFED_SEQUENCE)
422 count += seg->length;
423 else if (seg->type == AS_CONFED_SET)
424 count++;
425
426 seg = seg->next;
427 }
428 return count;
429}
430
431unsigned int
432aspath_count_hops (struct aspath *aspath)
433{
434 int count = 0;
435 struct assegment *seg = aspath->segments;
436
437 while (seg)
438 {
439 if (seg->type == AS_SEQUENCE)
440 count += seg->length;
441 else if (seg->type == AS_SET)
442 count++;
443
444 seg = seg->next;
445 }
446 return count;
447}
448
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000449/* Estimate size aspath /might/ take if encoded into an
450 * ASPATH attribute.
451 *
452 * This is a quick estimate, not definitive! aspath_put()
453 * may return a different number!!
454 */
paulfe69a502005-09-10 16:55:02 +0000455unsigned int
456aspath_size (struct aspath *aspath)
457{
458 int size = 0;
459 struct assegment *seg = aspath->segments;
460
461 while (seg)
462 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000463 size += ASSEGMENT_SIZE(seg->length, 1);
paulfe69a502005-09-10 16:55:02 +0000464 seg = seg->next;
465 }
466 return size;
467}
468
Paul Jakma2815e612006-09-14 02:56:07 +0000469/* Return highest public ASN in path */
470as_t
471aspath_highest (struct aspath *aspath)
472{
473 struct assegment *seg = aspath->segments;
474 as_t highest = 0;
475 unsigned int i;
476
477 while (seg)
478 {
479 for (i = 0; i < seg->length; i++)
480 if (seg->as[i] > highest
481 && (seg->as[i] < BGP_PRIVATE_AS_MIN
482 || seg->as[i] > BGP_PRIVATE_AS_MAX))
483 highest = seg->as[i];
484 seg = seg->next;
485 }
486 return highest;
487}
488
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000489/* Return 1 if there are any 4-byte ASes in the path */
490unsigned int
491aspath_has_as4 (struct aspath *aspath)
492{
493 struct assegment *seg = aspath->segments;
494 unsigned int i;
495
496 while (seg)
497 {
498 for (i = 0; i < seg->length; i++)
499 if (seg->as[i] > BGP_AS_MAX)
500 return 1;
501 seg = seg->next;
502 }
503 return 0;
504}
505
paul718e3742002-12-13 20:15:29 +0000506/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000507static char *
paul718e3742002-12-13 20:15:29 +0000508aspath_make_str_count (struct aspath *as)
509{
paulfe69a502005-09-10 16:55:02 +0000510 struct assegment *seg;
511 int str_size;
512 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000513 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000514
515 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000516 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000517 {
518 str_buf = XMALLOC (MTYPE_AS_STR, 1);
519 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000520 return str_buf;
521 }
paulfe69a502005-09-10 16:55:02 +0000522
523 seg = as->segments;
524
Denis Ovsienko014b6702009-06-23 21:10:45 +0400525 /* ASN takes 5 to 10 chars plus seperator, see below.
526 * If there is one differing segment type, we need an additional
527 * 2 chars for segment delimiters, and the final '\0'.
528 * Hopefully this is large enough to avoid hitting the realloc
529 * code below for most common sequences.
530 *
531 * This was changed to 10 after the well-known BGP assertion, which
532 * had hit some parts of the Internet in May of 2009.
533 */
534#define ASN_STR_LEN (10 + 1)
535 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
536 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000537 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000538
paulfe69a502005-09-10 16:55:02 +0000539 while (seg)
paul718e3742002-12-13 20:15:29 +0000540 {
541 int i;
paulfe69a502005-09-10 16:55:02 +0000542 char seperator;
paul718e3742002-12-13 20:15:29 +0000543
paulfe69a502005-09-10 16:55:02 +0000544 /* Check AS type validity. Set seperator for segment */
545 switch (seg->type)
546 {
547 case AS_SET:
548 case AS_CONFED_SET:
549 seperator = ',';
550 break;
551 case AS_SEQUENCE:
552 case AS_CONFED_SEQUENCE:
553 seperator = ' ';
554 break;
555 default:
556 XFREE (MTYPE_AS_STR, str_buf);
557 return NULL;
558 }
559
Denis Ovsienko014b6702009-06-23 21:10:45 +0400560 /* We might need to increase str_buf, particularly if path has
561 * differing segments types, our initial guesstimate above will
562 * have been wrong. Need 10 chars for ASN, a seperator each and
563 * potentially two segment delimiters, plus a space between each
564 * segment and trailing zero.
565 *
566 * This definitely didn't work with the value of 5 bytes and
567 * 32-bit ASNs.
568 */
569#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
570 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
571 {
572 str_size = len + SEGMENT_STR_LEN(seg);
573 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
574 }
575#undef ASN_STR_LEN
576#undef SEGMENT_STR_LEN
577
paulfe69a502005-09-10 16:55:02 +0000578 if (seg->type != AS_SEQUENCE)
Denis Ovsienko014b6702009-06-23 21:10:45 +0400579 len += snprintf (str_buf + len, str_size - len,
580 "%c",
581 aspath_delimiter_char (seg->type, AS_SEG_START));
paulfe69a502005-09-10 16:55:02 +0000582
583 /* write out the ASNs, with their seperators, bar the last one*/
584 for (i = 0; i < seg->length; i++)
585 {
586 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
587
588 if (i < (seg->length - 1))
589 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
590 }
591
592 if (seg->type != AS_SEQUENCE)
593 len += snprintf (str_buf + len, str_size - len, "%c",
594 aspath_delimiter_char (seg->type, AS_SEG_END));
595 if (seg->next)
596 len += snprintf (str_buf + len, str_size - len, " ");
597
598 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000599 }
paulfe69a502005-09-10 16:55:02 +0000600
601 assert (len < str_size);
602
603 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000604
605 return str_buf;
606}
607
paulfe69a502005-09-10 16:55:02 +0000608static void
609aspath_str_update (struct aspath *as)
610{
611 if (as->str)
612 XFREE (MTYPE_AS_STR, as->str);
613 as->str = aspath_make_str_count (as);
614}
615
paul718e3742002-12-13 20:15:29 +0000616/* Intern allocated AS path. */
617struct aspath *
618aspath_intern (struct aspath *aspath)
619{
620 struct aspath *find;
621
622 /* Assert this AS path structure is not interned. */
623 assert (aspath->refcnt == 0);
624
625 /* Check AS path hash. */
626 find = hash_get (ashash, aspath, hash_alloc_intern);
627
628 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000629 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000630
631 find->refcnt++;
632
633 if (! find->str)
634 find->str = aspath_make_str_count (find);
635
636 return find;
637}
638
639/* Duplicate aspath structure. Created same aspath structure but
640 reference count and AS path string is cleared. */
641struct aspath *
642aspath_dup (struct aspath *aspath)
643{
644 struct aspath *new;
645
paulfe69a502005-09-10 16:55:02 +0000646 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000647
paulfe69a502005-09-10 16:55:02 +0000648 if (aspath->segments)
649 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000650 else
paulfe69a502005-09-10 16:55:02 +0000651 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000652
paulfe69a502005-09-10 16:55:02 +0000653 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000654
655 return new;
656}
657
paul94f2b392005-06-28 12:44:16 +0000658static void *
paulfe69a502005-09-10 16:55:02 +0000659aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000660{
661 struct aspath *aspath;
662
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000663 /* New aspath structure is needed. */
paulfe69a502005-09-10 16:55:02 +0000664 aspath = aspath_dup (arg);
665
paul718e3742002-12-13 20:15:29 +0000666 /* Malformed AS path value. */
667 if (! aspath->str)
668 {
669 aspath_free (aspath);
670 return NULL;
671 }
672
673 return aspath;
674}
675
Paul Jakmaab005292010-11-27 22:48:34 +0000676/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000677static struct assegment *
Paul Jakmaab005292010-11-27 22:48:34 +0000678assegments_parse (struct stream *s, size_t length, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000679{
680 struct assegment_header segh;
681 struct assegment *seg, *prev = NULL, *head = NULL;
Paul Jakmaab005292010-11-27 22:48:34 +0000682 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000683
Paul Jakmaab005292010-11-27 22:48:34 +0000684 /* empty aspath (ie iBGP or somesuch) */
685 if (length == 0)
686 return NULL;
paulfe69a502005-09-10 16:55:02 +0000687
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000688 if (BGP_DEBUG (as4, AS4_SEGMENT))
689 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
690 (unsigned long) length);
Paul Jakmaab005292010-11-27 22:48:34 +0000691 /* basic checks */
692 if ((STREAM_READABLE(s) < length)
693 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
694 || (length % AS16_VALUE_SIZE ))
paulfe69a502005-09-10 16:55:02 +0000695 return NULL;
696
Paul Jakmaab005292010-11-27 22:48:34 +0000697 while (bytes < length)
paulfe69a502005-09-10 16:55:02 +0000698 {
699 int i;
Chris Hallcddb8112010-08-09 22:31:37 +0400700 size_t seg_size;
paulfe69a502005-09-10 16:55:02 +0000701
Paul Jakmaab005292010-11-27 22:48:34 +0000702 if ((length - bytes) <= AS_HEADER_SIZE)
Chris Hallcddb8112010-08-09 22:31:37 +0400703 {
Paul Jakmaab005292010-11-27 22:48:34 +0000704 if (head)
705 assegment_free_all (head);
706 return NULL;
707 }
708
709 /* softly softly, get the header first on its own */
paulfe69a502005-09-10 16:55:02 +0000710 segh.type = stream_getc (s);
711 segh.length = stream_getc (s);
712
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000713 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
714
715 if (BGP_DEBUG (as4, AS4_SEGMENT))
716 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
717 segh.type, segh.length);
718
Paul Jakmaab005292010-11-27 22:48:34 +0000719 /* check it.. */
720 if ( ((bytes + seg_size) > length)
721 /* 1771bis 4.3b: seg length contains one or more */
722 || (segh.length == 0)
723 /* Paranoia in case someone changes type of segment length.
724 * Shift both values by 0x10 to make the comparison operate
725 * on more, than 8 bits (otherwise it's a warning, bug #564).
Denis Ovsienko2eb445e2009-12-04 17:32:54 +0300726 */
Paul Jakmaab005292010-11-27 22:48:34 +0000727 || ((sizeof segh.length > 1)
728 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
paulfe69a502005-09-10 16:55:02 +0000729 {
Paul Jakmaab005292010-11-27 22:48:34 +0000730 if (head)
paulfe69a502005-09-10 16:55:02 +0000731 assegment_free_all (head);
732 return NULL;
733 }
734
Paul Jakmaab005292010-11-27 22:48:34 +0000735 switch (segh.type)
736 {
737 case AS_SEQUENCE:
738 case AS_SET:
739 case AS_CONFED_SEQUENCE:
740 case AS_CONFED_SET:
741 break;
742 default:
743 if (head)
744 assegment_free_all (head);
745 return NULL;
746 }
Chris Hallcddb8112010-08-09 22:31:37 +0400747
paulfe69a502005-09-10 16:55:02 +0000748 /* now its safe to trust lengths */
749 seg = assegment_new (segh.type, segh.length);
750
751 if (head)
752 prev->next = seg;
753 else /* it's the first segment */
754 head = prev = seg;
755
756 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000757 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
758
Paul Jakmaab005292010-11-27 22:48:34 +0000759 bytes += seg_size;
760
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000761 if (BGP_DEBUG (as4, AS4_SEGMENT))
Paul Jakmaab005292010-11-27 22:48:34 +0000762 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
763 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000764
765 prev = seg;
766 }
767
768 return assegment_normalise (head);
769}
770
Paul Jakmaab005292010-11-27 22:48:34 +0000771/* AS path parse function. pnt is a pointer to byte stream and length
772 is length of byte stream. If there is same AS path in the the AS
773 path hash then return it else make new AS path structure. */
paul718e3742002-12-13 20:15:29 +0000774struct aspath *
Paul Jakmaab005292010-11-27 22:48:34 +0000775aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000776{
777 struct aspath as;
778 struct aspath *find;
779
Paul Jakmaab005292010-11-27 22:48:34 +0000780 /* If length is odd it's malformed AS path. */
781 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
782 * otherwise its malformed when length is larger than 2 and (length-2)
783 * is not dividable by 4.
784 * But... this time we're lazy
785 */
786 if (length % AS16_VALUE_SIZE )
787 return NULL;
Chris Hallcddb8112010-08-09 22:31:37 +0400788
Paul Jakmaab005292010-11-27 22:48:34 +0000789 memset (&as, 0, sizeof (struct aspath));
790 as.segments = assegments_parse (s, length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000791
paul718e3742002-12-13 20:15:29 +0000792 /* If already same aspath exist then return it. */
793 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000794
795 /* aspath_hash_alloc dupes segments too. that probably could be
796 * optimised out.
797 */
798 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000799 if (as.str)
800 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000801
Paul Jakmaab005292010-11-27 22:48:34 +0000802 if (! find)
803 return NULL;
paul718e3742002-12-13 20:15:29 +0000804 find->refcnt++;
805
806 return find;
807}
808
paulfe69a502005-09-10 16:55:02 +0000809static inline void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000810assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000811{
paulfe69a502005-09-10 16:55:02 +0000812 int i;
813 assert (num <= AS_SEGMENT_MAX);
814
815 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000816 if ( use32bit )
817 stream_putl (s, as[i]);
818 else
819 {
820 if ( as[i] <= BGP_AS_MAX )
821 stream_putw(s, as[i]);
822 else
823 stream_putw(s, BGP_AS_TRANS);
824 }
paul718e3742002-12-13 20:15:29 +0000825}
826
paulfe69a502005-09-10 16:55:02 +0000827static inline size_t
828assegment_header_put (struct stream *s, u_char type, int length)
829{
830 size_t lenp;
831 assert (length <= AS_SEGMENT_MAX);
832 stream_putc (s, type);
833 lenp = stream_get_endp (s);
834 stream_putc (s, length);
835 return lenp;
836}
837
838/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000839size_t
840aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000841{
842 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000843 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000844
845 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000846 return 0;
paulfe69a502005-09-10 16:55:02 +0000847
848 if (seg)
849 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000850 /*
851 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
852 * At the moment, we would write out a partial aspath, and our peer
853 * will complain and drop the session :-/
854 *
855 * The general assumption here is that many things tested will
856 * never happen. And, in real live, up to now, they have not.
857 */
858 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000859 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000860 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000861 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000862 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000863 size_t lenp;
864
865 /* Overlength segments have to be split up */
866 while ( (seg->length - written) > AS_SEGMENT_MAX)
867 {
868 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000869 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000870 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000871 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000872 }
873
874 /* write the final segment, probably is also the first */
875 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000876 assegment_data_put (s, (seg->as + written), seg->length - written,
877 use32bit);
paulfe69a502005-09-10 16:55:02 +0000878
879 /* Sequence-type segments can be 'packed' together
880 * Case of a segment which was overlength and split up
881 * will be missed here, but that doesn't matter.
882 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000883 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000884 {
885 /* NB: We should never normally get here given we
886 * normalise aspath data when parse them. However, better
887 * safe than sorry. We potentially could call
888 * assegment_normalise here instead, but it's cheaper and
889 * easier to do it on the fly here rather than go through
890 * the segment list twice every time we write out
891 * aspath's.
892 */
893
894 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000895 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000896
897 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000898 stream_putc_at (s, lenp, seg->length - written + next->length);
899 asns_packed += next->length;
900
901 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000902 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000903
904 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
905 use32bit);
906 seg = next;
paulfe69a502005-09-10 16:55:02 +0000907 }
908 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000909 return bytes;
paulfe69a502005-09-10 16:55:02 +0000910}
911
912/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
913 * We have no way to manage the storage, so we use a static stream
914 * wrapper around aspath_put.
915 */
916u_char *
917aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
918{
919#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000920
921 if (!snmp_stream)
922 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000923 else
paul8fdc32a2006-01-16 12:01:29 +0000924 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000925
926 if (!as)
927 {
928 *varlen = 0;
929 return NULL;
930 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000931 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000932
paul8fdc32a2006-01-16 12:01:29 +0000933 *varlen = stream_get_endp (snmp_stream);
934 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000935}
936
937#define min(A,B) ((A) < (B) ? (A) : (B))
938
paul94f2b392005-06-28 12:44:16 +0000939static struct assegment *
paul718e3742002-12-13 20:15:29 +0000940aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
941 as_t as)
942{
943 int i;
944
945 /* If this is first AS set member, create new as-set segment. */
946 if (asset == NULL)
947 {
paulfe69a502005-09-10 16:55:02 +0000948 asset = assegment_new (AS_SET, 1);
949 if (! aspath->segments)
950 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000951 else
paulfe69a502005-09-10 16:55:02 +0000952 {
953 struct assegment *seg = aspath->segments;
954 while (seg->next)
955 seg = seg->next;
956 seg->next = asset;
957 }
paul718e3742002-12-13 20:15:29 +0000958 asset->type = AS_SET;
959 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000960 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000961 }
962 else
963 {
paul718e3742002-12-13 20:15:29 +0000964 /* Check this AS value already exists or not. */
965 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000966 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000967 return asset;
paulfe69a502005-09-10 16:55:02 +0000968
paul718e3742002-12-13 20:15:29 +0000969 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000970 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
971 asset->length * AS_VALUE_SIZE);
972 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000973 }
paulfe69a502005-09-10 16:55:02 +0000974
paul718e3742002-12-13 20:15:29 +0000975
976 return asset;
977}
978
979/* Modify as1 using as2 for aggregation. */
980struct aspath *
981aspath_aggregate (struct aspath *as1, struct aspath *as2)
982{
983 int i;
984 int minlen;
985 int match;
paulfe69a502005-09-10 16:55:02 +0000986 int from;
987 struct assegment *seg1 = as1->segments;
988 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000989 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000990 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000991 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +0000992
993 match = 0;
994 minlen = 0;
995 aspath = NULL;
996 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000997
998 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000999 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001000 {
paul718e3742002-12-13 20:15:29 +00001001 /* Check segment type. */
1002 if (seg1->type != seg2->type)
1003 break;
1004
1005 /* Minimum segment length. */
1006 minlen = min (seg1->length, seg2->length);
1007
1008 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001009 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001010 break;
1011
1012 if (match)
1013 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001014 struct assegment *seg = assegment_new (seg1->type, 0);
1015
1016 seg = assegment_append_asns (seg, seg1->as, match);
1017
paul718e3742002-12-13 20:15:29 +00001018 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001019 {
1020 aspath = aspath_new ();
1021 aspath->segments = seg;
1022 }
1023 else
1024 prevseg->next = seg;
1025
1026 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001027 }
1028
1029 if (match != minlen || match != seg1->length
1030 || seg1->length != seg2->length)
1031 break;
paulfe69a502005-09-10 16:55:02 +00001032
1033 seg1 = seg1->next;
1034 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001035 }
1036
1037 if (! aspath)
1038 aspath = aspath_new();
1039
1040 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001041 from = match;
1042 while (seg1)
paul718e3742002-12-13 20:15:29 +00001043 {
paulfe69a502005-09-10 16:55:02 +00001044 for (i = from; i < seg1->length; i++)
1045 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1046
1047 from = 0;
1048 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001049 }
1050
paulfe69a502005-09-10 16:55:02 +00001051 from = match;
1052 while (seg2)
paul718e3742002-12-13 20:15:29 +00001053 {
paulfe69a502005-09-10 16:55:02 +00001054 for (i = from; i < seg2->length; i++)
1055 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001056
paulfe69a502005-09-10 16:55:02 +00001057 from = 0;
1058 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001059 }
paulfe69a502005-09-10 16:55:02 +00001060
1061 assegment_normalise (aspath->segments);
1062 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001063 return aspath;
1064}
1065
1066/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1067 attribute, check the leftmost AS number in the AS_PATH attribute is
1068 or not the peer's AS number. */
1069int
1070aspath_firstas_check (struct aspath *aspath, as_t asno)
1071{
paulfe69a502005-09-10 16:55:02 +00001072 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001073 return 0;
paulfe69a502005-09-10 16:55:02 +00001074
1075 if (aspath->segments
1076 && (aspath->segments->type == AS_SEQUENCE)
1077 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001078 return 1;
1079
1080 return 0;
1081}
1082
Paul Jakma1f742f22006-08-06 15:52:11 +00001083/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001084int
1085aspath_loop_check (struct aspath *aspath, as_t asno)
1086{
paulfe69a502005-09-10 16:55:02 +00001087 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001088 int count = 0;
1089
Paul Jakma1f742f22006-08-06 15:52:11 +00001090 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001091 return 0;
paulfe69a502005-09-10 16:55:02 +00001092
1093 seg = aspath->segments;
1094
1095 while (seg)
paul718e3742002-12-13 20:15:29 +00001096 {
1097 int i;
paul718e3742002-12-13 20:15:29 +00001098
paulfe69a502005-09-10 16:55:02 +00001099 for (i = 0; i < seg->length; i++)
1100 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001101 count++;
paulfe69a502005-09-10 16:55:02 +00001102
1103 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001104 }
1105 return count;
1106}
1107
1108/* When all of AS path is private AS return 1. */
1109int
1110aspath_private_as_check (struct aspath *aspath)
1111{
paulfe69a502005-09-10 16:55:02 +00001112 struct assegment *seg;
1113
1114 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001115 return 0;
paulfe69a502005-09-10 16:55:02 +00001116
1117 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001118
paulfe69a502005-09-10 16:55:02 +00001119 while (seg)
paul718e3742002-12-13 20:15:29 +00001120 {
1121 int i;
paul718e3742002-12-13 20:15:29 +00001122
paulfe69a502005-09-10 16:55:02 +00001123 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001124 {
paulfe69a502005-09-10 16:55:02 +00001125 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1126 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001127 return 0;
1128 }
paulfe69a502005-09-10 16:55:02 +00001129 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001130 }
1131 return 1;
1132}
1133
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001134/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1135int
1136aspath_confed_check (struct aspath *aspath)
1137{
1138 struct assegment *seg;
1139
1140 if ( !(aspath && aspath->segments) )
1141 return 0;
1142
1143 seg = aspath->segments;
1144
1145 while (seg)
1146 {
1147 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1148 return 1;
1149 seg = seg->next;
1150 }
1151 return 0;
1152}
1153
1154/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1155 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1156int
1157aspath_left_confed_check (struct aspath *aspath)
1158{
1159
1160 if ( !(aspath && aspath->segments) )
1161 return 0;
1162
1163 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1164 || (aspath->segments->type == AS_CONFED_SET) )
1165 return 1;
1166
1167 return 0;
1168}
1169
paul718e3742002-12-13 20:15:29 +00001170/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001171static struct aspath *
paul718e3742002-12-13 20:15:29 +00001172aspath_merge (struct aspath *as1, struct aspath *as2)
1173{
paulfe69a502005-09-10 16:55:02 +00001174 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001175
1176 if (! as1 || ! as2)
1177 return NULL;
1178
paulfe69a502005-09-10 16:55:02 +00001179 last = new = assegment_dup_all (as1->segments);
1180
1181 /* find the last valid segment */
1182 while (last && last->next)
1183 last = last->next;
1184
1185 last->next = as2->segments;
1186 as2->segments = new;
1187 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001188 return as2;
1189}
1190
1191/* Prepend as1 to as2. as2 should be uninterned aspath. */
1192struct aspath *
1193aspath_prepend (struct aspath *as1, struct aspath *as2)
1194{
paulfe69a502005-09-10 16:55:02 +00001195 struct assegment *seg1;
1196 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001197
1198 if (! as1 || ! as2)
1199 return NULL;
paulfe69a502005-09-10 16:55:02 +00001200
1201 seg1 = as1->segments;
1202 seg2 = as2->segments;
1203
1204 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001205 if (seg2 == NULL)
1206 {
paulfe69a502005-09-10 16:55:02 +00001207 as2->segments = assegment_dup_all (as1->segments);
1208 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001209 return as2;
1210 }
paulfe69a502005-09-10 16:55:02 +00001211
1212 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001213 if (seg1 == NULL)
1214 return as2;
paulfe69a502005-09-10 16:55:02 +00001215
1216 /* find the tail as1's segment chain. */
1217 while (seg1 && seg1->next)
1218 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001219
Vasilis Tsiligiannis736d4402009-07-20 01:59:10 +03001220 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1221 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1222 as2 = aspath_delete_confed_seq (as2);
1223
paul718e3742002-12-13 20:15:29 +00001224 /* Compare last segment type of as1 and first segment type of as2. */
1225 if (seg1->type != seg2->type)
1226 return aspath_merge (as1, as2);
1227
1228 if (seg1->type == AS_SEQUENCE)
1229 {
paulfe69a502005-09-10 16:55:02 +00001230 /* We have two chains of segments, as1->segments and seg2,
1231 * and we have to attach them together, merging the attaching
1232 * segments together into one.
1233 *
1234 * 1. dupe as1->segments onto head of as2
1235 * 2. merge seg2's asns onto last segment of this new chain
1236 * 3. attach chain after seg2
1237 */
paul718e3742002-12-13 20:15:29 +00001238
paulfe69a502005-09-10 16:55:02 +00001239 /* dupe as1 onto as2's head */
1240 seg1 = as2->segments = assegment_dup_all (as1->segments);
1241
1242 /* refind the tail of as2, reusing seg1 */
1243 while (seg1 && seg1->next)
1244 seg1 = seg1->next;
1245
1246 /* merge the old head, seg2, into tail, seg1 */
1247 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1248
1249 /* bypass the merged seg2, and attach any chain after it to
1250 * chain descending from as2's head
1251 */
1252 seg1->next = seg2->next;
1253
1254 /* seg2 is now referenceless and useless*/
1255 assegment_free (seg2);
1256
1257 /* we've now prepended as1's segment chain to as2, merging
1258 * the inbetween AS_SEQUENCE of seg2 in the process
1259 */
1260 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001261 return as2;
1262 }
1263 else
1264 {
1265 /* AS_SET merge code is needed at here. */
1266 return aspath_merge (as1, as2);
1267 }
paulfe69a502005-09-10 16:55:02 +00001268 /* XXX: Ermmm, what if as1 has multiple segments?? */
1269
paul718e3742002-12-13 20:15:29 +00001270 /* Not reached */
1271}
1272
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001273/* Iterate over AS_PATH segments and wipe all occurences of the
1274 * listed AS numbers. Hence some segments may lose some or even
1275 * all data on the way, the operation is implemented as a smarter
1276 * version of aspath_dup(), which allocates memory to hold the new
1277 * data, not the original. The new AS path is returned.
1278 */
1279struct aspath *
1280aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1281{
1282 struct assegment * srcseg, * exclseg, * lastseg;
1283 struct aspath * newpath;
1284
1285 newpath = aspath_new();
1286 lastseg = NULL;
1287
1288 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1289 {
1290 unsigned i, y, newlen = 0, done = 0, skip_as;
1291 struct assegment * newseg;
1292
1293 /* Find out, how much ASns are we going to pick from this segment.
1294 * We can't perform filtering right inline, because the size of
1295 * the new segment isn't known at the moment yet.
1296 */
1297 for (i = 0; i < srcseg->length; i++)
1298 {
1299 skip_as = 0;
1300 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1301 for (y = 0; y < exclseg->length; y++)
1302 if (srcseg->as[i] == exclseg->as[y])
1303 {
1304 skip_as = 1;
1305 // There's no sense in testing the rest of exclusion list, bail out.
1306 break;
1307 }
1308 if (!skip_as)
1309 newlen++;
1310 }
1311 /* newlen is now the number of ASns to copy */
1312 if (!newlen)
1313 continue;
1314
1315 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1316 newseg = assegment_new (srcseg->type, newlen);
1317 for (i = 0; i < srcseg->length; i++)
1318 {
1319 skip_as = 0;
1320 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1321 for (y = 0; y < exclseg->length; y++)
1322 if (srcseg->as[i] == exclseg->as[y])
1323 {
1324 skip_as = 1;
1325 break;
1326 }
1327 if (skip_as)
1328 continue;
1329 newseg->as[done++] = srcseg->as[i];
1330 }
1331 /* At his point newlen must be equal to done, and both must be positive. Append
1332 * the filtered segment to the gross result. */
1333 if (!lastseg)
1334 newpath->segments = newseg;
1335 else
1336 lastseg->next = newseg;
1337 lastseg = newseg;
1338 }
1339 aspath_str_update (newpath);
1340 /* We are happy returning even an empty AS_PATH, because the administrator
1341 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1342 * by having a match rule against certain AS_PATH regexps in the route-map index.
1343 */
1344 aspath_free (source);
1345 return newpath;
1346}
1347
paul718e3742002-12-13 20:15:29 +00001348/* Add specified AS to the leftmost of aspath. */
1349static struct aspath *
1350aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1351{
paulfe69a502005-09-10 16:55:02 +00001352 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001353
1354 /* In case of empty aspath. */
1355 if (assegment == NULL || assegment->length == 0)
1356 {
paulfe69a502005-09-10 16:55:02 +00001357 aspath->segments = assegment_new (type, 1);
1358 aspath->segments->as[0] = asno;
1359
paul718e3742002-12-13 20:15:29 +00001360 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001361 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001362
1363 return aspath;
1364 }
1365
1366 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001367 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1368 else
paul718e3742002-12-13 20:15:29 +00001369 {
paulfe69a502005-09-10 16:55:02 +00001370 /* create new segment
1371 * push it onto head of aspath's segment chain
1372 */
paul718e3742002-12-13 20:15:29 +00001373 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001374
1375 newsegment = assegment_new (type, 1);
1376 newsegment->as[0] = asno;
1377
1378 newsegment->next = assegment;
1379 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001380 }
1381
1382 return aspath;
1383}
1384
1385/* Add specified AS to the leftmost of aspath. */
1386struct aspath *
1387aspath_add_seq (struct aspath *aspath, as_t asno)
1388{
1389 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1390}
1391
1392/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1393 as2's leftmost AS is same return 1. */
1394int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001395aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001396{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001397 const struct assegment *seg1 = NULL;
1398 const struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001399
paulfe69a502005-09-10 16:55:02 +00001400 if (!(aspath1 && aspath2))
1401 return 0;
paul718e3742002-12-13 20:15:29 +00001402
paulfe69a502005-09-10 16:55:02 +00001403 seg1 = aspath1->segments;
1404 seg2 = aspath2->segments;
1405
1406 /* find first non-confed segments for each */
1407 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1408 || (seg1->type == AS_CONFED_SET)))
1409 seg1 = seg1->next;
1410
1411 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1412 || (seg2->type == AS_CONFED_SET)))
1413 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001414
1415 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001416 if (!(seg1 && seg2
1417 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001418 return 0;
paulfe69a502005-09-10 16:55:02 +00001419
1420 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001421 return 1;
1422
1423 return 0;
1424}
1425
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001426/* Truncate an aspath after a number of hops, and put the hops remaining
1427 * at the front of another aspath. Needed for AS4 compat.
1428 *
1429 * Returned aspath is a /new/ aspath, which should either by free'd or
1430 * interned by the caller, as desired.
1431 */
1432struct aspath *
1433aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1434{
1435 struct assegment *seg, *newseg, *prevseg = NULL;
1436 struct aspath *newpath = NULL, *mergedpath;
1437 int hops, cpasns = 0;
1438
1439 if (!aspath)
1440 return NULL;
1441
1442 seg = aspath->segments;
1443
1444 /* CONFEDs should get reconciled too.. */
1445 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1446 - aspath_count_hops (as4path);
1447
1448 if (hops < 0)
1449 {
1450 if (BGP_DEBUG (as4, AS4))
1451 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1452 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1453 * which is daft behaviour - it contains vital loop-detection
1454 * information which must have been removed from AS_PATH.
1455 */
1456 hops = aspath_count_hops (aspath);
1457 }
1458
1459 if (!hops)
1460 return aspath_dup (as4path);
1461
1462 if ( BGP_DEBUG(as4, AS4))
1463 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1464 aspath->str, as4path->str);
1465
1466 while (seg && hops > 0)
1467 {
1468 switch (seg->type)
1469 {
1470 case AS_SET:
1471 case AS_CONFED_SET:
1472 hops--;
1473 cpasns = seg->length;
1474 break;
1475 case AS_CONFED_SEQUENCE:
1476 /* Should never split a confed-sequence, if hop-count
1477 * suggests we must then something's gone wrong somewhere.
1478 *
1479 * Most important goal is to preserve AS_PATHs prime function
1480 * as loop-detector, so we fudge the numbers so that the entire
1481 * confed-sequence is merged in.
1482 */
1483 if (hops < seg->length)
1484 {
1485 if (BGP_DEBUG (as4, AS4))
1486 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1487 " across 2/4 ASN boundary somewhere, broken..");
1488 hops = seg->length;
1489 }
1490 case AS_SEQUENCE:
1491 cpasns = MIN(seg->length, hops);
1492 hops -= seg->length;
1493 }
1494
1495 assert (cpasns <= seg->length);
1496
1497 newseg = assegment_new (seg->type, 0);
1498 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1499
1500 if (!newpath)
1501 {
1502 newpath = aspath_new ();
1503 newpath->segments = newseg;
1504 }
1505 else
1506 prevseg->next = newseg;
1507
1508 prevseg = newseg;
1509 seg = seg->next;
1510 }
1511
1512 /* We may be able to join some segments here, and we must
1513 * do this because... we want normalised aspaths in out hash
1514 * and we do not want to stumble in aspath_put.
1515 */
1516 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1517 aspath_free (newpath);
1518 mergedpath->segments = assegment_normalise (mergedpath->segments);
1519 aspath_str_update (mergedpath);
1520
1521 if ( BGP_DEBUG(as4, AS4))
1522 zlog_debug ("[AS4] result of synthesizing is %s",
1523 mergedpath->str);
1524
1525 return mergedpath;
1526}
1527
paul718e3742002-12-13 20:15:29 +00001528/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1529 as2's leftmost AS is same return 1. (confederation as-path
1530 only). */
1531int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001532aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001533{
paulfe69a502005-09-10 16:55:02 +00001534 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001535 return 0;
paulfe69a502005-09-10 16:55:02 +00001536
paulad727402005-11-23 02:47:02 +00001537 if ( !(aspath1->segments && aspath2->segments) )
1538 return 0;
1539
paulfe69a502005-09-10 16:55:02 +00001540 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1541 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001542 return 0;
paulfe69a502005-09-10 16:55:02 +00001543
1544 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001545 return 1;
1546
1547 return 0;
1548}
1549
paulfe69a502005-09-10 16:55:02 +00001550/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1551 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001552struct aspath *
1553aspath_delete_confed_seq (struct aspath *aspath)
1554{
paulfe69a502005-09-10 16:55:02 +00001555 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001556
paulfe69a502005-09-10 16:55:02 +00001557 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001558 return aspath;
1559
paulfe69a502005-09-10 16:55:02 +00001560 seg = aspath->segments;
1561
1562 /* "if the first path segment of the AS_PATH is
1563 * of type AS_CONFED_SEQUENCE,"
1564 */
1565 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1566 return aspath;
paul718e3742002-12-13 20:15:29 +00001567
paulfe69a502005-09-10 16:55:02 +00001568 /* "... that segment and any immediately following segments
1569 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1570 * from the AS_PATH attribute,"
1571 */
1572 while (seg &&
1573 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001574 {
paulfe69a502005-09-10 16:55:02 +00001575 aspath->segments = seg->next;
1576 assegment_free (seg);
1577 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001578 }
paulfe69a502005-09-10 16:55:02 +00001579 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001580 return aspath;
1581}
1582
1583/* Add new AS number to the leftmost part of the aspath as
1584 AS_CONFED_SEQUENCE. */
1585struct aspath*
1586aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1587{
1588 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1589}
1590
1591/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001592static void
paul718e3742002-12-13 20:15:29 +00001593aspath_as_add (struct aspath *as, as_t asno)
1594{
paulfe69a502005-09-10 16:55:02 +00001595 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001596
paulfe69a502005-09-10 16:55:02 +00001597 if (!seg)
1598 return;
1599
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001600 /* Last segment search procedure. */
1601 while (seg->next)
1602 seg = seg->next;
1603
paulfe69a502005-09-10 16:55:02 +00001604 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001605}
1606
1607/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001608static void
paul718e3742002-12-13 20:15:29 +00001609aspath_segment_add (struct aspath *as, int type)
1610{
paulfe69a502005-09-10 16:55:02 +00001611 struct assegment *seg = as->segments;
1612 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001613
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001614 if (seg)
1615 {
1616 while (seg->next)
1617 seg = seg->next;
1618 seg->next = new;
1619 }
paul718e3742002-12-13 20:15:29 +00001620 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001621 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001622}
1623
1624struct aspath *
paul94f2b392005-06-28 12:44:16 +00001625aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001626{
Paul Jakmaab005292010-11-27 22:48:34 +00001627 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001628}
1629
1630struct aspath *
paul94f2b392005-06-28 12:44:16 +00001631aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001632{
1633 struct aspath *aspath;
1634
1635 aspath = aspath_new ();
1636 aspath->str = aspath_make_str_count (aspath);
1637 return aspath;
1638}
1639
1640unsigned long
paulfe69a502005-09-10 16:55:02 +00001641aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001642{
1643 return ashash->count;
1644}
1645
1646/*
1647 Theoretically, one as path can have:
1648
1649 One BGP packet size should be less than 4096.
1650 One BGP attribute size should be less than 4096 - BGP header size.
1651 One BGP aspath size should be less than 4096 - BGP header size -
1652 BGP mandantry attribute size.
1653*/
1654
1655/* AS path string lexical token enum. */
1656enum as_token
1657{
1658 as_token_asval,
1659 as_token_set_start,
1660 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001661 as_token_confed_seq_start,
1662 as_token_confed_seq_end,
1663 as_token_confed_set_start,
1664 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001665 as_token_unknown
1666};
1667
1668/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001669static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001670aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001671{
paulfd79ac92004-10-13 05:06:08 +00001672 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001673
paulfe69a502005-09-10 16:55:02 +00001674 /* Skip seperators (space for sequences, ',' for sets). */
1675 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001676 p++;
1677
1678 /* Check the end of the string and type specify characters
1679 (e.g. {}()). */
1680 switch (*p)
1681 {
1682 case '\0':
1683 return NULL;
paul718e3742002-12-13 20:15:29 +00001684 case '{':
1685 *token = as_token_set_start;
1686 p++;
1687 return p;
paul718e3742002-12-13 20:15:29 +00001688 case '}':
1689 *token = as_token_set_end;
1690 p++;
1691 return p;
paul718e3742002-12-13 20:15:29 +00001692 case '(':
paulfe69a502005-09-10 16:55:02 +00001693 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001694 p++;
1695 return p;
paul718e3742002-12-13 20:15:29 +00001696 case ')':
paulfe69a502005-09-10 16:55:02 +00001697 *token = as_token_confed_seq_end;
1698 p++;
1699 return p;
paulfe69a502005-09-10 16:55:02 +00001700 case '[':
1701 *token = as_token_confed_set_start;
1702 p++;
1703 return p;
paulfe69a502005-09-10 16:55:02 +00001704 case ']':
1705 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001706 p++;
1707 return p;
paul718e3742002-12-13 20:15:29 +00001708 }
1709
1710 /* Check actual AS value. */
1711 if (isdigit ((int) *p))
1712 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001713 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001714
paul718e3742002-12-13 20:15:29 +00001715 *token = as_token_asval;
1716 asval = (*p - '0');
1717 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001718
paul718e3742002-12-13 20:15:29 +00001719 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001720 {
1721 asval *= 10;
1722 asval += (*p - '0');
1723 p++;
1724 }
paul718e3742002-12-13 20:15:29 +00001725 *asno = asval;
1726 return p;
1727 }
1728
1729 /* There is no match then return unknown token. */
1730 *token = as_token_unknown;
1731 return p++;
1732}
1733
1734struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001735aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001736{
paul3fff6ff2006-02-05 17:55:35 +00001737 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001738 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001739 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001740 struct aspath *aspath;
1741 int needtype;
1742
1743 aspath = aspath_new ();
1744
1745 /* We start default type as AS_SEQUENCE. */
1746 as_type = AS_SEQUENCE;
1747 needtype = 1;
1748
1749 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1750 {
1751 switch (token)
1752 {
1753 case as_token_asval:
1754 if (needtype)
1755 {
1756 aspath_segment_add (aspath, as_type);
1757 needtype = 0;
1758 }
1759 aspath_as_add (aspath, asno);
1760 break;
1761 case as_token_set_start:
1762 as_type = AS_SET;
1763 aspath_segment_add (aspath, as_type);
1764 needtype = 0;
1765 break;
1766 case as_token_set_end:
1767 as_type = AS_SEQUENCE;
1768 needtype = 1;
1769 break;
paulfe69a502005-09-10 16:55:02 +00001770 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001771 as_type = AS_CONFED_SEQUENCE;
1772 aspath_segment_add (aspath, as_type);
1773 needtype = 0;
1774 break;
paulfe69a502005-09-10 16:55:02 +00001775 case as_token_confed_seq_end:
1776 as_type = AS_SEQUENCE;
1777 needtype = 1;
1778 break;
1779 case as_token_confed_set_start:
1780 as_type = AS_CONFED_SET;
1781 aspath_segment_add (aspath, as_type);
1782 needtype = 0;
1783 break;
1784 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001785 as_type = AS_SEQUENCE;
1786 needtype = 1;
1787 break;
1788 case as_token_unknown:
1789 default:
paulfe69a502005-09-10 16:55:02 +00001790 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001791 return NULL;
paul718e3742002-12-13 20:15:29 +00001792 }
1793 }
1794
1795 aspath->str = aspath_make_str_count (aspath);
1796
1797 return aspath;
1798}
1799
1800/* Make hash value by raw aspath data. */
1801unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001802aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001803{
Paul Jakma923de652007-04-29 18:25:17 +00001804 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001805 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001806
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001807 if (!aspath->str)
1808 aspath_str_update (aspath);
1809
1810 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001811
1812 return key;
1813}
1814
1815/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001816static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001817aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001818{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001819 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1820 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001821
1822 while (seg1 || seg2)
1823 {
1824 int i;
1825 if ((!seg1 && seg2) || (seg1 && !seg2))
1826 return 0;
1827 if (seg1->type != seg2->type)
1828 return 0;
1829 if (seg1->length != seg2->length)
1830 return 0;
1831 for (i = 0; i < seg1->length; i++)
1832 if (seg1->as[i] != seg2->as[i])
1833 return 0;
1834 seg1 = seg1->next;
1835 seg2 = seg2->next;
1836 }
1837 return 1;
paul718e3742002-12-13 20:15:29 +00001838}
1839
1840/* AS path hash initialize. */
1841void
paul94f2b392005-06-28 12:44:16 +00001842aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001843{
1844 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1845}
paul8fdc32a2006-01-16 12:01:29 +00001846
1847void
1848aspath_finish (void)
1849{
1850 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00001851 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00001852
1853 if (snmp_stream)
1854 stream_free (snmp_stream);
1855}
paul718e3742002-12-13 20:15:29 +00001856
1857/* return and as path value */
1858const char *
1859aspath_print (struct aspath *as)
1860{
paulfe69a502005-09-10 16:55:02 +00001861 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001862}
1863
1864/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001865/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1866 * AS_PATH wasn't empty.
1867 */
paul718e3742002-12-13 20:15:29 +00001868void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001869aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001870{
Paul Jakmab2518c12006-05-12 23:48:40 +00001871 assert (format);
1872 vty_out (vty, format, as->str);
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001873 if (strlen (as->str) && strlen (suffix))
1874 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001875}
1876
paul94f2b392005-06-28 12:44:16 +00001877static void
paul718e3742002-12-13 20:15:29 +00001878aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1879{
1880 struct aspath *as;
1881
1882 as = (struct aspath *) backet->data;
1883
paulefa9f832002-12-13 21:47:59 +00001884 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001885 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1886}
1887
1888/* Print all aspath and hash information. This function is used from
1889 `show ip bgp paths' command. */
1890void
1891aspath_print_all_vty (struct vty *vty)
1892{
1893 hash_iterate (ashash,
1894 (void (*) (struct hash_backet *, void *))
1895 aspath_show_all_iterator,
1896 vty);
1897}