blob: 776c7127e5786228ba49b6bc3b3f27192be68b8a [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
Paul Jakmaf63f06d2011-04-08 12:44:43 +010094static as_t *
paulfe69a502005-09-10 16:55:02 +000095assegment_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
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100100static void
paulfe69a502005-09-10 16:55:02 +0000101assegment_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 */
Paul Jakmab881c702010-11-23 16:35:42 +0000677static int
678assegments_parse (struct stream *s, size_t length,
679 struct assegment **result, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000680{
681 struct assegment_header segh;
682 struct assegment *seg, *prev = NULL, *head = NULL;
Paul Jakmaab005292010-11-27 22:48:34 +0000683 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000684
Paul Jakmaab005292010-11-27 22:48:34 +0000685 /* empty aspath (ie iBGP or somesuch) */
686 if (length == 0)
Paul Jakmab881c702010-11-23 16:35:42 +0000687 return 0;
paulfe69a502005-09-10 16:55:02 +0000688
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000689 if (BGP_DEBUG (as4, AS4_SEGMENT))
690 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
691 (unsigned long) length);
Paul Jakmaab005292010-11-27 22:48:34 +0000692 /* basic checks */
693 if ((STREAM_READABLE(s) < length)
694 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
695 || (length % AS16_VALUE_SIZE ))
Paul Jakmab881c702010-11-23 16:35:42 +0000696 return -1;
paulfe69a502005-09-10 16:55:02 +0000697
Paul Jakmaab005292010-11-27 22:48:34 +0000698 while (bytes < length)
paulfe69a502005-09-10 16:55:02 +0000699 {
700 int i;
Chris Hallcddb8112010-08-09 22:31:37 +0400701 size_t seg_size;
paulfe69a502005-09-10 16:55:02 +0000702
Paul Jakmaab005292010-11-27 22:48:34 +0000703 if ((length - bytes) <= AS_HEADER_SIZE)
Chris Hallcddb8112010-08-09 22:31:37 +0400704 {
Paul Jakmaab005292010-11-27 22:48:34 +0000705 if (head)
706 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000707 return -1;
Paul Jakmaab005292010-11-27 22:48:34 +0000708 }
709
710 /* softly softly, get the header first on its own */
paulfe69a502005-09-10 16:55:02 +0000711 segh.type = stream_getc (s);
712 segh.length = stream_getc (s);
713
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000714 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
715
716 if (BGP_DEBUG (as4, AS4_SEGMENT))
717 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
718 segh.type, segh.length);
719
Paul Jakmaab005292010-11-27 22:48:34 +0000720 /* check it.. */
721 if ( ((bytes + seg_size) > length)
722 /* 1771bis 4.3b: seg length contains one or more */
723 || (segh.length == 0)
724 /* Paranoia in case someone changes type of segment length.
725 * Shift both values by 0x10 to make the comparison operate
726 * on more, than 8 bits (otherwise it's a warning, bug #564).
Denis Ovsienko2eb445e2009-12-04 17:32:54 +0300727 */
Paul Jakmaab005292010-11-27 22:48:34 +0000728 || ((sizeof segh.length > 1)
729 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
paulfe69a502005-09-10 16:55:02 +0000730 {
Paul Jakmaab005292010-11-27 22:48:34 +0000731 if (head)
paulfe69a502005-09-10 16:55:02 +0000732 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000733 return -1;
paulfe69a502005-09-10 16:55:02 +0000734 }
735
Paul Jakmaab005292010-11-27 22:48:34 +0000736 switch (segh.type)
737 {
738 case AS_SEQUENCE:
739 case AS_SET:
740 case AS_CONFED_SEQUENCE:
741 case AS_CONFED_SET:
742 break;
743 default:
744 if (head)
745 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000746 return -1;
Paul Jakmaab005292010-11-27 22:48:34 +0000747 }
Chris Hallcddb8112010-08-09 22:31:37 +0400748
paulfe69a502005-09-10 16:55:02 +0000749 /* now its safe to trust lengths */
750 seg = assegment_new (segh.type, segh.length);
751
752 if (head)
753 prev->next = seg;
754 else /* it's the first segment */
755 head = prev = seg;
756
757 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000758 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
759
Paul Jakmaab005292010-11-27 22:48:34 +0000760 bytes += seg_size;
761
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000762 if (BGP_DEBUG (as4, AS4_SEGMENT))
Paul Jakmaab005292010-11-27 22:48:34 +0000763 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
764 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000765
766 prev = seg;
767 }
768
Paul Jakmab881c702010-11-23 16:35:42 +0000769 *result = assegment_normalise (head);
770 return 0;
paulfe69a502005-09-10 16:55:02 +0000771}
772
Paul Jakmaab005292010-11-27 22:48:34 +0000773/* AS path parse function. pnt is a pointer to byte stream and length
774 is length of byte stream. If there is same AS path in the the AS
Paul Jakmab881c702010-11-23 16:35:42 +0000775 path hash then return it else make new AS path structure.
776
777 On error NULL is returned.
778 */
paul718e3742002-12-13 20:15:29 +0000779struct aspath *
Paul Jakmaab005292010-11-27 22:48:34 +0000780aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000781{
782 struct aspath as;
783 struct aspath *find;
784
Paul Jakmaab005292010-11-27 22:48:34 +0000785 /* If length is odd it's malformed AS path. */
786 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
787 * otherwise its malformed when length is larger than 2 and (length-2)
788 * is not dividable by 4.
789 * But... this time we're lazy
790 */
791 if (length % AS16_VALUE_SIZE )
792 return NULL;
Chris Hallcddb8112010-08-09 22:31:37 +0400793
Paul Jakmaab005292010-11-27 22:48:34 +0000794 memset (&as, 0, sizeof (struct aspath));
Paul Jakmab881c702010-11-23 16:35:42 +0000795 if (assegments_parse (s, length, &as.segments, use32bit) < 0)
796 return NULL;
paulfe69a502005-09-10 16:55:02 +0000797
paul718e3742002-12-13 20:15:29 +0000798 /* If already same aspath exist then return it. */
799 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000800
801 /* aspath_hash_alloc dupes segments too. that probably could be
802 * optimised out.
803 */
804 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000805 if (as.str)
806 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000807
Paul Jakmaab005292010-11-27 22:48:34 +0000808 if (! find)
809 return NULL;
paul718e3742002-12-13 20:15:29 +0000810 find->refcnt++;
811
812 return find;
813}
814
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100815static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000816assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000817{
paulfe69a502005-09-10 16:55:02 +0000818 int i;
819 assert (num <= AS_SEGMENT_MAX);
820
821 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000822 if ( use32bit )
823 stream_putl (s, as[i]);
824 else
825 {
826 if ( as[i] <= BGP_AS_MAX )
827 stream_putw(s, as[i]);
828 else
829 stream_putw(s, BGP_AS_TRANS);
830 }
paul718e3742002-12-13 20:15:29 +0000831}
832
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100833static size_t
paulfe69a502005-09-10 16:55:02 +0000834assegment_header_put (struct stream *s, u_char type, int length)
835{
836 size_t lenp;
837 assert (length <= AS_SEGMENT_MAX);
838 stream_putc (s, type);
839 lenp = stream_get_endp (s);
840 stream_putc (s, length);
841 return lenp;
842}
843
844/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000845size_t
846aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000847{
848 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000849 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000850
851 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000852 return 0;
paulfe69a502005-09-10 16:55:02 +0000853
854 if (seg)
855 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000856 /*
857 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
858 * At the moment, we would write out a partial aspath, and our peer
859 * will complain and drop the session :-/
860 *
861 * The general assumption here is that many things tested will
862 * never happen. And, in real live, up to now, they have not.
863 */
864 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000865 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000866 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000867 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000868 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000869 size_t lenp;
870
871 /* Overlength segments have to be split up */
872 while ( (seg->length - written) > AS_SEGMENT_MAX)
873 {
874 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000875 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000876 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000877 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000878 }
879
880 /* write the final segment, probably is also the first */
881 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000882 assegment_data_put (s, (seg->as + written), seg->length - written,
883 use32bit);
paulfe69a502005-09-10 16:55:02 +0000884
885 /* Sequence-type segments can be 'packed' together
886 * Case of a segment which was overlength and split up
887 * will be missed here, but that doesn't matter.
888 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000889 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000890 {
891 /* NB: We should never normally get here given we
892 * normalise aspath data when parse them. However, better
893 * safe than sorry. We potentially could call
894 * assegment_normalise here instead, but it's cheaper and
895 * easier to do it on the fly here rather than go through
896 * the segment list twice every time we write out
897 * aspath's.
898 */
899
900 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000901 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000902
903 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000904 stream_putc_at (s, lenp, seg->length - written + next->length);
905 asns_packed += next->length;
906
907 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000908 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000909
910 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
911 use32bit);
912 seg = next;
paulfe69a502005-09-10 16:55:02 +0000913 }
914 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000915 return bytes;
paulfe69a502005-09-10 16:55:02 +0000916}
917
918/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
919 * We have no way to manage the storage, so we use a static stream
920 * wrapper around aspath_put.
921 */
922u_char *
923aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
924{
925#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000926
927 if (!snmp_stream)
928 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000929 else
paul8fdc32a2006-01-16 12:01:29 +0000930 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000931
932 if (!as)
933 {
934 *varlen = 0;
935 return NULL;
936 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000937 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000938
paul8fdc32a2006-01-16 12:01:29 +0000939 *varlen = stream_get_endp (snmp_stream);
940 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000941}
942
943#define min(A,B) ((A) < (B) ? (A) : (B))
944
paul94f2b392005-06-28 12:44:16 +0000945static struct assegment *
paul718e3742002-12-13 20:15:29 +0000946aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
947 as_t as)
948{
949 int i;
950
951 /* If this is first AS set member, create new as-set segment. */
952 if (asset == NULL)
953 {
paulfe69a502005-09-10 16:55:02 +0000954 asset = assegment_new (AS_SET, 1);
955 if (! aspath->segments)
956 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000957 else
paulfe69a502005-09-10 16:55:02 +0000958 {
959 struct assegment *seg = aspath->segments;
960 while (seg->next)
961 seg = seg->next;
962 seg->next = asset;
963 }
paul718e3742002-12-13 20:15:29 +0000964 asset->type = AS_SET;
965 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000966 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000967 }
968 else
969 {
paul718e3742002-12-13 20:15:29 +0000970 /* Check this AS value already exists or not. */
971 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000972 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000973 return asset;
paulfe69a502005-09-10 16:55:02 +0000974
paul718e3742002-12-13 20:15:29 +0000975 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000976 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
977 asset->length * AS_VALUE_SIZE);
978 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000979 }
paulfe69a502005-09-10 16:55:02 +0000980
paul718e3742002-12-13 20:15:29 +0000981
982 return asset;
983}
984
985/* Modify as1 using as2 for aggregation. */
986struct aspath *
987aspath_aggregate (struct aspath *as1, struct aspath *as2)
988{
989 int i;
990 int minlen;
991 int match;
paulfe69a502005-09-10 16:55:02 +0000992 int from;
993 struct assegment *seg1 = as1->segments;
994 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000995 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000996 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000997 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +0000998
999 match = 0;
1000 minlen = 0;
1001 aspath = NULL;
1002 asset = NULL;
paul718e3742002-12-13 20:15:29 +00001003
1004 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +00001005 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001006 {
paul718e3742002-12-13 20:15:29 +00001007 /* Check segment type. */
1008 if (seg1->type != seg2->type)
1009 break;
1010
1011 /* Minimum segment length. */
1012 minlen = min (seg1->length, seg2->length);
1013
1014 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001015 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001016 break;
1017
1018 if (match)
1019 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001020 struct assegment *seg = assegment_new (seg1->type, 0);
1021
1022 seg = assegment_append_asns (seg, seg1->as, match);
1023
paul718e3742002-12-13 20:15:29 +00001024 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001025 {
1026 aspath = aspath_new ();
1027 aspath->segments = seg;
1028 }
1029 else
1030 prevseg->next = seg;
1031
1032 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001033 }
1034
1035 if (match != minlen || match != seg1->length
1036 || seg1->length != seg2->length)
1037 break;
paulfe69a502005-09-10 16:55:02 +00001038
1039 seg1 = seg1->next;
1040 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001041 }
1042
1043 if (! aspath)
1044 aspath = aspath_new();
1045
1046 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001047 from = match;
1048 while (seg1)
paul718e3742002-12-13 20:15:29 +00001049 {
paulfe69a502005-09-10 16:55:02 +00001050 for (i = from; i < seg1->length; i++)
1051 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1052
1053 from = 0;
1054 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001055 }
1056
paulfe69a502005-09-10 16:55:02 +00001057 from = match;
1058 while (seg2)
paul718e3742002-12-13 20:15:29 +00001059 {
paulfe69a502005-09-10 16:55:02 +00001060 for (i = from; i < seg2->length; i++)
1061 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001062
paulfe69a502005-09-10 16:55:02 +00001063 from = 0;
1064 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001065 }
paulfe69a502005-09-10 16:55:02 +00001066
1067 assegment_normalise (aspath->segments);
1068 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001069 return aspath;
1070}
1071
1072/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1073 attribute, check the leftmost AS number in the AS_PATH attribute is
1074 or not the peer's AS number. */
1075int
1076aspath_firstas_check (struct aspath *aspath, as_t asno)
1077{
paulfe69a502005-09-10 16:55:02 +00001078 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001079 return 0;
paulfe69a502005-09-10 16:55:02 +00001080
1081 if (aspath->segments
1082 && (aspath->segments->type == AS_SEQUENCE)
1083 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001084 return 1;
1085
1086 return 0;
1087}
1088
Paul Jakma1f742f22006-08-06 15:52:11 +00001089/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001090int
1091aspath_loop_check (struct aspath *aspath, as_t asno)
1092{
paulfe69a502005-09-10 16:55:02 +00001093 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001094 int count = 0;
1095
Paul Jakma1f742f22006-08-06 15:52:11 +00001096 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001097 return 0;
paulfe69a502005-09-10 16:55:02 +00001098
1099 seg = aspath->segments;
1100
1101 while (seg)
paul718e3742002-12-13 20:15:29 +00001102 {
1103 int i;
paul718e3742002-12-13 20:15:29 +00001104
paulfe69a502005-09-10 16:55:02 +00001105 for (i = 0; i < seg->length; i++)
1106 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001107 count++;
paulfe69a502005-09-10 16:55:02 +00001108
1109 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001110 }
1111 return count;
1112}
1113
1114/* When all of AS path is private AS return 1. */
1115int
1116aspath_private_as_check (struct aspath *aspath)
1117{
paulfe69a502005-09-10 16:55:02 +00001118 struct assegment *seg;
1119
1120 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001121 return 0;
paulfe69a502005-09-10 16:55:02 +00001122
1123 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001124
paulfe69a502005-09-10 16:55:02 +00001125 while (seg)
paul718e3742002-12-13 20:15:29 +00001126 {
1127 int i;
paul718e3742002-12-13 20:15:29 +00001128
paulfe69a502005-09-10 16:55:02 +00001129 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001130 {
paulfe69a502005-09-10 16:55:02 +00001131 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1132 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001133 return 0;
1134 }
paulfe69a502005-09-10 16:55:02 +00001135 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001136 }
1137 return 1;
1138}
1139
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001140/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1141int
1142aspath_confed_check (struct aspath *aspath)
1143{
1144 struct assegment *seg;
1145
1146 if ( !(aspath && aspath->segments) )
1147 return 0;
1148
1149 seg = aspath->segments;
1150
1151 while (seg)
1152 {
1153 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1154 return 1;
1155 seg = seg->next;
1156 }
1157 return 0;
1158}
1159
1160/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1161 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1162int
1163aspath_left_confed_check (struct aspath *aspath)
1164{
1165
1166 if ( !(aspath && aspath->segments) )
1167 return 0;
1168
1169 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1170 || (aspath->segments->type == AS_CONFED_SET) )
1171 return 1;
1172
1173 return 0;
1174}
1175
paul718e3742002-12-13 20:15:29 +00001176/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001177static struct aspath *
paul718e3742002-12-13 20:15:29 +00001178aspath_merge (struct aspath *as1, struct aspath *as2)
1179{
paulfe69a502005-09-10 16:55:02 +00001180 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001181
1182 if (! as1 || ! as2)
1183 return NULL;
1184
paulfe69a502005-09-10 16:55:02 +00001185 last = new = assegment_dup_all (as1->segments);
1186
1187 /* find the last valid segment */
1188 while (last && last->next)
1189 last = last->next;
1190
1191 last->next = as2->segments;
1192 as2->segments = new;
1193 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001194 return as2;
1195}
1196
1197/* Prepend as1 to as2. as2 should be uninterned aspath. */
1198struct aspath *
1199aspath_prepend (struct aspath *as1, struct aspath *as2)
1200{
paulfe69a502005-09-10 16:55:02 +00001201 struct assegment *seg1;
1202 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001203
1204 if (! as1 || ! as2)
1205 return NULL;
paulfe69a502005-09-10 16:55:02 +00001206
1207 seg1 = as1->segments;
1208 seg2 = as2->segments;
1209
1210 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001211 if (seg2 == NULL)
1212 {
paulfe69a502005-09-10 16:55:02 +00001213 as2->segments = assegment_dup_all (as1->segments);
1214 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001215 return as2;
1216 }
paulfe69a502005-09-10 16:55:02 +00001217
1218 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001219 if (seg1 == NULL)
1220 return as2;
paulfe69a502005-09-10 16:55:02 +00001221
1222 /* find the tail as1's segment chain. */
1223 while (seg1 && seg1->next)
1224 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001225
Vasilis Tsiligiannis736d4402009-07-20 01:59:10 +03001226 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1227 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1228 as2 = aspath_delete_confed_seq (as2);
1229
paul718e3742002-12-13 20:15:29 +00001230 /* Compare last segment type of as1 and first segment type of as2. */
1231 if (seg1->type != seg2->type)
1232 return aspath_merge (as1, as2);
1233
1234 if (seg1->type == AS_SEQUENCE)
1235 {
paulfe69a502005-09-10 16:55:02 +00001236 /* We have two chains of segments, as1->segments and seg2,
1237 * and we have to attach them together, merging the attaching
1238 * segments together into one.
1239 *
1240 * 1. dupe as1->segments onto head of as2
1241 * 2. merge seg2's asns onto last segment of this new chain
1242 * 3. attach chain after seg2
1243 */
paul718e3742002-12-13 20:15:29 +00001244
paulfe69a502005-09-10 16:55:02 +00001245 /* dupe as1 onto as2's head */
1246 seg1 = as2->segments = assegment_dup_all (as1->segments);
1247
1248 /* refind the tail of as2, reusing seg1 */
1249 while (seg1 && seg1->next)
1250 seg1 = seg1->next;
1251
1252 /* merge the old head, seg2, into tail, seg1 */
1253 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1254
1255 /* bypass the merged seg2, and attach any chain after it to
1256 * chain descending from as2's head
1257 */
1258 seg1->next = seg2->next;
1259
1260 /* seg2 is now referenceless and useless*/
1261 assegment_free (seg2);
1262
1263 /* we've now prepended as1's segment chain to as2, merging
1264 * the inbetween AS_SEQUENCE of seg2 in the process
1265 */
1266 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001267 return as2;
1268 }
1269 else
1270 {
1271 /* AS_SET merge code is needed at here. */
1272 return aspath_merge (as1, as2);
1273 }
paulfe69a502005-09-10 16:55:02 +00001274 /* XXX: Ermmm, what if as1 has multiple segments?? */
1275
paul718e3742002-12-13 20:15:29 +00001276 /* Not reached */
1277}
1278
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001279/* Iterate over AS_PATH segments and wipe all occurences of the
1280 * listed AS numbers. Hence some segments may lose some or even
1281 * all data on the way, the operation is implemented as a smarter
1282 * version of aspath_dup(), which allocates memory to hold the new
1283 * data, not the original. The new AS path is returned.
1284 */
1285struct aspath *
1286aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1287{
1288 struct assegment * srcseg, * exclseg, * lastseg;
1289 struct aspath * newpath;
1290
1291 newpath = aspath_new();
1292 lastseg = NULL;
1293
1294 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1295 {
1296 unsigned i, y, newlen = 0, done = 0, skip_as;
1297 struct assegment * newseg;
1298
1299 /* Find out, how much ASns are we going to pick from this segment.
1300 * We can't perform filtering right inline, because the size of
1301 * the new segment isn't known at the moment yet.
1302 */
1303 for (i = 0; i < srcseg->length; i++)
1304 {
1305 skip_as = 0;
1306 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1307 for (y = 0; y < exclseg->length; y++)
1308 if (srcseg->as[i] == exclseg->as[y])
1309 {
1310 skip_as = 1;
1311 // There's no sense in testing the rest of exclusion list, bail out.
1312 break;
1313 }
1314 if (!skip_as)
1315 newlen++;
1316 }
1317 /* newlen is now the number of ASns to copy */
1318 if (!newlen)
1319 continue;
1320
1321 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1322 newseg = assegment_new (srcseg->type, newlen);
1323 for (i = 0; i < srcseg->length; i++)
1324 {
1325 skip_as = 0;
1326 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1327 for (y = 0; y < exclseg->length; y++)
1328 if (srcseg->as[i] == exclseg->as[y])
1329 {
1330 skip_as = 1;
1331 break;
1332 }
1333 if (skip_as)
1334 continue;
1335 newseg->as[done++] = srcseg->as[i];
1336 }
1337 /* At his point newlen must be equal to done, and both must be positive. Append
1338 * the filtered segment to the gross result. */
1339 if (!lastseg)
1340 newpath->segments = newseg;
1341 else
1342 lastseg->next = newseg;
1343 lastseg = newseg;
1344 }
1345 aspath_str_update (newpath);
1346 /* We are happy returning even an empty AS_PATH, because the administrator
1347 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1348 * by having a match rule against certain AS_PATH regexps in the route-map index.
1349 */
1350 aspath_free (source);
1351 return newpath;
1352}
1353
paul718e3742002-12-13 20:15:29 +00001354/* Add specified AS to the leftmost of aspath. */
1355static struct aspath *
1356aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1357{
paulfe69a502005-09-10 16:55:02 +00001358 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001359
1360 /* In case of empty aspath. */
1361 if (assegment == NULL || assegment->length == 0)
1362 {
paulfe69a502005-09-10 16:55:02 +00001363 aspath->segments = assegment_new (type, 1);
1364 aspath->segments->as[0] = asno;
1365
paul718e3742002-12-13 20:15:29 +00001366 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001367 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001368
1369 return aspath;
1370 }
1371
1372 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001373 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1374 else
paul718e3742002-12-13 20:15:29 +00001375 {
paulfe69a502005-09-10 16:55:02 +00001376 /* create new segment
1377 * push it onto head of aspath's segment chain
1378 */
paul718e3742002-12-13 20:15:29 +00001379 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001380
1381 newsegment = assegment_new (type, 1);
1382 newsegment->as[0] = asno;
1383
1384 newsegment->next = assegment;
1385 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001386 }
1387
1388 return aspath;
1389}
1390
1391/* Add specified AS to the leftmost of aspath. */
1392struct aspath *
1393aspath_add_seq (struct aspath *aspath, as_t asno)
1394{
1395 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1396}
1397
1398/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1399 as2's leftmost AS is same return 1. */
1400int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001401aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001402{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001403 const struct assegment *seg1 = NULL;
1404 const struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001405
paulfe69a502005-09-10 16:55:02 +00001406 if (!(aspath1 && aspath2))
1407 return 0;
paul718e3742002-12-13 20:15:29 +00001408
paulfe69a502005-09-10 16:55:02 +00001409 seg1 = aspath1->segments;
1410 seg2 = aspath2->segments;
1411
1412 /* find first non-confed segments for each */
1413 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1414 || (seg1->type == AS_CONFED_SET)))
1415 seg1 = seg1->next;
1416
1417 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1418 || (seg2->type == AS_CONFED_SET)))
1419 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001420
1421 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001422 if (!(seg1 && seg2
1423 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001424 return 0;
paulfe69a502005-09-10 16:55:02 +00001425
1426 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001427 return 1;
1428
1429 return 0;
1430}
1431
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001432/* Truncate an aspath after a number of hops, and put the hops remaining
1433 * at the front of another aspath. Needed for AS4 compat.
1434 *
1435 * Returned aspath is a /new/ aspath, which should either by free'd or
1436 * interned by the caller, as desired.
1437 */
1438struct aspath *
1439aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1440{
1441 struct assegment *seg, *newseg, *prevseg = NULL;
1442 struct aspath *newpath = NULL, *mergedpath;
1443 int hops, cpasns = 0;
1444
1445 if (!aspath)
1446 return NULL;
1447
1448 seg = aspath->segments;
1449
1450 /* CONFEDs should get reconciled too.. */
1451 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1452 - aspath_count_hops (as4path);
1453
1454 if (hops < 0)
1455 {
1456 if (BGP_DEBUG (as4, AS4))
1457 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1458 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1459 * which is daft behaviour - it contains vital loop-detection
1460 * information which must have been removed from AS_PATH.
1461 */
1462 hops = aspath_count_hops (aspath);
1463 }
1464
1465 if (!hops)
1466 return aspath_dup (as4path);
1467
1468 if ( BGP_DEBUG(as4, AS4))
1469 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1470 aspath->str, as4path->str);
1471
1472 while (seg && hops > 0)
1473 {
1474 switch (seg->type)
1475 {
1476 case AS_SET:
1477 case AS_CONFED_SET:
1478 hops--;
1479 cpasns = seg->length;
1480 break;
1481 case AS_CONFED_SEQUENCE:
1482 /* Should never split a confed-sequence, if hop-count
1483 * suggests we must then something's gone wrong somewhere.
1484 *
1485 * Most important goal is to preserve AS_PATHs prime function
1486 * as loop-detector, so we fudge the numbers so that the entire
1487 * confed-sequence is merged in.
1488 */
1489 if (hops < seg->length)
1490 {
1491 if (BGP_DEBUG (as4, AS4))
1492 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1493 " across 2/4 ASN boundary somewhere, broken..");
1494 hops = seg->length;
1495 }
1496 case AS_SEQUENCE:
1497 cpasns = MIN(seg->length, hops);
1498 hops -= seg->length;
1499 }
1500
1501 assert (cpasns <= seg->length);
1502
1503 newseg = assegment_new (seg->type, 0);
1504 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1505
1506 if (!newpath)
1507 {
1508 newpath = aspath_new ();
1509 newpath->segments = newseg;
1510 }
1511 else
1512 prevseg->next = newseg;
1513
1514 prevseg = newseg;
1515 seg = seg->next;
1516 }
1517
1518 /* We may be able to join some segments here, and we must
1519 * do this because... we want normalised aspaths in out hash
1520 * and we do not want to stumble in aspath_put.
1521 */
1522 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1523 aspath_free (newpath);
1524 mergedpath->segments = assegment_normalise (mergedpath->segments);
1525 aspath_str_update (mergedpath);
1526
1527 if ( BGP_DEBUG(as4, AS4))
1528 zlog_debug ("[AS4] result of synthesizing is %s",
1529 mergedpath->str);
1530
1531 return mergedpath;
1532}
1533
paul718e3742002-12-13 20:15:29 +00001534/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1535 as2's leftmost AS is same return 1. (confederation as-path
1536 only). */
1537int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001538aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001539{
paulfe69a502005-09-10 16:55:02 +00001540 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001541 return 0;
paulfe69a502005-09-10 16:55:02 +00001542
paulad727402005-11-23 02:47:02 +00001543 if ( !(aspath1->segments && aspath2->segments) )
1544 return 0;
1545
paulfe69a502005-09-10 16:55:02 +00001546 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1547 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001548 return 0;
paulfe69a502005-09-10 16:55:02 +00001549
1550 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001551 return 1;
1552
1553 return 0;
1554}
1555
paulfe69a502005-09-10 16:55:02 +00001556/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1557 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001558struct aspath *
1559aspath_delete_confed_seq (struct aspath *aspath)
1560{
paulfe69a502005-09-10 16:55:02 +00001561 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001562
paulfe69a502005-09-10 16:55:02 +00001563 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001564 return aspath;
1565
paulfe69a502005-09-10 16:55:02 +00001566 seg = aspath->segments;
1567
1568 /* "if the first path segment of the AS_PATH is
1569 * of type AS_CONFED_SEQUENCE,"
1570 */
1571 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1572 return aspath;
paul718e3742002-12-13 20:15:29 +00001573
paulfe69a502005-09-10 16:55:02 +00001574 /* "... that segment and any immediately following segments
1575 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1576 * from the AS_PATH attribute,"
1577 */
1578 while (seg &&
1579 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001580 {
paulfe69a502005-09-10 16:55:02 +00001581 aspath->segments = seg->next;
1582 assegment_free (seg);
1583 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001584 }
paulfe69a502005-09-10 16:55:02 +00001585 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001586 return aspath;
1587}
1588
1589/* Add new AS number to the leftmost part of the aspath as
1590 AS_CONFED_SEQUENCE. */
1591struct aspath*
1592aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1593{
1594 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1595}
1596
1597/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001598static void
paul718e3742002-12-13 20:15:29 +00001599aspath_as_add (struct aspath *as, as_t asno)
1600{
paulfe69a502005-09-10 16:55:02 +00001601 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001602
paulfe69a502005-09-10 16:55:02 +00001603 if (!seg)
1604 return;
1605
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001606 /* Last segment search procedure. */
1607 while (seg->next)
1608 seg = seg->next;
1609
paulfe69a502005-09-10 16:55:02 +00001610 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001611}
1612
1613/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001614static void
paul718e3742002-12-13 20:15:29 +00001615aspath_segment_add (struct aspath *as, int type)
1616{
paulfe69a502005-09-10 16:55:02 +00001617 struct assegment *seg = as->segments;
1618 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001619
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001620 if (seg)
1621 {
1622 while (seg->next)
1623 seg = seg->next;
1624 seg->next = new;
1625 }
paul718e3742002-12-13 20:15:29 +00001626 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001627 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001628}
1629
1630struct aspath *
paul94f2b392005-06-28 12:44:16 +00001631aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001632{
Paul Jakmaab005292010-11-27 22:48:34 +00001633 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001634}
1635
1636struct aspath *
paul94f2b392005-06-28 12:44:16 +00001637aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001638{
1639 struct aspath *aspath;
1640
1641 aspath = aspath_new ();
1642 aspath->str = aspath_make_str_count (aspath);
1643 return aspath;
1644}
1645
1646unsigned long
paulfe69a502005-09-10 16:55:02 +00001647aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001648{
1649 return ashash->count;
1650}
1651
1652/*
1653 Theoretically, one as path can have:
1654
1655 One BGP packet size should be less than 4096.
1656 One BGP attribute size should be less than 4096 - BGP header size.
1657 One BGP aspath size should be less than 4096 - BGP header size -
1658 BGP mandantry attribute size.
1659*/
1660
1661/* AS path string lexical token enum. */
1662enum as_token
1663{
1664 as_token_asval,
1665 as_token_set_start,
1666 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001667 as_token_confed_seq_start,
1668 as_token_confed_seq_end,
1669 as_token_confed_set_start,
1670 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001671 as_token_unknown
1672};
1673
1674/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001675static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001676aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001677{
paulfd79ac92004-10-13 05:06:08 +00001678 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001679
paulfe69a502005-09-10 16:55:02 +00001680 /* Skip seperators (space for sequences, ',' for sets). */
1681 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001682 p++;
1683
1684 /* Check the end of the string and type specify characters
1685 (e.g. {}()). */
1686 switch (*p)
1687 {
1688 case '\0':
1689 return NULL;
paul718e3742002-12-13 20:15:29 +00001690 case '{':
1691 *token = as_token_set_start;
1692 p++;
1693 return p;
paul718e3742002-12-13 20:15:29 +00001694 case '}':
1695 *token = as_token_set_end;
1696 p++;
1697 return p;
paul718e3742002-12-13 20:15:29 +00001698 case '(':
paulfe69a502005-09-10 16:55:02 +00001699 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001700 p++;
1701 return p;
paul718e3742002-12-13 20:15:29 +00001702 case ')':
paulfe69a502005-09-10 16:55:02 +00001703 *token = as_token_confed_seq_end;
1704 p++;
1705 return p;
paulfe69a502005-09-10 16:55:02 +00001706 case '[':
1707 *token = as_token_confed_set_start;
1708 p++;
1709 return p;
paulfe69a502005-09-10 16:55:02 +00001710 case ']':
1711 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001712 p++;
1713 return p;
paul718e3742002-12-13 20:15:29 +00001714 }
1715
1716 /* Check actual AS value. */
1717 if (isdigit ((int) *p))
1718 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001719 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001720
paul718e3742002-12-13 20:15:29 +00001721 *token = as_token_asval;
1722 asval = (*p - '0');
1723 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001724
paul718e3742002-12-13 20:15:29 +00001725 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001726 {
1727 asval *= 10;
1728 asval += (*p - '0');
1729 p++;
1730 }
paul718e3742002-12-13 20:15:29 +00001731 *asno = asval;
1732 return p;
1733 }
1734
1735 /* There is no match then return unknown token. */
1736 *token = as_token_unknown;
1737 return p++;
1738}
1739
1740struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001741aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001742{
paul3fff6ff2006-02-05 17:55:35 +00001743 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001744 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001745 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001746 struct aspath *aspath;
1747 int needtype;
1748
1749 aspath = aspath_new ();
1750
1751 /* We start default type as AS_SEQUENCE. */
1752 as_type = AS_SEQUENCE;
1753 needtype = 1;
1754
1755 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1756 {
1757 switch (token)
1758 {
1759 case as_token_asval:
1760 if (needtype)
1761 {
1762 aspath_segment_add (aspath, as_type);
1763 needtype = 0;
1764 }
1765 aspath_as_add (aspath, asno);
1766 break;
1767 case as_token_set_start:
1768 as_type = AS_SET;
1769 aspath_segment_add (aspath, as_type);
1770 needtype = 0;
1771 break;
1772 case as_token_set_end:
1773 as_type = AS_SEQUENCE;
1774 needtype = 1;
1775 break;
paulfe69a502005-09-10 16:55:02 +00001776 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001777 as_type = AS_CONFED_SEQUENCE;
1778 aspath_segment_add (aspath, as_type);
1779 needtype = 0;
1780 break;
paulfe69a502005-09-10 16:55:02 +00001781 case as_token_confed_seq_end:
1782 as_type = AS_SEQUENCE;
1783 needtype = 1;
1784 break;
1785 case as_token_confed_set_start:
1786 as_type = AS_CONFED_SET;
1787 aspath_segment_add (aspath, as_type);
1788 needtype = 0;
1789 break;
1790 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001791 as_type = AS_SEQUENCE;
1792 needtype = 1;
1793 break;
1794 case as_token_unknown:
1795 default:
paulfe69a502005-09-10 16:55:02 +00001796 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001797 return NULL;
paul718e3742002-12-13 20:15:29 +00001798 }
1799 }
1800
1801 aspath->str = aspath_make_str_count (aspath);
1802
1803 return aspath;
1804}
1805
1806/* Make hash value by raw aspath data. */
1807unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001808aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001809{
Paul Jakma923de652007-04-29 18:25:17 +00001810 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001811 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001812
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001813 if (!aspath->str)
1814 aspath_str_update (aspath);
1815
1816 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001817
1818 return key;
1819}
1820
1821/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001822static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001823aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001824{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001825 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1826 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001827
1828 while (seg1 || seg2)
1829 {
1830 int i;
1831 if ((!seg1 && seg2) || (seg1 && !seg2))
1832 return 0;
1833 if (seg1->type != seg2->type)
1834 return 0;
1835 if (seg1->length != seg2->length)
1836 return 0;
1837 for (i = 0; i < seg1->length; i++)
1838 if (seg1->as[i] != seg2->as[i])
1839 return 0;
1840 seg1 = seg1->next;
1841 seg2 = seg2->next;
1842 }
1843 return 1;
paul718e3742002-12-13 20:15:29 +00001844}
1845
1846/* AS path hash initialize. */
1847void
paul94f2b392005-06-28 12:44:16 +00001848aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001849{
1850 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1851}
paul8fdc32a2006-01-16 12:01:29 +00001852
1853void
1854aspath_finish (void)
1855{
1856 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00001857 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00001858
1859 if (snmp_stream)
1860 stream_free (snmp_stream);
1861}
paul718e3742002-12-13 20:15:29 +00001862
1863/* return and as path value */
1864const char *
1865aspath_print (struct aspath *as)
1866{
paulfe69a502005-09-10 16:55:02 +00001867 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001868}
1869
1870/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001871/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1872 * AS_PATH wasn't empty.
1873 */
paul718e3742002-12-13 20:15:29 +00001874void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001875aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001876{
Paul Jakmab2518c12006-05-12 23:48:40 +00001877 assert (format);
1878 vty_out (vty, format, as->str);
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001879 if (strlen (as->str) && strlen (suffix))
1880 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001881}
1882
paul94f2b392005-06-28 12:44:16 +00001883static void
paul718e3742002-12-13 20:15:29 +00001884aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1885{
1886 struct aspath *as;
1887
1888 as = (struct aspath *) backet->data;
1889
paulefa9f832002-12-13 21:47:59 +00001890 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001891 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1892}
1893
1894/* Print all aspath and hash information. This function is used from
1895 `show ip bgp paths' command. */
1896void
1897aspath_print_all_vty (struct vty *vty)
1898{
1899 hash_iterate (ashash,
1900 (void (*) (struct hash_backet *, void *))
1901 aspath_show_all_iterator,
1902 vty);
1903}