blob: 9d49f343c6b9f072e9b976543e03b98f6e030164 [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"
David Lamparter6b0655a2014-06-04 06:53:35 +020037
paul718e3742002-12-13 20:15:29 +000038/* 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;
David Lamparter6b0655a2014-06-04 06:53:35 +020093
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +000094/* Callers are required to initialize the memory */
Paul Jakmaf63f06d2011-04-08 12:44:43 +010095static as_t *
paulfe69a502005-09-10 16:55:02 +000096assegment_data_new (int num)
97{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +000098 return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
paulfe69a502005-09-10 16:55:02 +000099}
100
Lou Berger056f3762013-04-10 12:30:04 -0700101static void
102assegment_data_free (as_t *asdata)
103{
104 XFREE (MTYPE_AS_SEG_DATA, asdata);
105}
106
paulfe69a502005-09-10 16:55:02 +0000107/* Get a new segment. Note that 0 is an allowed length,
108 * and will result in a segment with no allocated data segment.
109 * the caller should immediately assign data to the segment, as the segment
110 * otherwise is not generally valid
111 */
112static struct assegment *
113assegment_new (u_char type, u_short length)
114{
115 struct assegment *new;
116
117 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
118
119 if (length)
120 new->as = assegment_data_new (length);
121
122 new->length = length;
123 new->type = type;
124
125 return new;
126}
127
128static void
129assegment_free (struct assegment *seg)
130{
131 if (!seg)
132 return;
133
134 if (seg->as)
Lou Berger056f3762013-04-10 12:30:04 -0700135 assegment_data_free (seg->as);
paulfe69a502005-09-10 16:55:02 +0000136 memset (seg, 0xfe, sizeof(struct assegment));
137 XFREE (MTYPE_AS_SEG, seg);
138
139 return;
140}
141
142/* free entire chain of segments */
143static void
144assegment_free_all (struct assegment *seg)
145{
146 struct assegment *prev;
147
148 while (seg)
149 {
150 prev = seg;
151 seg = seg->next;
152 assegment_free (prev);
153 }
154}
155
156/* Duplicate just the given assegment and its data */
157static struct assegment *
158assegment_dup (struct assegment *seg)
159{
160 struct assegment *new;
161
162 new = assegment_new (seg->type, seg->length);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000163 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );
paulfe69a502005-09-10 16:55:02 +0000164
165 return new;
166}
167
168/* Duplicate entire chain of assegments, return the head */
169static struct assegment *
170assegment_dup_all (struct assegment *seg)
171{
172 struct assegment *new = NULL;
173 struct assegment *head = NULL;
174
175 while (seg)
176 {
177 if (head)
178 {
179 new->next = assegment_dup (seg);
180 new = new->next;
181 }
182 else
183 head = new = assegment_dup (seg);
184
185 seg = seg->next;
186 }
187 return head;
188}
189
190/* prepend the as number to given segment, given num of times */
191static struct assegment *
192assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
193{
194 as_t *newas;
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000195 int i;
paulfe69a502005-09-10 16:55:02 +0000196
197 if (!num)
198 return seg;
199
200 if (num >= AS_SEGMENT_MAX)
201 return seg; /* we don't do huge prepends */
202
Lou Berger056f3762013-04-10 12:30:04 -0700203 if ((newas = assegment_data_new (seg->length + num)) == NULL)
204 return seg;
205
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000206 for (i = 0; i < num; i++)
207 newas[i] = asnum;
208
209 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
Lou Berger056f3762013-04-10 12:30:04 -0700210 assegment_data_free (seg->as);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000211 seg->as = newas;
212 seg->length += num;
213
214 return seg;
paulfe69a502005-09-10 16:55:02 +0000215}
216
217/* append given array of as numbers to the segment */
218static struct assegment *
219assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
220{
paul02335422006-01-16 11:13:27 +0000221 as_t *newas;
222
223 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000224 ASSEGMENT_DATA_SIZE (seg->length + num, 1));
paulfe69a502005-09-10 16:55:02 +0000225
paul02335422006-01-16 11:13:27 +0000226 if (newas)
paulfe69a502005-09-10 16:55:02 +0000227 {
paul02335422006-01-16 11:13:27 +0000228 seg->as = newas;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000229 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));
paulfe69a502005-09-10 16:55:02 +0000230 seg->length += num;
231 return seg;
232 }
233
234 assegment_free_all (seg);
235 return NULL;
236}
237
238static int
239int_cmp (const void *p1, const void *p2)
240{
241 const as_t *as1 = p1;
242 const as_t *as2 = p2;
243
244 return (*as1 == *as2)
245 ? 0 : ( (*as1 > *as2) ? 1 : -1);
246}
247
248/* normalise the segment.
249 * In particular, merge runs of AS_SEQUENCEs into one segment
250 * Internally, we do not care about the wire segment length limit, and
251 * we want each distinct AS_PATHs to have the exact same internal
252 * representation - eg, so that our hashing actually works..
253 */
254static struct assegment *
255assegment_normalise (struct assegment *head)
256{
257 struct assegment *seg = head, *pin;
258 struct assegment *tmp;
259
260 if (!head)
261 return head;
262
263 while (seg)
264 {
265 pin = seg;
266
267 /* Sort values SET segments, for determinism in paths to aid
268 * creation of hash values / path comparisons
269 * and because it helps other lesser implementations ;)
270 */
271 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000272 {
273 int tail = 0;
274 int i;
275
276 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
277
278 /* weed out dupes */
279 for (i=1; i < seg->length; i++)
280 {
281 if (seg->as[tail] == seg->as[i])
282 continue;
283
284 tail++;
285 if (tail < i)
286 seg->as[tail] = seg->as[i];
287 }
288 /* seg->length can be 0.. */
289 if (seg->length)
290 seg->length = tail + 1;
291 }
paulfe69a502005-09-10 16:55:02 +0000292
293 /* read ahead from the current, pinned segment while the segments
294 * are packable/mergeable. Append all following packable segments
295 * to the segment we have pinned and remove these appended
296 * segments.
297 */
298 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
299 {
300 tmp = pin->next;
301 seg = pin->next;
302
303 /* append the next sequence to the pinned sequence */
304 pin = assegment_append_asns (pin, seg->as, seg->length);
305
306 /* bypass the next sequence */
307 pin->next = seg->next;
308
309 /* get rid of the now referenceless segment */
310 assegment_free (tmp);
311
312 }
313
314 seg = pin->next;
315 }
316 return head;
317}
David Lamparter6b0655a2014-06-04 06:53:35 +0200318
paul718e3742002-12-13 20:15:29 +0000319static struct aspath *
paulfe69a502005-09-10 16:55:02 +0000320aspath_new (void)
paul718e3742002-12-13 20:15:29 +0000321{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700322 return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000323}
324
325/* Free AS path structure. */
326void
327aspath_free (struct aspath *aspath)
328{
329 if (!aspath)
330 return;
paulfe69a502005-09-10 16:55:02 +0000331 if (aspath->segments)
332 assegment_free_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000333 if (aspath->str)
334 XFREE (MTYPE_AS_STR, aspath->str);
335 XFREE (MTYPE_AS_PATH, aspath);
336}
337
338/* Unintern aspath from AS path bucket. */
339void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000340aspath_unintern (struct aspath **aspath)
paul718e3742002-12-13 20:15:29 +0000341{
342 struct aspath *ret;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000343 struct aspath *asp = *aspath;
344
345 if (asp->refcnt)
346 asp->refcnt--;
paul718e3742002-12-13 20:15:29 +0000347
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000348 if (asp->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000349 {
350 /* This aspath must exist in aspath hash table. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000351 ret = hash_release (ashash, asp);
paul718e3742002-12-13 20:15:29 +0000352 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000353 aspath_free (asp);
354 *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000355 }
356}
357
358/* Return the start or end delimiters for a particular Segment type */
359#define AS_SEG_START 0
360#define AS_SEG_END 1
361static char
362aspath_delimiter_char (u_char type, u_char which)
363{
364 int i;
365 struct
366 {
367 int type;
368 char start;
369 char end;
370 } aspath_delim_char [] =
371 {
372 { AS_SET, '{', '}' },
paul718e3742002-12-13 20:15:29 +0000373 { AS_CONFED_SET, '[', ']' },
374 { AS_CONFED_SEQUENCE, '(', ')' },
375 { 0 }
376 };
377
378 for (i = 0; aspath_delim_char[i].type != 0; i++)
379 {
380 if (aspath_delim_char[i].type == type)
381 {
382 if (which == AS_SEG_START)
383 return aspath_delim_char[i].start;
384 else if (which == AS_SEG_END)
385 return aspath_delim_char[i].end;
386 }
387 }
388 return ' ';
389}
390
Denis Ovsienko014b6702009-06-23 21:10:45 +0400391/* countup asns from this segment and index onward */
392static int
393assegment_count_asns (struct assegment *seg, int from)
394{
395 int count = 0;
396 while (seg)
397 {
398 if (!from)
399 count += seg->length;
400 else
401 {
402 count += (seg->length - from);
403 from = 0;
404 }
405 seg = seg->next;
406 }
407 return count;
408}
409
paulfe69a502005-09-10 16:55:02 +0000410unsigned int
411aspath_count_confeds (struct aspath *aspath)
412{
413 int count = 0;
414 struct assegment *seg = aspath->segments;
415
416 while (seg)
417 {
418 if (seg->type == AS_CONFED_SEQUENCE)
419 count += seg->length;
420 else if (seg->type == AS_CONFED_SET)
421 count++;
422
423 seg = seg->next;
424 }
425 return count;
426}
427
428unsigned int
429aspath_count_hops (struct aspath *aspath)
430{
431 int count = 0;
432 struct assegment *seg = aspath->segments;
433
434 while (seg)
435 {
436 if (seg->type == AS_SEQUENCE)
437 count += seg->length;
438 else if (seg->type == AS_SET)
439 count++;
440
441 seg = seg->next;
442 }
443 return count;
444}
445
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000446/* Estimate size aspath /might/ take if encoded into an
447 * ASPATH attribute.
448 *
449 * This is a quick estimate, not definitive! aspath_put()
450 * may return a different number!!
451 */
paulfe69a502005-09-10 16:55:02 +0000452unsigned int
453aspath_size (struct aspath *aspath)
454{
455 int size = 0;
456 struct assegment *seg = aspath->segments;
457
458 while (seg)
459 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000460 size += ASSEGMENT_SIZE(seg->length, 1);
paulfe69a502005-09-10 16:55:02 +0000461 seg = seg->next;
462 }
463 return size;
464}
465
Paul Jakma2815e612006-09-14 02:56:07 +0000466/* Return highest public ASN in path */
467as_t
468aspath_highest (struct aspath *aspath)
469{
470 struct assegment *seg = aspath->segments;
471 as_t highest = 0;
472 unsigned int i;
473
474 while (seg)
475 {
476 for (i = 0; i < seg->length; i++)
477 if (seg->as[i] > highest
478 && (seg->as[i] < BGP_PRIVATE_AS_MIN
479 || seg->as[i] > BGP_PRIVATE_AS_MAX))
480 highest = seg->as[i];
481 seg = seg->next;
482 }
483 return highest;
484}
485
Timo Teräs85c854a2014-09-30 11:31:53 +0300486/* Return the left-most ASN in path */
487as_t
488aspath_leftmost (struct aspath *aspath)
489{
490 struct assegment *seg = aspath->segments;
491 as_t leftmost = 0;
492
493 if (seg && seg->length && seg->type == AS_SEQUENCE)
494 leftmost = seg->as[0];
495
496 return leftmost;
497}
498
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000499/* Return 1 if there are any 4-byte ASes in the path */
500unsigned int
501aspath_has_as4 (struct aspath *aspath)
502{
503 struct assegment *seg = aspath->segments;
504 unsigned int i;
505
506 while (seg)
507 {
508 for (i = 0; i < seg->length; i++)
509 if (seg->as[i] > BGP_AS_MAX)
510 return 1;
511 seg = seg->next;
512 }
513 return 0;
514}
515
paul718e3742002-12-13 20:15:29 +0000516/* Convert aspath structure to string expression. */
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000517static void
paul718e3742002-12-13 20:15:29 +0000518aspath_make_str_count (struct aspath *as)
519{
paulfe69a502005-09-10 16:55:02 +0000520 struct assegment *seg;
521 int str_size;
522 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000523 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000524
525 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000526 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000527 {
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000528 as->str = XMALLOC (MTYPE_AS_STR, 1);
529 as->str[0] = '\0';
530 as->str_len = 0;
531 return;
paul718e3742002-12-13 20:15:29 +0000532 }
paulfe69a502005-09-10 16:55:02 +0000533
534 seg = as->segments;
535
Denis Ovsienko014b6702009-06-23 21:10:45 +0400536 /* ASN takes 5 to 10 chars plus seperator, see below.
537 * If there is one differing segment type, we need an additional
538 * 2 chars for segment delimiters, and the final '\0'.
539 * Hopefully this is large enough to avoid hitting the realloc
540 * code below for most common sequences.
541 *
542 * This was changed to 10 after the well-known BGP assertion, which
543 * had hit some parts of the Internet in May of 2009.
544 */
545#define ASN_STR_LEN (10 + 1)
546 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
547 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000548 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000549
paulfe69a502005-09-10 16:55:02 +0000550 while (seg)
paul718e3742002-12-13 20:15:29 +0000551 {
552 int i;
paulfe69a502005-09-10 16:55:02 +0000553 char seperator;
paul718e3742002-12-13 20:15:29 +0000554
paulfe69a502005-09-10 16:55:02 +0000555 /* Check AS type validity. Set seperator for segment */
556 switch (seg->type)
557 {
558 case AS_SET:
559 case AS_CONFED_SET:
560 seperator = ',';
561 break;
562 case AS_SEQUENCE:
563 case AS_CONFED_SEQUENCE:
564 seperator = ' ';
565 break;
566 default:
567 XFREE (MTYPE_AS_STR, str_buf);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000568 as->str = NULL;
569 as->str_len = 0;
570 return;
paulfe69a502005-09-10 16:55:02 +0000571 }
572
Denis Ovsienko014b6702009-06-23 21:10:45 +0400573 /* We might need to increase str_buf, particularly if path has
574 * differing segments types, our initial guesstimate above will
575 * have been wrong. Need 10 chars for ASN, a seperator each and
576 * potentially two segment delimiters, plus a space between each
577 * segment and trailing zero.
578 *
579 * This definitely didn't work with the value of 5 bytes and
580 * 32-bit ASNs.
581 */
582#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
583 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
584 {
585 str_size = len + SEGMENT_STR_LEN(seg);
586 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
587 }
588#undef ASN_STR_LEN
589#undef SEGMENT_STR_LEN
590
paulfe69a502005-09-10 16:55:02 +0000591 if (seg->type != AS_SEQUENCE)
Denis Ovsienko014b6702009-06-23 21:10:45 +0400592 len += snprintf (str_buf + len, str_size - len,
593 "%c",
594 aspath_delimiter_char (seg->type, AS_SEG_START));
paulfe69a502005-09-10 16:55:02 +0000595
596 /* write out the ASNs, with their seperators, bar the last one*/
597 for (i = 0; i < seg->length; i++)
598 {
599 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
600
601 if (i < (seg->length - 1))
602 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
603 }
604
605 if (seg->type != AS_SEQUENCE)
606 len += snprintf (str_buf + len, str_size - len, "%c",
607 aspath_delimiter_char (seg->type, AS_SEG_END));
608 if (seg->next)
609 len += snprintf (str_buf + len, str_size - len, " ");
610
611 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000612 }
paulfe69a502005-09-10 16:55:02 +0000613
614 assert (len < str_size);
615
616 str_buf[len] = '\0';
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000617 as->str = str_buf;
618 as->str_len = len;
paul718e3742002-12-13 20:15:29 +0000619
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000620 return;
paul718e3742002-12-13 20:15:29 +0000621}
622
paulfe69a502005-09-10 16:55:02 +0000623static void
624aspath_str_update (struct aspath *as)
625{
626 if (as->str)
627 XFREE (MTYPE_AS_STR, as->str);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000628 aspath_make_str_count (as);
paulfe69a502005-09-10 16:55:02 +0000629}
630
paul718e3742002-12-13 20:15:29 +0000631/* Intern allocated AS path. */
632struct aspath *
633aspath_intern (struct aspath *aspath)
634{
635 struct aspath *find;
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000636
637 /* Assert this AS path structure is not interned and has the string
638 representation built. */
paul718e3742002-12-13 20:15:29 +0000639 assert (aspath->refcnt == 0);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000640 assert (aspath->str);
paul718e3742002-12-13 20:15:29 +0000641
642 /* Check AS path hash. */
643 find = hash_get (ashash, aspath, hash_alloc_intern);
paul718e3742002-12-13 20:15:29 +0000644 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000645 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000646
647 find->refcnt++;
648
paul718e3742002-12-13 20:15:29 +0000649 return find;
650}
651
652/* Duplicate aspath structure. Created same aspath structure but
653 reference count and AS path string is cleared. */
654struct aspath *
655aspath_dup (struct aspath *aspath)
656{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000657 unsigned short buflen = aspath->str_len + 1;
paul718e3742002-12-13 20:15:29 +0000658 struct aspath *new;
659
paulfe69a502005-09-10 16:55:02 +0000660 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000661
paulfe69a502005-09-10 16:55:02 +0000662 if (aspath->segments)
663 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000664
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000665 if (!aspath->str)
666 return new;
667
668 new->str = XMALLOC (MTYPE_AS_STR, buflen);
669 new->str_len = aspath->str_len;
670
671 /* copy the string data */
672 if (aspath->str_len > 0)
673 memcpy (new->str, aspath->str, buflen);
674 else
675 new->str[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000676
677 return new;
678}
679
paul94f2b392005-06-28 12:44:16 +0000680static void *
paulfe69a502005-09-10 16:55:02 +0000681aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000682{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000683 const struct aspath *aspath = arg;
684 struct aspath *new;
685
686 /* Malformed AS path value. */
687 assert (aspath->str);
688 if (! aspath->str)
689 return NULL;
paul718e3742002-12-13 20:15:29 +0000690
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000691 /* New aspath structure is needed. */
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000692 new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000693
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000694 /* Reuse segments and string representation */
695 new->refcnt = 0;
696 new->segments = aspath->segments;
697 new->str = aspath->str;
698 new->str_len = aspath->str_len;
699
700 return new;
paul718e3742002-12-13 20:15:29 +0000701}
702
Paul Jakmaab005292010-11-27 22:48:34 +0000703/* parse as-segment byte stream in struct assegment */
Paul Jakmab881c702010-11-23 16:35:42 +0000704static int
705assegments_parse (struct stream *s, size_t length,
706 struct assegment **result, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000707{
708 struct assegment_header segh;
709 struct assegment *seg, *prev = NULL, *head = NULL;
Paul Jakmaab005292010-11-27 22:48:34 +0000710 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000711
Paul Jakmaab005292010-11-27 22:48:34 +0000712 /* empty aspath (ie iBGP or somesuch) */
713 if (length == 0)
Paul Jakmab881c702010-11-23 16:35:42 +0000714 return 0;
paulfe69a502005-09-10 16:55:02 +0000715
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000716 if (BGP_DEBUG (as4, AS4_SEGMENT))
717 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
718 (unsigned long) length);
Paul Jakmaab005292010-11-27 22:48:34 +0000719 /* basic checks */
720 if ((STREAM_READABLE(s) < length)
721 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
722 || (length % AS16_VALUE_SIZE ))
Paul Jakmab881c702010-11-23 16:35:42 +0000723 return -1;
paulfe69a502005-09-10 16:55:02 +0000724
Paul Jakmaab005292010-11-27 22:48:34 +0000725 while (bytes < length)
paulfe69a502005-09-10 16:55:02 +0000726 {
727 int i;
Chris Hallcddb8112010-08-09 22:31:37 +0400728 size_t seg_size;
paulfe69a502005-09-10 16:55:02 +0000729
Paul Jakmaab005292010-11-27 22:48:34 +0000730 if ((length - bytes) <= AS_HEADER_SIZE)
Chris Hallcddb8112010-08-09 22:31:37 +0400731 {
Paul Jakmaab005292010-11-27 22:48:34 +0000732 if (head)
733 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000734 return -1;
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100735 }
736
Paul Jakmaab005292010-11-27 22:48:34 +0000737 /* softly softly, get the header first on its own */
paulfe69a502005-09-10 16:55:02 +0000738 segh.type = stream_getc (s);
739 segh.length = stream_getc (s);
740
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000741 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
742
743 if (BGP_DEBUG (as4, AS4_SEGMENT))
744 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
745 segh.type, segh.length);
746
Paul Jakmaab005292010-11-27 22:48:34 +0000747 /* check it.. */
748 if ( ((bytes + seg_size) > length)
749 /* 1771bis 4.3b: seg length contains one or more */
750 || (segh.length == 0)
751 /* Paranoia in case someone changes type of segment length.
752 * Shift both values by 0x10 to make the comparison operate
753 * on more, than 8 bits (otherwise it's a warning, bug #564).
Denis Ovsienko2eb445e2009-12-04 17:32:54 +0300754 */
Paul Jakmaab005292010-11-27 22:48:34 +0000755 || ((sizeof segh.length > 1)
756 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
paulfe69a502005-09-10 16:55:02 +0000757 {
Paul Jakmaab005292010-11-27 22:48:34 +0000758 if (head)
paulfe69a502005-09-10 16:55:02 +0000759 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000760 return -1;
paulfe69a502005-09-10 16:55:02 +0000761 }
762
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100763 switch (segh.type)
764 {
765 case AS_SEQUENCE:
766 case AS_SET:
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100767 case AS_CONFED_SEQUENCE:
768 case AS_CONFED_SET:
Paul Jakmaab005292010-11-27 22:48:34 +0000769 break;
770 default:
771 if (head)
772 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000773 return -1;
paulfe69a502005-09-10 16:55:02 +0000774 }
Chris Hallcddb8112010-08-09 22:31:37 +0400775
paulfe69a502005-09-10 16:55:02 +0000776 /* now its safe to trust lengths */
777 seg = assegment_new (segh.type, segh.length);
778
779 if (head)
780 prev->next = seg;
781 else /* it's the first segment */
782 head = prev = seg;
783
784 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000785 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
786
Paul Jakmaab005292010-11-27 22:48:34 +0000787 bytes += seg_size;
788
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000789 if (BGP_DEBUG (as4, AS4_SEGMENT))
Paul Jakmaab005292010-11-27 22:48:34 +0000790 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
791 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000792
793 prev = seg;
794 }
795
Paul Jakmab881c702010-11-23 16:35:42 +0000796 *result = assegment_normalise (head);
797 return 0;
paulfe69a502005-09-10 16:55:02 +0000798}
799
Paul Jakmaab005292010-11-27 22:48:34 +0000800/* AS path parse function. pnt is a pointer to byte stream and length
801 is length of byte stream. If there is same AS path in the the AS
Paul Jakmab881c702010-11-23 16:35:42 +0000802 path hash then return it else make new AS path structure.
803
804 On error NULL is returned.
Chris Hallcddb8112010-08-09 22:31:37 +0400805 */
paul718e3742002-12-13 20:15:29 +0000806struct aspath *
Paul Jakmaab005292010-11-27 22:48:34 +0000807aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000808{
809 struct aspath as;
810 struct aspath *find;
811
Paul Jakmaab005292010-11-27 22:48:34 +0000812 /* If length is odd it's malformed AS path. */
813 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
814 * otherwise its malformed when length is larger than 2 and (length-2)
815 * is not dividable by 4.
816 * But... this time we're lazy
817 */
818 if (length % AS16_VALUE_SIZE )
819 return NULL;
Chris Hallcddb8112010-08-09 22:31:37 +0400820
Paul Jakmaab005292010-11-27 22:48:34 +0000821 memset (&as, 0, sizeof (struct aspath));
Paul Jakmab881c702010-11-23 16:35:42 +0000822 if (assegments_parse (s, length, &as.segments, use32bit) < 0)
823 return NULL;
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000824
paul718e3742002-12-13 20:15:29 +0000825 /* If already same aspath exist then return it. */
826 find = hash_get (ashash, &as, aspath_hash_alloc);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000827
828 /* bug! should not happen, let the daemon crash below */
829 assert (find);
830
831 /* if the aspath was already hashed free temporary memory. */
832 if (find->refcnt)
833 {
834 assegment_free_all (as.segments);
835 /* aspath_key_make() always updates the string */
836 XFREE (MTYPE_AS_STR, as.str);
837 }
838
paul718e3742002-12-13 20:15:29 +0000839 find->refcnt++;
840
841 return find;
842}
843
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100844static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000845assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000846{
paulfe69a502005-09-10 16:55:02 +0000847 int i;
848 assert (num <= AS_SEGMENT_MAX);
849
850 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000851 if ( use32bit )
852 stream_putl (s, as[i]);
853 else
854 {
855 if ( as[i] <= BGP_AS_MAX )
856 stream_putw(s, as[i]);
857 else
858 stream_putw(s, BGP_AS_TRANS);
859 }
paul718e3742002-12-13 20:15:29 +0000860}
861
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100862static size_t
paulfe69a502005-09-10 16:55:02 +0000863assegment_header_put (struct stream *s, u_char type, int length)
864{
865 size_t lenp;
866 assert (length <= AS_SEGMENT_MAX);
867 stream_putc (s, type);
868 lenp = stream_get_endp (s);
869 stream_putc (s, length);
870 return lenp;
871}
872
873/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000874size_t
875aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000876{
877 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000878 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000879
880 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000881 return 0;
paulfe69a502005-09-10 16:55:02 +0000882
883 if (seg)
884 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000885 /*
886 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
887 * At the moment, we would write out a partial aspath, and our peer
888 * will complain and drop the session :-/
889 *
890 * The general assumption here is that many things tested will
891 * never happen. And, in real live, up to now, they have not.
892 */
893 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000894 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000895 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000896 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000897 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000898 size_t lenp;
899
900 /* Overlength segments have to be split up */
901 while ( (seg->length - written) > AS_SEGMENT_MAX)
902 {
903 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000904 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000905 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000906 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000907 }
908
909 /* write the final segment, probably is also the first */
910 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000911 assegment_data_put (s, (seg->as + written), seg->length - written,
912 use32bit);
paulfe69a502005-09-10 16:55:02 +0000913
914 /* Sequence-type segments can be 'packed' together
915 * Case of a segment which was overlength and split up
916 * will be missed here, but that doesn't matter.
917 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000918 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000919 {
920 /* NB: We should never normally get here given we
921 * normalise aspath data when parse them. However, better
922 * safe than sorry. We potentially could call
923 * assegment_normalise here instead, but it's cheaper and
924 * easier to do it on the fly here rather than go through
925 * the segment list twice every time we write out
926 * aspath's.
927 */
928
929 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000930 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000931
932 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000933 stream_putc_at (s, lenp, seg->length - written + next->length);
934 asns_packed += next->length;
935
936 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000937 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000938
939 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
940 use32bit);
941 seg = next;
paulfe69a502005-09-10 16:55:02 +0000942 }
943 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000944 return bytes;
paulfe69a502005-09-10 16:55:02 +0000945}
946
947/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
948 * We have no way to manage the storage, so we use a static stream
949 * wrapper around aspath_put.
950 */
951u_char *
952aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
953{
954#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000955
956 if (!snmp_stream)
957 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000958 else
paul8fdc32a2006-01-16 12:01:29 +0000959 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000960
961 if (!as)
962 {
963 *varlen = 0;
964 return NULL;
965 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000966 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000967
paul8fdc32a2006-01-16 12:01:29 +0000968 *varlen = stream_get_endp (snmp_stream);
969 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000970}
971
972#define min(A,B) ((A) < (B) ? (A) : (B))
973
paul94f2b392005-06-28 12:44:16 +0000974static struct assegment *
paul718e3742002-12-13 20:15:29 +0000975aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
976 as_t as)
977{
978 int i;
979
980 /* If this is first AS set member, create new as-set segment. */
981 if (asset == NULL)
982 {
paulfe69a502005-09-10 16:55:02 +0000983 asset = assegment_new (AS_SET, 1);
984 if (! aspath->segments)
985 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000986 else
paulfe69a502005-09-10 16:55:02 +0000987 {
988 struct assegment *seg = aspath->segments;
989 while (seg->next)
990 seg = seg->next;
991 seg->next = asset;
992 }
paul718e3742002-12-13 20:15:29 +0000993 asset->type = AS_SET;
994 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000995 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000996 }
997 else
998 {
paul718e3742002-12-13 20:15:29 +0000999 /* Check this AS value already exists or not. */
1000 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +00001001 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +00001002 return asset;
paulfe69a502005-09-10 16:55:02 +00001003
paul718e3742002-12-13 20:15:29 +00001004 asset->length++;
paulfe69a502005-09-10 16:55:02 +00001005 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
1006 asset->length * AS_VALUE_SIZE);
1007 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +00001008 }
paulfe69a502005-09-10 16:55:02 +00001009
paul718e3742002-12-13 20:15:29 +00001010
1011 return asset;
1012}
1013
1014/* Modify as1 using as2 for aggregation. */
1015struct aspath *
1016aspath_aggregate (struct aspath *as1, struct aspath *as2)
1017{
1018 int i;
1019 int minlen;
1020 int match;
paulfe69a502005-09-10 16:55:02 +00001021 int from;
1022 struct assegment *seg1 = as1->segments;
1023 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001024 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +00001025 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001026 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +00001027
1028 match = 0;
1029 minlen = 0;
1030 aspath = NULL;
1031 asset = NULL;
paul718e3742002-12-13 20:15:29 +00001032
1033 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +00001034 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001035 {
paul718e3742002-12-13 20:15:29 +00001036 /* Check segment type. */
1037 if (seg1->type != seg2->type)
1038 break;
1039
1040 /* Minimum segment length. */
1041 minlen = min (seg1->length, seg2->length);
1042
1043 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001044 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001045 break;
1046
1047 if (match)
1048 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001049 struct assegment *seg = assegment_new (seg1->type, 0);
1050
1051 seg = assegment_append_asns (seg, seg1->as, match);
1052
paul718e3742002-12-13 20:15:29 +00001053 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001054 {
1055 aspath = aspath_new ();
1056 aspath->segments = seg;
1057 }
1058 else
1059 prevseg->next = seg;
1060
1061 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001062 }
1063
1064 if (match != minlen || match != seg1->length
1065 || seg1->length != seg2->length)
1066 break;
paulfe69a502005-09-10 16:55:02 +00001067
1068 seg1 = seg1->next;
1069 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001070 }
1071
1072 if (! aspath)
1073 aspath = aspath_new();
1074
1075 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001076 from = match;
1077 while (seg1)
paul718e3742002-12-13 20:15:29 +00001078 {
paulfe69a502005-09-10 16:55:02 +00001079 for (i = from; i < seg1->length; i++)
1080 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1081
1082 from = 0;
1083 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001084 }
1085
paulfe69a502005-09-10 16:55:02 +00001086 from = match;
1087 while (seg2)
paul718e3742002-12-13 20:15:29 +00001088 {
paulfe69a502005-09-10 16:55:02 +00001089 for (i = from; i < seg2->length; i++)
1090 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001091
paulfe69a502005-09-10 16:55:02 +00001092 from = 0;
1093 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001094 }
paulfe69a502005-09-10 16:55:02 +00001095
1096 assegment_normalise (aspath->segments);
1097 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001098 return aspath;
1099}
1100
1101/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1102 attribute, check the leftmost AS number in the AS_PATH attribute is
1103 or not the peer's AS number. */
1104int
1105aspath_firstas_check (struct aspath *aspath, as_t asno)
1106{
paulfe69a502005-09-10 16:55:02 +00001107 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001108 return 0;
paulfe69a502005-09-10 16:55:02 +00001109
1110 if (aspath->segments
1111 && (aspath->segments->type == AS_SEQUENCE)
1112 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001113 return 1;
1114
1115 return 0;
1116}
1117
Paul Jakma1f742f22006-08-06 15:52:11 +00001118/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001119int
1120aspath_loop_check (struct aspath *aspath, as_t asno)
1121{
paulfe69a502005-09-10 16:55:02 +00001122 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001123 int count = 0;
1124
Paul Jakma1f742f22006-08-06 15:52:11 +00001125 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001126 return 0;
paulfe69a502005-09-10 16:55:02 +00001127
1128 seg = aspath->segments;
1129
1130 while (seg)
paul718e3742002-12-13 20:15:29 +00001131 {
1132 int i;
paul718e3742002-12-13 20:15:29 +00001133
paulfe69a502005-09-10 16:55:02 +00001134 for (i = 0; i < seg->length; i++)
1135 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001136 count++;
paulfe69a502005-09-10 16:55:02 +00001137
1138 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001139 }
1140 return count;
1141}
1142
1143/* When all of AS path is private AS return 1. */
1144int
1145aspath_private_as_check (struct aspath *aspath)
1146{
paulfe69a502005-09-10 16:55:02 +00001147 struct assegment *seg;
1148
1149 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001150 return 0;
paulfe69a502005-09-10 16:55:02 +00001151
1152 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001153
paulfe69a502005-09-10 16:55:02 +00001154 while (seg)
paul718e3742002-12-13 20:15:29 +00001155 {
1156 int i;
paul718e3742002-12-13 20:15:29 +00001157
paulfe69a502005-09-10 16:55:02 +00001158 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001159 {
paulfe69a502005-09-10 16:55:02 +00001160 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1161 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001162 return 0;
1163 }
paulfe69a502005-09-10 16:55:02 +00001164 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001165 }
1166 return 1;
1167}
1168
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001169/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1170int
1171aspath_confed_check (struct aspath *aspath)
1172{
1173 struct assegment *seg;
1174
1175 if ( !(aspath && aspath->segments) )
1176 return 0;
1177
1178 seg = aspath->segments;
1179
1180 while (seg)
1181 {
1182 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1183 return 1;
1184 seg = seg->next;
1185 }
1186 return 0;
1187}
1188
1189/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1190 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1191int
1192aspath_left_confed_check (struct aspath *aspath)
1193{
1194
1195 if ( !(aspath && aspath->segments) )
1196 return 0;
1197
1198 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1199 || (aspath->segments->type == AS_CONFED_SET) )
1200 return 1;
1201
1202 return 0;
1203}
1204
paul718e3742002-12-13 20:15:29 +00001205/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001206static struct aspath *
paul718e3742002-12-13 20:15:29 +00001207aspath_merge (struct aspath *as1, struct aspath *as2)
1208{
paulfe69a502005-09-10 16:55:02 +00001209 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001210
1211 if (! as1 || ! as2)
1212 return NULL;
1213
paulfe69a502005-09-10 16:55:02 +00001214 last = new = assegment_dup_all (as1->segments);
1215
1216 /* find the last valid segment */
1217 while (last && last->next)
1218 last = last->next;
1219
1220 last->next = as2->segments;
1221 as2->segments = new;
1222 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001223 return as2;
1224}
1225
1226/* Prepend as1 to as2. as2 should be uninterned aspath. */
1227struct aspath *
1228aspath_prepend (struct aspath *as1, struct aspath *as2)
1229{
paulfe69a502005-09-10 16:55:02 +00001230 struct assegment *seg1;
1231 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001232
1233 if (! as1 || ! as2)
1234 return NULL;
paulfe69a502005-09-10 16:55:02 +00001235
1236 seg1 = as1->segments;
1237 seg2 = as2->segments;
1238
1239 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001240 if (seg2 == NULL)
1241 {
paulfe69a502005-09-10 16:55:02 +00001242 as2->segments = assegment_dup_all (as1->segments);
1243 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001244 return as2;
1245 }
paulfe69a502005-09-10 16:55:02 +00001246
1247 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001248 if (seg1 == NULL)
1249 return as2;
paulfe69a502005-09-10 16:55:02 +00001250
1251 /* find the tail as1's segment chain. */
1252 while (seg1 && seg1->next)
1253 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001254
Vasilis Tsiligiannis736d4402009-07-20 01:59:10 +03001255 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1256 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1257 as2 = aspath_delete_confed_seq (as2);
1258
paul718e3742002-12-13 20:15:29 +00001259 /* Compare last segment type of as1 and first segment type of as2. */
1260 if (seg1->type != seg2->type)
1261 return aspath_merge (as1, as2);
1262
1263 if (seg1->type == AS_SEQUENCE)
1264 {
paulfe69a502005-09-10 16:55:02 +00001265 /* We have two chains of segments, as1->segments and seg2,
1266 * and we have to attach them together, merging the attaching
1267 * segments together into one.
1268 *
1269 * 1. dupe as1->segments onto head of as2
1270 * 2. merge seg2's asns onto last segment of this new chain
1271 * 3. attach chain after seg2
1272 */
paul718e3742002-12-13 20:15:29 +00001273
paulfe69a502005-09-10 16:55:02 +00001274 /* dupe as1 onto as2's head */
1275 seg1 = as2->segments = assegment_dup_all (as1->segments);
1276
1277 /* refind the tail of as2, reusing seg1 */
1278 while (seg1 && seg1->next)
1279 seg1 = seg1->next;
1280
1281 /* merge the old head, seg2, into tail, seg1 */
1282 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1283
1284 /* bypass the merged seg2, and attach any chain after it to
1285 * chain descending from as2's head
1286 */
1287 seg1->next = seg2->next;
1288
1289 /* seg2 is now referenceless and useless*/
1290 assegment_free (seg2);
1291
1292 /* we've now prepended as1's segment chain to as2, merging
1293 * the inbetween AS_SEQUENCE of seg2 in the process
1294 */
1295 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001296 return as2;
1297 }
1298 else
1299 {
1300 /* AS_SET merge code is needed at here. */
1301 return aspath_merge (as1, as2);
1302 }
paulfe69a502005-09-10 16:55:02 +00001303 /* XXX: Ermmm, what if as1 has multiple segments?? */
1304
paul718e3742002-12-13 20:15:29 +00001305 /* Not reached */
1306}
1307
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001308/* Iterate over AS_PATH segments and wipe all occurences of the
1309 * listed AS numbers. Hence some segments may lose some or even
1310 * all data on the way, the operation is implemented as a smarter
1311 * version of aspath_dup(), which allocates memory to hold the new
1312 * data, not the original. The new AS path is returned.
1313 */
1314struct aspath *
1315aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1316{
1317 struct assegment * srcseg, * exclseg, * lastseg;
1318 struct aspath * newpath;
1319
1320 newpath = aspath_new();
1321 lastseg = NULL;
1322
1323 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1324 {
1325 unsigned i, y, newlen = 0, done = 0, skip_as;
1326 struct assegment * newseg;
1327
1328 /* Find out, how much ASns are we going to pick from this segment.
1329 * We can't perform filtering right inline, because the size of
1330 * the new segment isn't known at the moment yet.
1331 */
1332 for (i = 0; i < srcseg->length; i++)
1333 {
1334 skip_as = 0;
1335 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1336 for (y = 0; y < exclseg->length; y++)
1337 if (srcseg->as[i] == exclseg->as[y])
1338 {
1339 skip_as = 1;
1340 // There's no sense in testing the rest of exclusion list, bail out.
1341 break;
1342 }
1343 if (!skip_as)
1344 newlen++;
1345 }
1346 /* newlen is now the number of ASns to copy */
1347 if (!newlen)
1348 continue;
1349
1350 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1351 newseg = assegment_new (srcseg->type, newlen);
1352 for (i = 0; i < srcseg->length; i++)
1353 {
1354 skip_as = 0;
1355 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1356 for (y = 0; y < exclseg->length; y++)
1357 if (srcseg->as[i] == exclseg->as[y])
1358 {
1359 skip_as = 1;
1360 break;
1361 }
1362 if (skip_as)
1363 continue;
1364 newseg->as[done++] = srcseg->as[i];
1365 }
1366 /* At his point newlen must be equal to done, and both must be positive. Append
1367 * the filtered segment to the gross result. */
1368 if (!lastseg)
1369 newpath->segments = newseg;
1370 else
1371 lastseg->next = newseg;
1372 lastseg = newseg;
1373 }
1374 aspath_str_update (newpath);
1375 /* We are happy returning even an empty AS_PATH, because the administrator
1376 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1377 * by having a match rule against certain AS_PATH regexps in the route-map index.
1378 */
1379 aspath_free (source);
1380 return newpath;
1381}
1382
paul718e3742002-12-13 20:15:29 +00001383/* Add specified AS to the leftmost of aspath. */
1384static struct aspath *
Timo Teräs85c854a2014-09-30 11:31:53 +03001385aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num)
paul718e3742002-12-13 20:15:29 +00001386{
paulfe69a502005-09-10 16:55:02 +00001387 struct assegment *assegment = aspath->segments;
David Lamparter21401f32015-03-03 08:55:26 +01001388 unsigned i;
paul718e3742002-12-13 20:15:29 +00001389
Timo Teräs85c854a2014-09-30 11:31:53 +03001390 if (assegment && assegment->type == type)
paul718e3742002-12-13 20:15:29 +00001391 {
Timo Teräs85c854a2014-09-30 11:31:53 +03001392 /* extend existing segment */
1393 aspath->segments = assegment_prepend_asns (aspath->segments, asno, num);
paul718e3742002-12-13 20:15:29 +00001394 }
paulfe69a502005-09-10 16:55:02 +00001395 else
paul718e3742002-12-13 20:15:29 +00001396 {
Timo Teräs85c854a2014-09-30 11:31:53 +03001397 /* prepend with new segment */
1398 struct assegment *newsegment = assegment_new (type, num);
1399 for (i = 0; i < num; i++)
1400 newsegment->as[i] = asno;
1401
1402 /* insert potentially replacing empty segment */
1403 if (assegment && assegment->length == 0)
1404 {
1405 newsegment->next = assegment->next;
1406 assegment_free (assegment);
1407 }
1408 else
1409 newsegment->next = assegment;
paulfe69a502005-09-10 16:55:02 +00001410 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001411 }
1412
Timo Teräs85c854a2014-09-30 11:31:53 +03001413 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001414 return aspath;
1415}
1416
Timo Teräs85c854a2014-09-30 11:31:53 +03001417/* Add specified AS to the leftmost of aspath num times. */
1418struct aspath *
1419aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num)
1420{
1421 return aspath_add_asns (aspath, asno, AS_SEQUENCE, num);
1422}
1423
paul718e3742002-12-13 20:15:29 +00001424/* Add specified AS to the leftmost of aspath. */
1425struct aspath *
1426aspath_add_seq (struct aspath *aspath, as_t asno)
1427{
Timo Teräs85c854a2014-09-30 11:31:53 +03001428 return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1);
paul718e3742002-12-13 20:15:29 +00001429}
1430
1431/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1432 as2's leftmost AS is same return 1. */
1433int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001434aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001435{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001436 const struct assegment *seg1;
1437 const struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001438
paulfe69a502005-09-10 16:55:02 +00001439 if (!(aspath1 && aspath2))
1440 return 0;
paul718e3742002-12-13 20:15:29 +00001441
paulfe69a502005-09-10 16:55:02 +00001442 seg1 = aspath1->segments;
1443 seg2 = aspath2->segments;
1444
1445 /* find first non-confed segments for each */
1446 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1447 || (seg1->type == AS_CONFED_SET)))
1448 seg1 = seg1->next;
1449
1450 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1451 || (seg2->type == AS_CONFED_SET)))
1452 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001453
1454 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001455 if (!(seg1 && seg2
1456 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001457 return 0;
paulfe69a502005-09-10 16:55:02 +00001458
1459 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001460 return 1;
1461
1462 return 0;
1463}
1464
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001465/* Truncate an aspath after a number of hops, and put the hops remaining
1466 * at the front of another aspath. Needed for AS4 compat.
1467 *
1468 * Returned aspath is a /new/ aspath, which should either by free'd or
1469 * interned by the caller, as desired.
1470 */
1471struct aspath *
1472aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1473{
1474 struct assegment *seg, *newseg, *prevseg = NULL;
1475 struct aspath *newpath = NULL, *mergedpath;
1476 int hops, cpasns = 0;
1477
1478 if (!aspath)
1479 return NULL;
1480
1481 seg = aspath->segments;
1482
1483 /* CONFEDs should get reconciled too.. */
1484 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1485 - aspath_count_hops (as4path);
1486
1487 if (hops < 0)
1488 {
1489 if (BGP_DEBUG (as4, AS4))
1490 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1491 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1492 * which is daft behaviour - it contains vital loop-detection
1493 * information which must have been removed from AS_PATH.
1494 */
1495 hops = aspath_count_hops (aspath);
1496 }
1497
1498 if (!hops)
1499 return aspath_dup (as4path);
1500
1501 if ( BGP_DEBUG(as4, AS4))
1502 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1503 aspath->str, as4path->str);
1504
1505 while (seg && hops > 0)
1506 {
1507 switch (seg->type)
1508 {
1509 case AS_SET:
1510 case AS_CONFED_SET:
1511 hops--;
1512 cpasns = seg->length;
1513 break;
1514 case AS_CONFED_SEQUENCE:
1515 /* Should never split a confed-sequence, if hop-count
1516 * suggests we must then something's gone wrong somewhere.
1517 *
1518 * Most important goal is to preserve AS_PATHs prime function
1519 * as loop-detector, so we fudge the numbers so that the entire
1520 * confed-sequence is merged in.
1521 */
1522 if (hops < seg->length)
1523 {
1524 if (BGP_DEBUG (as4, AS4))
1525 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1526 " across 2/4 ASN boundary somewhere, broken..");
1527 hops = seg->length;
1528 }
1529 case AS_SEQUENCE:
1530 cpasns = MIN(seg->length, hops);
1531 hops -= seg->length;
1532 }
1533
1534 assert (cpasns <= seg->length);
1535
1536 newseg = assegment_new (seg->type, 0);
1537 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1538
1539 if (!newpath)
1540 {
1541 newpath = aspath_new ();
1542 newpath->segments = newseg;
1543 }
1544 else
1545 prevseg->next = newseg;
1546
1547 prevseg = newseg;
1548 seg = seg->next;
1549 }
1550
1551 /* We may be able to join some segments here, and we must
1552 * do this because... we want normalised aspaths in out hash
1553 * and we do not want to stumble in aspath_put.
1554 */
1555 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1556 aspath_free (newpath);
1557 mergedpath->segments = assegment_normalise (mergedpath->segments);
1558 aspath_str_update (mergedpath);
1559
1560 if ( BGP_DEBUG(as4, AS4))
1561 zlog_debug ("[AS4] result of synthesizing is %s",
1562 mergedpath->str);
1563
1564 return mergedpath;
1565}
1566
paul718e3742002-12-13 20:15:29 +00001567/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1568 as2's leftmost AS is same return 1. (confederation as-path
1569 only). */
1570int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001571aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001572{
paulfe69a502005-09-10 16:55:02 +00001573 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001574 return 0;
paulfe69a502005-09-10 16:55:02 +00001575
paulad727402005-11-23 02:47:02 +00001576 if ( !(aspath1->segments && aspath2->segments) )
1577 return 0;
1578
paulfe69a502005-09-10 16:55:02 +00001579 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1580 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001581 return 0;
paulfe69a502005-09-10 16:55:02 +00001582
1583 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001584 return 1;
1585
1586 return 0;
1587}
1588
paulfe69a502005-09-10 16:55:02 +00001589/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1590 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001591struct aspath *
1592aspath_delete_confed_seq (struct aspath *aspath)
1593{
paulfe69a502005-09-10 16:55:02 +00001594 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001595
paulfe69a502005-09-10 16:55:02 +00001596 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001597 return aspath;
1598
paulfe69a502005-09-10 16:55:02 +00001599 seg = aspath->segments;
1600
1601 /* "if the first path segment of the AS_PATH is
1602 * of type AS_CONFED_SEQUENCE,"
1603 */
1604 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1605 return aspath;
paul718e3742002-12-13 20:15:29 +00001606
paulfe69a502005-09-10 16:55:02 +00001607 /* "... that segment and any immediately following segments
1608 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1609 * from the AS_PATH attribute,"
1610 */
1611 while (seg &&
1612 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001613 {
paulfe69a502005-09-10 16:55:02 +00001614 aspath->segments = seg->next;
1615 assegment_free (seg);
1616 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001617 }
paulfe69a502005-09-10 16:55:02 +00001618 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001619 return aspath;
1620}
1621
1622/* Add new AS number to the leftmost part of the aspath as
1623 AS_CONFED_SEQUENCE. */
1624struct aspath*
1625aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1626{
Timo Teräs85c854a2014-09-30 11:31:53 +03001627 return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1);
paul718e3742002-12-13 20:15:29 +00001628}
1629
1630/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001631static void
paul718e3742002-12-13 20:15:29 +00001632aspath_as_add (struct aspath *as, as_t asno)
1633{
paulfe69a502005-09-10 16:55:02 +00001634 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001635
paulfe69a502005-09-10 16:55:02 +00001636 if (!seg)
1637 return;
1638
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001639 /* Last segment search procedure. */
1640 while (seg->next)
1641 seg = seg->next;
1642
paulfe69a502005-09-10 16:55:02 +00001643 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001644}
1645
1646/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001647static void
paul718e3742002-12-13 20:15:29 +00001648aspath_segment_add (struct aspath *as, int type)
1649{
paulfe69a502005-09-10 16:55:02 +00001650 struct assegment *seg = as->segments;
1651 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001652
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001653 if (seg)
1654 {
1655 while (seg->next)
1656 seg = seg->next;
1657 seg->next = new;
1658 }
paul718e3742002-12-13 20:15:29 +00001659 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001660 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001661}
1662
1663struct aspath *
paul94f2b392005-06-28 12:44:16 +00001664aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001665{
Paul Jakmaab005292010-11-27 22:48:34 +00001666 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001667}
1668
1669struct aspath *
paul94f2b392005-06-28 12:44:16 +00001670aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001671{
1672 struct aspath *aspath;
1673
1674 aspath = aspath_new ();
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001675 aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +00001676 return aspath;
1677}
1678
1679unsigned long
paulfe69a502005-09-10 16:55:02 +00001680aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001681{
1682 return ashash->count;
1683}
David Lamparter6b0655a2014-06-04 06:53:35 +02001684
paul718e3742002-12-13 20:15:29 +00001685/*
1686 Theoretically, one as path can have:
1687
1688 One BGP packet size should be less than 4096.
1689 One BGP attribute size should be less than 4096 - BGP header size.
1690 One BGP aspath size should be less than 4096 - BGP header size -
1691 BGP mandantry attribute size.
1692*/
1693
1694/* AS path string lexical token enum. */
1695enum as_token
1696{
1697 as_token_asval,
1698 as_token_set_start,
1699 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001700 as_token_confed_seq_start,
1701 as_token_confed_seq_end,
1702 as_token_confed_set_start,
1703 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001704 as_token_unknown
1705};
1706
1707/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001708static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001709aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001710{
paulfd79ac92004-10-13 05:06:08 +00001711 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001712
paulfe69a502005-09-10 16:55:02 +00001713 /* Skip seperators (space for sequences, ',' for sets). */
1714 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001715 p++;
1716
1717 /* Check the end of the string and type specify characters
1718 (e.g. {}()). */
1719 switch (*p)
1720 {
1721 case '\0':
1722 return NULL;
paul718e3742002-12-13 20:15:29 +00001723 case '{':
1724 *token = as_token_set_start;
1725 p++;
1726 return p;
paul718e3742002-12-13 20:15:29 +00001727 case '}':
1728 *token = as_token_set_end;
1729 p++;
1730 return p;
paul718e3742002-12-13 20:15:29 +00001731 case '(':
paulfe69a502005-09-10 16:55:02 +00001732 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001733 p++;
1734 return p;
paul718e3742002-12-13 20:15:29 +00001735 case ')':
paulfe69a502005-09-10 16:55:02 +00001736 *token = as_token_confed_seq_end;
1737 p++;
1738 return p;
paulfe69a502005-09-10 16:55:02 +00001739 case '[':
1740 *token = as_token_confed_set_start;
1741 p++;
1742 return p;
paulfe69a502005-09-10 16:55:02 +00001743 case ']':
1744 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001745 p++;
1746 return p;
paul718e3742002-12-13 20:15:29 +00001747 }
1748
1749 /* Check actual AS value. */
1750 if (isdigit ((int) *p))
1751 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001752 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001753
paul718e3742002-12-13 20:15:29 +00001754 *token = as_token_asval;
1755 asval = (*p - '0');
1756 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001757
paul718e3742002-12-13 20:15:29 +00001758 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001759 {
1760 asval *= 10;
1761 asval += (*p - '0');
1762 p++;
1763 }
paul718e3742002-12-13 20:15:29 +00001764 *asno = asval;
1765 return p;
1766 }
1767
1768 /* There is no match then return unknown token. */
1769 *token = as_token_unknown;
1770 return p++;
1771}
1772
1773struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001774aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001775{
paul3fff6ff2006-02-05 17:55:35 +00001776 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001777 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001778 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001779 struct aspath *aspath;
1780 int needtype;
1781
1782 aspath = aspath_new ();
1783
1784 /* We start default type as AS_SEQUENCE. */
1785 as_type = AS_SEQUENCE;
1786 needtype = 1;
1787
1788 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1789 {
1790 switch (token)
1791 {
1792 case as_token_asval:
1793 if (needtype)
1794 {
1795 aspath_segment_add (aspath, as_type);
1796 needtype = 0;
1797 }
1798 aspath_as_add (aspath, asno);
1799 break;
1800 case as_token_set_start:
1801 as_type = AS_SET;
1802 aspath_segment_add (aspath, as_type);
1803 needtype = 0;
1804 break;
1805 case as_token_set_end:
1806 as_type = AS_SEQUENCE;
1807 needtype = 1;
1808 break;
paulfe69a502005-09-10 16:55:02 +00001809 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001810 as_type = AS_CONFED_SEQUENCE;
1811 aspath_segment_add (aspath, as_type);
1812 needtype = 0;
1813 break;
paulfe69a502005-09-10 16:55:02 +00001814 case as_token_confed_seq_end:
1815 as_type = AS_SEQUENCE;
1816 needtype = 1;
1817 break;
1818 case as_token_confed_set_start:
1819 as_type = AS_CONFED_SET;
1820 aspath_segment_add (aspath, as_type);
1821 needtype = 0;
1822 break;
1823 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001824 as_type = AS_SEQUENCE;
1825 needtype = 1;
1826 break;
1827 case as_token_unknown:
1828 default:
paulfe69a502005-09-10 16:55:02 +00001829 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001830 return NULL;
paul718e3742002-12-13 20:15:29 +00001831 }
1832 }
1833
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001834 aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +00001835
1836 return aspath;
1837}
David Lamparter6b0655a2014-06-04 06:53:35 +02001838
paul718e3742002-12-13 20:15:29 +00001839/* Make hash value by raw aspath data. */
1840unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001841aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001842{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001843 struct aspath *aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001844 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001845
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001846 if (!aspath->str)
1847 aspath_str_update (aspath);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001848
1849 key = jhash (aspath->str, aspath->str_len, 2334325);
paul718e3742002-12-13 20:15:29 +00001850
1851 return key;
1852}
1853
1854/* If two aspath have same value then return 1 else return 0 */
Josh Bailey96450fa2011-07-20 20:45:12 -07001855int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001856aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001857{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001858 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1859 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001860
1861 while (seg1 || seg2)
1862 {
1863 int i;
1864 if ((!seg1 && seg2) || (seg1 && !seg2))
1865 return 0;
1866 if (seg1->type != seg2->type)
1867 return 0;
1868 if (seg1->length != seg2->length)
1869 return 0;
1870 for (i = 0; i < seg1->length; i++)
1871 if (seg1->as[i] != seg2->as[i])
1872 return 0;
1873 seg1 = seg1->next;
1874 seg2 = seg2->next;
1875 }
1876 return 1;
paul718e3742002-12-13 20:15:29 +00001877}
1878
1879/* AS path hash initialize. */
1880void
paul94f2b392005-06-28 12:44:16 +00001881aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001882{
Stephen Hemminger90645f52013-01-04 22:29:21 +00001883 ashash = hash_create_size (32768, aspath_key_make, aspath_cmp);
paul718e3742002-12-13 20:15:29 +00001884}
paul8fdc32a2006-01-16 12:01:29 +00001885
1886void
1887aspath_finish (void)
1888{
Lou Berger056f3762013-04-10 12:30:04 -07001889 hash_clean (ashash, (void (*)(void *))aspath_free);
paul8fdc32a2006-01-16 12:01:29 +00001890 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00001891 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00001892
1893 if (snmp_stream)
1894 stream_free (snmp_stream);
1895}
David Lamparter6b0655a2014-06-04 06:53:35 +02001896
paul718e3742002-12-13 20:15:29 +00001897/* return and as path value */
1898const char *
1899aspath_print (struct aspath *as)
1900{
paulfe69a502005-09-10 16:55:02 +00001901 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001902}
1903
1904/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001905/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1906 * AS_PATH wasn't empty.
1907 */
paul718e3742002-12-13 20:15:29 +00001908void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001909aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001910{
Paul Jakmab2518c12006-05-12 23:48:40 +00001911 assert (format);
1912 vty_out (vty, format, as->str);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001913 if (as->str_len && strlen (suffix))
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001914 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001915}
1916
paul94f2b392005-06-28 12:44:16 +00001917static void
paul718e3742002-12-13 20:15:29 +00001918aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1919{
1920 struct aspath *as;
1921
1922 as = (struct aspath *) backet->data;
1923
David Lampartereed3c482015-03-03 08:51:53 +01001924 vty_out (vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001925 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1926}
1927
1928/* Print all aspath and hash information. This function is used from
1929 `show ip bgp paths' command. */
1930void
1931aspath_print_all_vty (struct vty *vty)
1932{
1933 hash_iterate (ashash,
1934 (void (*) (struct hash_backet *, void *))
1935 aspath_show_all_iterator,
1936 vty);
1937}