blob: 49b65b628c67ed5d683eb46ff1ba705e34a9aea8 [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"
Donald Sharp04907292016-01-07 10:03:01 -050032#include "filter.h"
paul718e3742002-12-13 20:15:29 +000033
34#include "bgpd/bgpd.h"
35#include "bgpd/bgp_aspath.h"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000036#include "bgpd/bgp_debug.h"
37#include "bgpd/bgp_attr.h"
David Lamparter6b0655a2014-06-04 06:53:35 +020038
paul718e3742002-12-13 20:15:29 +000039/* Attr. Flags and Attr. Type Code. */
40#define AS_HEADER_SIZE 2
41
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000042/* Now FOUR octets are used for AS value. */
paul718e3742002-12-13 20:15:29 +000043#define AS_VALUE_SIZE sizeof (as_t)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000044/* This is the old one */
45#define AS16_VALUE_SIZE sizeof (as16_t)
paul718e3742002-12-13 20:15:29 +000046
paulfe69a502005-09-10 16:55:02 +000047/* Maximum protocol segment length value */
48#define AS_SEGMENT_MAX 255
paul718e3742002-12-13 20:15:29 +000049
paulfe69a502005-09-10 16:55:02 +000050/* The following length and size macros relate specifically to Quagga's
51 * internal representation of AS-Segments, not per se to the on-wire
52 * sizes and lengths. At present (200508) they sort of match, however
53 * the ONLY functions which should now about the on-wire syntax are
54 * aspath_put, assegment_put and assegment_parse.
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000055 *
56 * aspath_put returns bytes written, the only definitive record of
57 * size of wire-format attribute..
paulfe69a502005-09-10 16:55:02 +000058 */
59
60/* Calculated size in bytes of ASN segment data to hold N ASN's */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000061#define ASSEGMENT_DATA_SIZE(N,S) \
62 ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )
paulfe69a502005-09-10 16:55:02 +000063
64/* Calculated size of segment struct to hold N ASN's */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000065#define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
paulfe69a502005-09-10 16:55:02 +000066
67/* AS segment octet length. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000068#define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
paulfe69a502005-09-10 16:55:02 +000069
70/* AS_SEQUENCE segments can be packed together */
71/* Can the types of X and Y be considered for packing? */
72#define ASSEGMENT_TYPES_PACKABLE(X,Y) \
73 ( ((X)->type == (Y)->type) \
74 && ((X)->type == AS_SEQUENCE))
75/* Types and length of X,Y suitable for packing? */
76#define ASSEGMENTS_PACKABLE(X,Y) \
77 ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \
78 && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) )
79
80/* As segment header - the on-wire representation
81 * NOT the internal representation!
82 */
83struct assegment_header
paul718e3742002-12-13 20:15:29 +000084{
85 u_char type;
86 u_char length;
paul718e3742002-12-13 20:15:29 +000087};
88
89/* Hash for aspath. This is the top level structure of AS path. */
Stephen Hemmingerda88ea82009-12-17 13:14:28 +030090static struct hash *ashash;
paul8fdc32a2006-01-16 12:01:29 +000091
92/* Stream for SNMP. See aspath_snmp_pathseg */
93static struct stream *snmp_stream;
David Lamparter6b0655a2014-06-04 06:53:35 +020094
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +000095/* Callers are required to initialize the memory */
Paul Jakmaf63f06d2011-04-08 12:44:43 +010096static as_t *
paulfe69a502005-09-10 16:55:02 +000097assegment_data_new (int num)
98{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +000099 return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
paulfe69a502005-09-10 16:55:02 +0000100}
101
Lou Berger056f3762013-04-10 12:30:04 -0700102static void
103assegment_data_free (as_t *asdata)
104{
105 XFREE (MTYPE_AS_SEG_DATA, asdata);
106}
107
paulfe69a502005-09-10 16:55:02 +0000108/* Get a new segment. Note that 0 is an allowed length,
109 * and will result in a segment with no allocated data segment.
110 * the caller should immediately assign data to the segment, as the segment
111 * otherwise is not generally valid
112 */
113static struct assegment *
114assegment_new (u_char type, u_short length)
115{
116 struct assegment *new;
117
118 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
119
120 if (length)
121 new->as = assegment_data_new (length);
122
123 new->length = length;
124 new->type = type;
125
126 return new;
127}
128
129static void
130assegment_free (struct assegment *seg)
131{
132 if (!seg)
133 return;
134
135 if (seg->as)
Lou Berger056f3762013-04-10 12:30:04 -0700136 assegment_data_free (seg->as);
paulfe69a502005-09-10 16:55:02 +0000137 memset (seg, 0xfe, sizeof(struct assegment));
138 XFREE (MTYPE_AS_SEG, seg);
139
140 return;
141}
142
143/* free entire chain of segments */
144static void
145assegment_free_all (struct assegment *seg)
146{
147 struct assegment *prev;
148
149 while (seg)
150 {
151 prev = seg;
152 seg = seg->next;
153 assegment_free (prev);
154 }
155}
156
157/* Duplicate just the given assegment and its data */
158static struct assegment *
159assegment_dup (struct assegment *seg)
160{
161 struct assegment *new;
162
163 new = assegment_new (seg->type, seg->length);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000164 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );
paulfe69a502005-09-10 16:55:02 +0000165
166 return new;
167}
168
169/* Duplicate entire chain of assegments, return the head */
170static struct assegment *
171assegment_dup_all (struct assegment *seg)
172{
173 struct assegment *new = NULL;
174 struct assegment *head = NULL;
175
176 while (seg)
177 {
178 if (head)
179 {
180 new->next = assegment_dup (seg);
181 new = new->next;
182 }
183 else
184 head = new = assegment_dup (seg);
185
186 seg = seg->next;
187 }
188 return head;
189}
190
191/* prepend the as number to given segment, given num of times */
192static struct assegment *
193assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
194{
195 as_t *newas;
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000196 int i;
paulfe69a502005-09-10 16:55:02 +0000197
198 if (!num)
199 return seg;
200
201 if (num >= AS_SEGMENT_MAX)
202 return seg; /* we don't do huge prepends */
203
Lou Berger056f3762013-04-10 12:30:04 -0700204 if ((newas = assegment_data_new (seg->length + num)) == NULL)
205 return seg;
206
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000207 for (i = 0; i < num; i++)
208 newas[i] = asnum;
209
210 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
Lou Berger056f3762013-04-10 12:30:04 -0700211 assegment_data_free (seg->as);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000212 seg->as = newas;
213 seg->length += num;
214
215 return seg;
paulfe69a502005-09-10 16:55:02 +0000216}
217
218/* append given array of as numbers to the segment */
219static struct assegment *
220assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
221{
paul02335422006-01-16 11:13:27 +0000222 as_t *newas;
223
224 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000225 ASSEGMENT_DATA_SIZE (seg->length + num, 1));
paulfe69a502005-09-10 16:55:02 +0000226
paul02335422006-01-16 11:13:27 +0000227 if (newas)
paulfe69a502005-09-10 16:55:02 +0000228 {
paul02335422006-01-16 11:13:27 +0000229 seg->as = newas;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000230 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));
paulfe69a502005-09-10 16:55:02 +0000231 seg->length += num;
232 return seg;
233 }
234
235 assegment_free_all (seg);
236 return NULL;
237}
238
239static int
240int_cmp (const void *p1, const void *p2)
241{
242 const as_t *as1 = p1;
243 const as_t *as2 = p2;
244
245 return (*as1 == *as2)
246 ? 0 : ( (*as1 > *as2) ? 1 : -1);
247}
248
249/* normalise the segment.
250 * In particular, merge runs of AS_SEQUENCEs into one segment
251 * Internally, we do not care about the wire segment length limit, and
252 * we want each distinct AS_PATHs to have the exact same internal
253 * representation - eg, so that our hashing actually works..
254 */
255static struct assegment *
256assegment_normalise (struct assegment *head)
257{
258 struct assegment *seg = head, *pin;
259 struct assegment *tmp;
260
261 if (!head)
262 return head;
263
264 while (seg)
265 {
266 pin = seg;
267
268 /* Sort values SET segments, for determinism in paths to aid
269 * creation of hash values / path comparisons
270 * and because it helps other lesser implementations ;)
271 */
272 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000273 {
274 int tail = 0;
275 int i;
276
277 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
278
279 /* weed out dupes */
280 for (i=1; i < seg->length; i++)
281 {
282 if (seg->as[tail] == seg->as[i])
283 continue;
284
285 tail++;
286 if (tail < i)
287 seg->as[tail] = seg->as[i];
288 }
289 /* seg->length can be 0.. */
290 if (seg->length)
291 seg->length = tail + 1;
292 }
paulfe69a502005-09-10 16:55:02 +0000293
294 /* read ahead from the current, pinned segment while the segments
295 * are packable/mergeable. Append all following packable segments
296 * to the segment we have pinned and remove these appended
297 * segments.
298 */
299 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
300 {
301 tmp = pin->next;
302 seg = pin->next;
303
304 /* append the next sequence to the pinned sequence */
305 pin = assegment_append_asns (pin, seg->as, seg->length);
306
307 /* bypass the next sequence */
308 pin->next = seg->next;
309
310 /* get rid of the now referenceless segment */
311 assegment_free (tmp);
312
313 }
314
315 seg = pin->next;
316 }
317 return head;
318}
David Lamparter6b0655a2014-06-04 06:53:35 +0200319
paul718e3742002-12-13 20:15:29 +0000320static struct aspath *
paulfe69a502005-09-10 16:55:02 +0000321aspath_new (void)
paul718e3742002-12-13 20:15:29 +0000322{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700323 return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000324}
325
326/* Free AS path structure. */
327void
328aspath_free (struct aspath *aspath)
329{
330 if (!aspath)
331 return;
paulfe69a502005-09-10 16:55:02 +0000332 if (aspath->segments)
333 assegment_free_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000334 if (aspath->str)
335 XFREE (MTYPE_AS_STR, aspath->str);
336 XFREE (MTYPE_AS_PATH, aspath);
337}
338
339/* Unintern aspath from AS path bucket. */
340void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000341aspath_unintern (struct aspath **aspath)
paul718e3742002-12-13 20:15:29 +0000342{
343 struct aspath *ret;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000344 struct aspath *asp = *aspath;
345
346 if (asp->refcnt)
347 asp->refcnt--;
paul718e3742002-12-13 20:15:29 +0000348
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000349 if (asp->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000350 {
351 /* This aspath must exist in aspath hash table. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000352 ret = hash_release (ashash, asp);
paul718e3742002-12-13 20:15:29 +0000353 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000354 aspath_free (asp);
355 *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000356 }
357}
358
359/* Return the start or end delimiters for a particular Segment type */
360#define AS_SEG_START 0
361#define AS_SEG_END 1
362static char
363aspath_delimiter_char (u_char type, u_char which)
364{
365 int i;
366 struct
367 {
368 int type;
369 char start;
370 char end;
371 } aspath_delim_char [] =
372 {
373 { AS_SET, '{', '}' },
paul718e3742002-12-13 20:15:29 +0000374 { AS_CONFED_SET, '[', ']' },
375 { AS_CONFED_SEQUENCE, '(', ')' },
376 { 0 }
377 };
378
379 for (i = 0; aspath_delim_char[i].type != 0; i++)
380 {
381 if (aspath_delim_char[i].type == type)
382 {
383 if (which == AS_SEG_START)
384 return aspath_delim_char[i].start;
385 else if (which == AS_SEG_END)
386 return aspath_delim_char[i].end;
387 }
388 }
389 return ' ';
390}
391
Denis Ovsienko014b6702009-06-23 21:10:45 +0400392/* countup asns from this segment and index onward */
393static int
394assegment_count_asns (struct assegment *seg, int from)
395{
396 int count = 0;
397 while (seg)
398 {
399 if (!from)
400 count += seg->length;
401 else
402 {
403 count += (seg->length - from);
404 from = 0;
405 }
406 seg = seg->next;
407 }
408 return count;
409}
410
paulfe69a502005-09-10 16:55:02 +0000411unsigned int
412aspath_count_confeds (struct aspath *aspath)
413{
414 int count = 0;
415 struct assegment *seg = aspath->segments;
416
417 while (seg)
418 {
419 if (seg->type == AS_CONFED_SEQUENCE)
420 count += seg->length;
421 else if (seg->type == AS_CONFED_SET)
422 count++;
423
424 seg = seg->next;
425 }
426 return count;
427}
428
429unsigned int
430aspath_count_hops (struct aspath *aspath)
431{
432 int count = 0;
433 struct assegment *seg = aspath->segments;
434
435 while (seg)
436 {
437 if (seg->type == AS_SEQUENCE)
438 count += seg->length;
439 else if (seg->type == AS_SET)
440 count++;
441
442 seg = seg->next;
443 }
444 return count;
445}
446
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000447/* Estimate size aspath /might/ take if encoded into an
448 * ASPATH attribute.
449 *
450 * This is a quick estimate, not definitive! aspath_put()
451 * may return a different number!!
452 */
paulfe69a502005-09-10 16:55:02 +0000453unsigned int
454aspath_size (struct aspath *aspath)
455{
456 int size = 0;
457 struct assegment *seg = aspath->segments;
458
459 while (seg)
460 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000461 size += ASSEGMENT_SIZE(seg->length, 1);
paulfe69a502005-09-10 16:55:02 +0000462 seg = seg->next;
463 }
464 return size;
465}
466
Paul Jakma2815e612006-09-14 02:56:07 +0000467/* Return highest public ASN in path */
468as_t
469aspath_highest (struct aspath *aspath)
470{
471 struct assegment *seg = aspath->segments;
472 as_t highest = 0;
473 unsigned int i;
474
475 while (seg)
476 {
477 for (i = 0; i < seg->length; i++)
478 if (seg->as[i] > highest
479 && (seg->as[i] < BGP_PRIVATE_AS_MIN
480 || seg->as[i] > BGP_PRIVATE_AS_MAX))
481 highest = seg->as[i];
482 seg = seg->next;
483 }
484 return highest;
485}
486
Timo Teräs85c854a2014-09-30 11:31:53 +0300487/* Return the left-most ASN in path */
488as_t
489aspath_leftmost (struct aspath *aspath)
490{
491 struct assegment *seg = aspath->segments;
492 as_t leftmost = 0;
493
494 if (seg && seg->length && seg->type == AS_SEQUENCE)
495 leftmost = seg->as[0];
496
497 return leftmost;
498}
499
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000500/* Return 1 if there are any 4-byte ASes in the path */
501unsigned int
502aspath_has_as4 (struct aspath *aspath)
503{
504 struct assegment *seg = aspath->segments;
505 unsigned int i;
506
507 while (seg)
508 {
509 for (i = 0; i < seg->length; i++)
510 if (seg->as[i] > BGP_AS_MAX)
511 return 1;
512 seg = seg->next;
513 }
514 return 0;
515}
516
paul718e3742002-12-13 20:15:29 +0000517/* Convert aspath structure to string expression. */
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000518static void
paul718e3742002-12-13 20:15:29 +0000519aspath_make_str_count (struct aspath *as)
520{
paulfe69a502005-09-10 16:55:02 +0000521 struct assegment *seg;
522 int str_size;
523 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000524 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000525
526 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000527 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000528 {
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000529 as->str = XMALLOC (MTYPE_AS_STR, 1);
530 as->str[0] = '\0';
531 as->str_len = 0;
532 return;
paul718e3742002-12-13 20:15:29 +0000533 }
paulfe69a502005-09-10 16:55:02 +0000534
535 seg = as->segments;
536
Denis Ovsienko014b6702009-06-23 21:10:45 +0400537 /* ASN takes 5 to 10 chars plus seperator, see below.
538 * If there is one differing segment type, we need an additional
539 * 2 chars for segment delimiters, and the final '\0'.
540 * Hopefully this is large enough to avoid hitting the realloc
541 * code below for most common sequences.
542 *
543 * This was changed to 10 after the well-known BGP assertion, which
544 * had hit some parts of the Internet in May of 2009.
545 */
546#define ASN_STR_LEN (10 + 1)
547 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
548 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000549 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000550
paulfe69a502005-09-10 16:55:02 +0000551 while (seg)
paul718e3742002-12-13 20:15:29 +0000552 {
553 int i;
paulfe69a502005-09-10 16:55:02 +0000554 char seperator;
paul718e3742002-12-13 20:15:29 +0000555
paulfe69a502005-09-10 16:55:02 +0000556 /* Check AS type validity. Set seperator for segment */
557 switch (seg->type)
558 {
559 case AS_SET:
560 case AS_CONFED_SET:
561 seperator = ',';
562 break;
563 case AS_SEQUENCE:
564 case AS_CONFED_SEQUENCE:
565 seperator = ' ';
566 break;
567 default:
568 XFREE (MTYPE_AS_STR, str_buf);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000569 as->str = NULL;
570 as->str_len = 0;
571 return;
paulfe69a502005-09-10 16:55:02 +0000572 }
573
Denis Ovsienko014b6702009-06-23 21:10:45 +0400574 /* We might need to increase str_buf, particularly if path has
575 * differing segments types, our initial guesstimate above will
576 * have been wrong. Need 10 chars for ASN, a seperator each and
577 * potentially two segment delimiters, plus a space between each
578 * segment and trailing zero.
579 *
580 * This definitely didn't work with the value of 5 bytes and
581 * 32-bit ASNs.
582 */
583#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
584 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
585 {
586 str_size = len + SEGMENT_STR_LEN(seg);
587 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
588 }
589#undef ASN_STR_LEN
590#undef SEGMENT_STR_LEN
591
paulfe69a502005-09-10 16:55:02 +0000592 if (seg->type != AS_SEQUENCE)
Denis Ovsienko014b6702009-06-23 21:10:45 +0400593 len += snprintf (str_buf + len, str_size - len,
594 "%c",
595 aspath_delimiter_char (seg->type, AS_SEG_START));
paulfe69a502005-09-10 16:55:02 +0000596
597 /* write out the ASNs, with their seperators, bar the last one*/
598 for (i = 0; i < seg->length; i++)
599 {
600 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
601
602 if (i < (seg->length - 1))
603 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
604 }
605
606 if (seg->type != AS_SEQUENCE)
607 len += snprintf (str_buf + len, str_size - len, "%c",
608 aspath_delimiter_char (seg->type, AS_SEG_END));
609 if (seg->next)
610 len += snprintf (str_buf + len, str_size - len, " ");
611
612 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000613 }
paulfe69a502005-09-10 16:55:02 +0000614
615 assert (len < str_size);
616
617 str_buf[len] = '\0';
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000618 as->str = str_buf;
619 as->str_len = len;
paul718e3742002-12-13 20:15:29 +0000620
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000621 return;
paul718e3742002-12-13 20:15:29 +0000622}
623
paulfe69a502005-09-10 16:55:02 +0000624static void
625aspath_str_update (struct aspath *as)
626{
627 if (as->str)
628 XFREE (MTYPE_AS_STR, as->str);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000629 aspath_make_str_count (as);
paulfe69a502005-09-10 16:55:02 +0000630}
631
paul718e3742002-12-13 20:15:29 +0000632/* Intern allocated AS path. */
633struct aspath *
634aspath_intern (struct aspath *aspath)
635{
636 struct aspath *find;
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000637
638 /* Assert this AS path structure is not interned and has the string
639 representation built. */
paul718e3742002-12-13 20:15:29 +0000640 assert (aspath->refcnt == 0);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000641 assert (aspath->str);
paul718e3742002-12-13 20:15:29 +0000642
643 /* Check AS path hash. */
644 find = hash_get (ashash, aspath, hash_alloc_intern);
paul718e3742002-12-13 20:15:29 +0000645 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000646 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000647
648 find->refcnt++;
649
paul718e3742002-12-13 20:15:29 +0000650 return find;
651}
652
653/* Duplicate aspath structure. Created same aspath structure but
654 reference count and AS path string is cleared. */
655struct aspath *
656aspath_dup (struct aspath *aspath)
657{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000658 unsigned short buflen = aspath->str_len + 1;
paul718e3742002-12-13 20:15:29 +0000659 struct aspath *new;
660
paulfe69a502005-09-10 16:55:02 +0000661 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000662
paulfe69a502005-09-10 16:55:02 +0000663 if (aspath->segments)
664 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000665
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000666 if (!aspath->str)
667 return new;
668
669 new->str = XMALLOC (MTYPE_AS_STR, buflen);
670 new->str_len = aspath->str_len;
671
672 /* copy the string data */
673 if (aspath->str_len > 0)
674 memcpy (new->str, aspath->str, buflen);
675 else
676 new->str[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000677
678 return new;
679}
680
paul94f2b392005-06-28 12:44:16 +0000681static void *
paulfe69a502005-09-10 16:55:02 +0000682aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000683{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000684 const struct aspath *aspath = arg;
685 struct aspath *new;
686
687 /* Malformed AS path value. */
688 assert (aspath->str);
689 if (! aspath->str)
690 return NULL;
paul718e3742002-12-13 20:15:29 +0000691
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000692 /* New aspath structure is needed. */
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000693 new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000694
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000695 /* Reuse segments and string representation */
696 new->refcnt = 0;
697 new->segments = aspath->segments;
698 new->str = aspath->str;
699 new->str_len = aspath->str_len;
700
701 return new;
paul718e3742002-12-13 20:15:29 +0000702}
703
Paul Jakmaab005292010-11-27 22:48:34 +0000704/* parse as-segment byte stream in struct assegment */
Paul Jakmab881c702010-11-23 16:35:42 +0000705static int
706assegments_parse (struct stream *s, size_t length,
707 struct assegment **result, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000708{
709 struct assegment_header segh;
710 struct assegment *seg, *prev = NULL, *head = NULL;
Paul Jakmaab005292010-11-27 22:48:34 +0000711 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000712
Paul Jakmaab005292010-11-27 22:48:34 +0000713 /* empty aspath (ie iBGP or somesuch) */
714 if (length == 0)
Paul Jakmab881c702010-11-23 16:35:42 +0000715 return 0;
paulfe69a502005-09-10 16:55:02 +0000716
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000717 if (BGP_DEBUG (as4, AS4_SEGMENT))
718 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
719 (unsigned long) length);
Paul Jakmaab005292010-11-27 22:48:34 +0000720 /* basic checks */
721 if ((STREAM_READABLE(s) < length)
722 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
723 || (length % AS16_VALUE_SIZE ))
Paul Jakmab881c702010-11-23 16:35:42 +0000724 return -1;
paulfe69a502005-09-10 16:55:02 +0000725
Paul Jakmaab005292010-11-27 22:48:34 +0000726 while (bytes < length)
paulfe69a502005-09-10 16:55:02 +0000727 {
728 int i;
Chris Hallcddb8112010-08-09 22:31:37 +0400729 size_t seg_size;
paulfe69a502005-09-10 16:55:02 +0000730
Paul Jakmaab005292010-11-27 22:48:34 +0000731 if ((length - bytes) <= AS_HEADER_SIZE)
Chris Hallcddb8112010-08-09 22:31:37 +0400732 {
Paul Jakmaab005292010-11-27 22:48:34 +0000733 if (head)
734 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000735 return -1;
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100736 }
737
Paul Jakmaab005292010-11-27 22:48:34 +0000738 /* softly softly, get the header first on its own */
paulfe69a502005-09-10 16:55:02 +0000739 segh.type = stream_getc (s);
740 segh.length = stream_getc (s);
741
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000742 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
743
744 if (BGP_DEBUG (as4, AS4_SEGMENT))
745 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
746 segh.type, segh.length);
747
Paul Jakmaab005292010-11-27 22:48:34 +0000748 /* check it.. */
749 if ( ((bytes + seg_size) > length)
750 /* 1771bis 4.3b: seg length contains one or more */
751 || (segh.length == 0)
752 /* Paranoia in case someone changes type of segment length.
753 * Shift both values by 0x10 to make the comparison operate
754 * on more, than 8 bits (otherwise it's a warning, bug #564).
Denis Ovsienko2eb445e2009-12-04 17:32:54 +0300755 */
Paul Jakmaab005292010-11-27 22:48:34 +0000756 || ((sizeof segh.length > 1)
757 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
paulfe69a502005-09-10 16:55:02 +0000758 {
Paul Jakmaab005292010-11-27 22:48:34 +0000759 if (head)
paulfe69a502005-09-10 16:55:02 +0000760 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000761 return -1;
paulfe69a502005-09-10 16:55:02 +0000762 }
763
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100764 switch (segh.type)
765 {
766 case AS_SEQUENCE:
767 case AS_SET:
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100768 case AS_CONFED_SEQUENCE:
769 case AS_CONFED_SET:
Paul Jakmaab005292010-11-27 22:48:34 +0000770 break;
771 default:
772 if (head)
773 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000774 return -1;
paulfe69a502005-09-10 16:55:02 +0000775 }
Chris Hallcddb8112010-08-09 22:31:37 +0400776
paulfe69a502005-09-10 16:55:02 +0000777 /* now its safe to trust lengths */
778 seg = assegment_new (segh.type, segh.length);
779
780 if (head)
781 prev->next = seg;
782 else /* it's the first segment */
783 head = prev = seg;
784
785 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000786 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
787
Paul Jakmaab005292010-11-27 22:48:34 +0000788 bytes += seg_size;
789
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000790 if (BGP_DEBUG (as4, AS4_SEGMENT))
Paul Jakmaab005292010-11-27 22:48:34 +0000791 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
792 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000793
794 prev = seg;
795 }
796
Paul Jakmab881c702010-11-23 16:35:42 +0000797 *result = assegment_normalise (head);
798 return 0;
paulfe69a502005-09-10 16:55:02 +0000799}
800
Paul Jakmaab005292010-11-27 22:48:34 +0000801/* AS path parse function. pnt is a pointer to byte stream and length
802 is length of byte stream. If there is same AS path in the the AS
Paul Jakmab881c702010-11-23 16:35:42 +0000803 path hash then return it else make new AS path structure.
804
805 On error NULL is returned.
Chris Hallcddb8112010-08-09 22:31:37 +0400806 */
paul718e3742002-12-13 20:15:29 +0000807struct aspath *
Paul Jakmaab005292010-11-27 22:48:34 +0000808aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000809{
810 struct aspath as;
811 struct aspath *find;
812
Paul Jakmaab005292010-11-27 22:48:34 +0000813 /* If length is odd it's malformed AS path. */
814 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
815 * otherwise its malformed when length is larger than 2 and (length-2)
816 * is not dividable by 4.
817 * But... this time we're lazy
818 */
819 if (length % AS16_VALUE_SIZE )
820 return NULL;
Chris Hallcddb8112010-08-09 22:31:37 +0400821
Paul Jakmaab005292010-11-27 22:48:34 +0000822 memset (&as, 0, sizeof (struct aspath));
Paul Jakmab881c702010-11-23 16:35:42 +0000823 if (assegments_parse (s, length, &as.segments, use32bit) < 0)
824 return NULL;
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000825
paul718e3742002-12-13 20:15:29 +0000826 /* If already same aspath exist then return it. */
827 find = hash_get (ashash, &as, aspath_hash_alloc);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000828
829 /* bug! should not happen, let the daemon crash below */
830 assert (find);
831
832 /* if the aspath was already hashed free temporary memory. */
833 if (find->refcnt)
834 {
835 assegment_free_all (as.segments);
836 /* aspath_key_make() always updates the string */
837 XFREE (MTYPE_AS_STR, as.str);
838 }
839
paul718e3742002-12-13 20:15:29 +0000840 find->refcnt++;
841
842 return find;
843}
844
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100845static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000846assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000847{
paulfe69a502005-09-10 16:55:02 +0000848 int i;
849 assert (num <= AS_SEGMENT_MAX);
850
851 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000852 if ( use32bit )
853 stream_putl (s, as[i]);
854 else
855 {
856 if ( as[i] <= BGP_AS_MAX )
857 stream_putw(s, as[i]);
858 else
859 stream_putw(s, BGP_AS_TRANS);
860 }
paul718e3742002-12-13 20:15:29 +0000861}
862
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100863static size_t
paulfe69a502005-09-10 16:55:02 +0000864assegment_header_put (struct stream *s, u_char type, int length)
865{
866 size_t lenp;
867 assert (length <= AS_SEGMENT_MAX);
868 stream_putc (s, type);
869 lenp = stream_get_endp (s);
870 stream_putc (s, length);
871 return lenp;
872}
873
874/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000875size_t
876aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000877{
878 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000879 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000880
881 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000882 return 0;
paulfe69a502005-09-10 16:55:02 +0000883
884 if (seg)
885 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000886 /*
887 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
888 * At the moment, we would write out a partial aspath, and our peer
889 * will complain and drop the session :-/
890 *
891 * The general assumption here is that many things tested will
892 * never happen. And, in real live, up to now, they have not.
893 */
894 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000895 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000896 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000897 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000898 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000899 size_t lenp;
900
901 /* Overlength segments have to be split up */
902 while ( (seg->length - written) > AS_SEGMENT_MAX)
903 {
904 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000905 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000906 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000907 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000908 }
909
910 /* write the final segment, probably is also the first */
911 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000912 assegment_data_put (s, (seg->as + written), seg->length - written,
913 use32bit);
paulfe69a502005-09-10 16:55:02 +0000914
915 /* Sequence-type segments can be 'packed' together
916 * Case of a segment which was overlength and split up
917 * will be missed here, but that doesn't matter.
918 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000919 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000920 {
921 /* NB: We should never normally get here given we
922 * normalise aspath data when parse them. However, better
923 * safe than sorry. We potentially could call
924 * assegment_normalise here instead, but it's cheaper and
925 * easier to do it on the fly here rather than go through
926 * the segment list twice every time we write out
927 * aspath's.
928 */
929
930 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000931 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000932
933 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000934 stream_putc_at (s, lenp, seg->length - written + next->length);
935 asns_packed += next->length;
936
937 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000938 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000939
940 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
941 use32bit);
942 seg = next;
paulfe69a502005-09-10 16:55:02 +0000943 }
944 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000945 return bytes;
paulfe69a502005-09-10 16:55:02 +0000946}
947
948/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
949 * We have no way to manage the storage, so we use a static stream
950 * wrapper around aspath_put.
951 */
952u_char *
953aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
954{
955#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000956
957 if (!snmp_stream)
958 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000959 else
paul8fdc32a2006-01-16 12:01:29 +0000960 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000961
962 if (!as)
963 {
964 *varlen = 0;
965 return NULL;
966 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000967 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000968
paul8fdc32a2006-01-16 12:01:29 +0000969 *varlen = stream_get_endp (snmp_stream);
970 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000971}
972
973#define min(A,B) ((A) < (B) ? (A) : (B))
974
paul94f2b392005-06-28 12:44:16 +0000975static struct assegment *
paul718e3742002-12-13 20:15:29 +0000976aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
977 as_t as)
978{
979 int i;
980
981 /* If this is first AS set member, create new as-set segment. */
982 if (asset == NULL)
983 {
paulfe69a502005-09-10 16:55:02 +0000984 asset = assegment_new (AS_SET, 1);
985 if (! aspath->segments)
986 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000987 else
paulfe69a502005-09-10 16:55:02 +0000988 {
989 struct assegment *seg = aspath->segments;
990 while (seg->next)
991 seg = seg->next;
992 seg->next = asset;
993 }
paul718e3742002-12-13 20:15:29 +0000994 asset->type = AS_SET;
995 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000996 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000997 }
998 else
999 {
paul718e3742002-12-13 20:15:29 +00001000 /* Check this AS value already exists or not. */
1001 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +00001002 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +00001003 return asset;
paulfe69a502005-09-10 16:55:02 +00001004
paul718e3742002-12-13 20:15:29 +00001005 asset->length++;
paulfe69a502005-09-10 16:55:02 +00001006 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
1007 asset->length * AS_VALUE_SIZE);
1008 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +00001009 }
paulfe69a502005-09-10 16:55:02 +00001010
paul718e3742002-12-13 20:15:29 +00001011
1012 return asset;
1013}
1014
1015/* Modify as1 using as2 for aggregation. */
1016struct aspath *
1017aspath_aggregate (struct aspath *as1, struct aspath *as2)
1018{
1019 int i;
1020 int minlen;
1021 int match;
paulfe69a502005-09-10 16:55:02 +00001022 int from;
1023 struct assegment *seg1 = as1->segments;
1024 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001025 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +00001026 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001027 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +00001028
1029 match = 0;
1030 minlen = 0;
1031 aspath = NULL;
1032 asset = NULL;
paul718e3742002-12-13 20:15:29 +00001033
1034 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +00001035 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001036 {
paul718e3742002-12-13 20:15:29 +00001037 /* Check segment type. */
1038 if (seg1->type != seg2->type)
1039 break;
1040
1041 /* Minimum segment length. */
1042 minlen = min (seg1->length, seg2->length);
1043
1044 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001045 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001046 break;
1047
1048 if (match)
1049 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001050 struct assegment *seg = assegment_new (seg1->type, 0);
1051
1052 seg = assegment_append_asns (seg, seg1->as, match);
1053
paul718e3742002-12-13 20:15:29 +00001054 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001055 {
1056 aspath = aspath_new ();
1057 aspath->segments = seg;
1058 }
1059 else
1060 prevseg->next = seg;
1061
1062 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001063 }
1064
1065 if (match != minlen || match != seg1->length
1066 || seg1->length != seg2->length)
1067 break;
paulfe69a502005-09-10 16:55:02 +00001068
1069 seg1 = seg1->next;
1070 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001071 }
1072
1073 if (! aspath)
1074 aspath = aspath_new();
1075
1076 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001077 from = match;
1078 while (seg1)
paul718e3742002-12-13 20:15:29 +00001079 {
paulfe69a502005-09-10 16:55:02 +00001080 for (i = from; i < seg1->length; i++)
1081 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1082
1083 from = 0;
1084 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001085 }
1086
paulfe69a502005-09-10 16:55:02 +00001087 from = match;
1088 while (seg2)
paul718e3742002-12-13 20:15:29 +00001089 {
paulfe69a502005-09-10 16:55:02 +00001090 for (i = from; i < seg2->length; i++)
1091 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001092
paulfe69a502005-09-10 16:55:02 +00001093 from = 0;
1094 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001095 }
paulfe69a502005-09-10 16:55:02 +00001096
1097 assegment_normalise (aspath->segments);
1098 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001099 return aspath;
1100}
1101
Boian Boneva3936d02014-06-25 20:26:44 +03001102/* Modify as1 using as2 for aggregation for multipath, keeping the
1103 * AS-Path length the same, and so minimising change to the preference
1104 * of the mpath aggregrate route.
1105 */
1106struct aspath *
1107aspath_aggregate_mpath (struct aspath *as1, struct aspath *as2)
1108{
1109 int i;
1110 int minlen;
1111 int match;
1112 int from1,from2;
1113 struct assegment *seg1 = as1->segments;
1114 struct assegment *seg2 = as2->segments;
1115 struct aspath *aspath = NULL;
1116 struct assegment *asset;
1117 struct assegment *prevseg = NULL;
1118
1119 match = 0;
1120 minlen = 0;
1121 aspath = NULL;
1122 asset = NULL;
1123
1124 /* First of all check common leading sequence. */
1125 while (seg1 && seg2)
1126 {
1127 /* Check segment type. */
1128 if (seg1->type != seg2->type)
1129 break;
1130
1131 /* Minimum segment length. */
1132 minlen = min (seg1->length, seg2->length);
1133
1134 for (match = 0; match < minlen; match++)
1135 if (seg1->as[match] != seg2->as[match])
1136 break;
1137
1138 if (match)
1139 {
1140 struct assegment *seg = assegment_new (seg1->type, 0);
1141
1142 seg = assegment_append_asns (seg, seg1->as, match);
1143
1144 if (! aspath)
1145 {
1146 aspath = aspath_new ();
1147 aspath->segments = seg;
1148 }
1149 else
1150 prevseg->next = seg;
1151
1152 prevseg = seg;
1153 }
1154
1155 if (match != minlen || match != seg1->length
1156 || seg1->length != seg2->length)
1157 break;
1158
1159 seg1 = seg1->next;
1160 seg2 = seg2->next;
1161 }
1162
1163 if (! aspath)
1164 aspath = aspath_new();
1165
1166 /* Make as-set using rest of all information. */
1167 from1 = from2 = match;
1168 while (seg1 || seg2)
1169 {
1170 if (seg1)
1171 {
1172 if (seg1->type == AS_SEQUENCE)
1173 {
1174 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[from1]);
1175 from1++;
1176 if (from1 >= seg1->length)
1177 {
1178 from1 = 0;
1179 seg1 = seg1->next;
1180 }
1181 }
1182 else
1183 {
1184 for (i = from1; i < seg1->length; i++)
1185 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1186
1187 from1 = 0;
1188 seg1 = seg1->next;
1189 }
1190 }
1191
1192 if (seg2)
1193 {
1194 if (seg2->type == AS_SEQUENCE)
1195 {
1196 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[from2]);
1197 from2++;
1198 if (from2 >= seg2->length)
1199 {
1200 from2 = 0;
1201 seg2 = seg2->next;
1202 }
1203 }
1204 else
1205 {
1206 for (i = from2; i < seg2->length; i++)
1207 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
1208
1209 from2 = 0;
1210 seg2 = seg2->next;
1211 }
1212 }
1213
1214 if (asset->length == 1)
1215 asset->type = AS_SEQUENCE;
1216 asset = NULL;
1217 }
1218
1219 assegment_normalise (aspath->segments);
1220 aspath_str_update (aspath);
1221 return aspath;
1222}
1223
paul718e3742002-12-13 20:15:29 +00001224/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1225 attribute, check the leftmost AS number in the AS_PATH attribute is
1226 or not the peer's AS number. */
1227int
1228aspath_firstas_check (struct aspath *aspath, as_t asno)
1229{
paulfe69a502005-09-10 16:55:02 +00001230 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001231 return 0;
paulfe69a502005-09-10 16:55:02 +00001232
1233 if (aspath->segments
1234 && (aspath->segments->type == AS_SEQUENCE)
1235 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001236 return 1;
1237
1238 return 0;
1239}
1240
Paul Jakma1f742f22006-08-06 15:52:11 +00001241/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001242int
1243aspath_loop_check (struct aspath *aspath, as_t asno)
1244{
paulfe69a502005-09-10 16:55:02 +00001245 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001246 int count = 0;
1247
Paul Jakma1f742f22006-08-06 15:52:11 +00001248 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001249 return 0;
paulfe69a502005-09-10 16:55:02 +00001250
1251 seg = aspath->segments;
1252
1253 while (seg)
paul718e3742002-12-13 20:15:29 +00001254 {
1255 int i;
paul718e3742002-12-13 20:15:29 +00001256
paulfe69a502005-09-10 16:55:02 +00001257 for (i = 0; i < seg->length; i++)
1258 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001259 count++;
paulfe69a502005-09-10 16:55:02 +00001260
1261 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001262 }
1263 return count;
1264}
1265
1266/* When all of AS path is private AS return 1. */
1267int
1268aspath_private_as_check (struct aspath *aspath)
1269{
paulfe69a502005-09-10 16:55:02 +00001270 struct assegment *seg;
1271
1272 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001273 return 0;
paulfe69a502005-09-10 16:55:02 +00001274
1275 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001276
paulfe69a502005-09-10 16:55:02 +00001277 while (seg)
paul718e3742002-12-13 20:15:29 +00001278 {
1279 int i;
paul718e3742002-12-13 20:15:29 +00001280
paulfe69a502005-09-10 16:55:02 +00001281 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001282 {
paulfe69a502005-09-10 16:55:02 +00001283 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1284 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001285 return 0;
1286 }
paulfe69a502005-09-10 16:55:02 +00001287 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001288 }
1289 return 1;
1290}
1291
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001292/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1293int
1294aspath_confed_check (struct aspath *aspath)
1295{
1296 struct assegment *seg;
1297
1298 if ( !(aspath && aspath->segments) )
1299 return 0;
1300
1301 seg = aspath->segments;
1302
1303 while (seg)
1304 {
1305 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1306 return 1;
1307 seg = seg->next;
1308 }
1309 return 0;
1310}
1311
1312/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1313 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1314int
1315aspath_left_confed_check (struct aspath *aspath)
1316{
1317
1318 if ( !(aspath && aspath->segments) )
1319 return 0;
1320
1321 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1322 || (aspath->segments->type == AS_CONFED_SET) )
1323 return 1;
1324
1325 return 0;
1326}
1327
paul718e3742002-12-13 20:15:29 +00001328/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001329static struct aspath *
paul718e3742002-12-13 20:15:29 +00001330aspath_merge (struct aspath *as1, struct aspath *as2)
1331{
paulfe69a502005-09-10 16:55:02 +00001332 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001333
1334 if (! as1 || ! as2)
1335 return NULL;
1336
paulfe69a502005-09-10 16:55:02 +00001337 last = new = assegment_dup_all (as1->segments);
1338
1339 /* find the last valid segment */
1340 while (last && last->next)
1341 last = last->next;
1342
1343 last->next = as2->segments;
1344 as2->segments = new;
1345 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001346 return as2;
1347}
1348
1349/* Prepend as1 to as2. as2 should be uninterned aspath. */
1350struct aspath *
1351aspath_prepend (struct aspath *as1, struct aspath *as2)
1352{
paulfe69a502005-09-10 16:55:02 +00001353 struct assegment *seg1;
1354 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001355
1356 if (! as1 || ! as2)
1357 return NULL;
paulfe69a502005-09-10 16:55:02 +00001358
1359 seg1 = as1->segments;
1360 seg2 = as2->segments;
1361
1362 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001363 if (seg2 == NULL)
1364 {
paulfe69a502005-09-10 16:55:02 +00001365 as2->segments = assegment_dup_all (as1->segments);
1366 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001367 return as2;
1368 }
paulfe69a502005-09-10 16:55:02 +00001369
1370 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001371 if (seg1 == NULL)
1372 return as2;
paulfe69a502005-09-10 16:55:02 +00001373
1374 /* find the tail as1's segment chain. */
1375 while (seg1 && seg1->next)
1376 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001377
Vasilis Tsiligiannis736d4402009-07-20 01:59:10 +03001378 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1379 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1380 as2 = aspath_delete_confed_seq (as2);
1381
paul718e3742002-12-13 20:15:29 +00001382 /* Compare last segment type of as1 and first segment type of as2. */
1383 if (seg1->type != seg2->type)
1384 return aspath_merge (as1, as2);
1385
1386 if (seg1->type == AS_SEQUENCE)
1387 {
paulfe69a502005-09-10 16:55:02 +00001388 /* We have two chains of segments, as1->segments and seg2,
1389 * and we have to attach them together, merging the attaching
1390 * segments together into one.
1391 *
1392 * 1. dupe as1->segments onto head of as2
1393 * 2. merge seg2's asns onto last segment of this new chain
1394 * 3. attach chain after seg2
1395 */
paul718e3742002-12-13 20:15:29 +00001396
paulfe69a502005-09-10 16:55:02 +00001397 /* dupe as1 onto as2's head */
1398 seg1 = as2->segments = assegment_dup_all (as1->segments);
1399
1400 /* refind the tail of as2, reusing seg1 */
1401 while (seg1 && seg1->next)
1402 seg1 = seg1->next;
1403
1404 /* merge the old head, seg2, into tail, seg1 */
1405 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1406
1407 /* bypass the merged seg2, and attach any chain after it to
1408 * chain descending from as2's head
1409 */
1410 seg1->next = seg2->next;
1411
1412 /* seg2 is now referenceless and useless*/
1413 assegment_free (seg2);
1414
1415 /* we've now prepended as1's segment chain to as2, merging
1416 * the inbetween AS_SEQUENCE of seg2 in the process
1417 */
1418 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001419 return as2;
1420 }
1421 else
1422 {
1423 /* AS_SET merge code is needed at here. */
1424 return aspath_merge (as1, as2);
1425 }
paulfe69a502005-09-10 16:55:02 +00001426 /* XXX: Ermmm, what if as1 has multiple segments?? */
1427
paul718e3742002-12-13 20:15:29 +00001428 /* Not reached */
1429}
1430
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001431/* Iterate over AS_PATH segments and wipe all occurences of the
1432 * listed AS numbers. Hence some segments may lose some or even
1433 * all data on the way, the operation is implemented as a smarter
1434 * version of aspath_dup(), which allocates memory to hold the new
1435 * data, not the original. The new AS path is returned.
1436 */
1437struct aspath *
1438aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1439{
1440 struct assegment * srcseg, * exclseg, * lastseg;
1441 struct aspath * newpath;
1442
1443 newpath = aspath_new();
1444 lastseg = NULL;
1445
1446 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1447 {
1448 unsigned i, y, newlen = 0, done = 0, skip_as;
1449 struct assegment * newseg;
1450
1451 /* Find out, how much ASns are we going to pick from this segment.
1452 * We can't perform filtering right inline, because the size of
1453 * the new segment isn't known at the moment yet.
1454 */
1455 for (i = 0; i < srcseg->length; i++)
1456 {
1457 skip_as = 0;
1458 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1459 for (y = 0; y < exclseg->length; y++)
1460 if (srcseg->as[i] == exclseg->as[y])
1461 {
1462 skip_as = 1;
1463 // There's no sense in testing the rest of exclusion list, bail out.
1464 break;
1465 }
1466 if (!skip_as)
1467 newlen++;
1468 }
1469 /* newlen is now the number of ASns to copy */
1470 if (!newlen)
1471 continue;
1472
1473 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1474 newseg = assegment_new (srcseg->type, newlen);
1475 for (i = 0; i < srcseg->length; i++)
1476 {
1477 skip_as = 0;
1478 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1479 for (y = 0; y < exclseg->length; y++)
1480 if (srcseg->as[i] == exclseg->as[y])
1481 {
1482 skip_as = 1;
1483 break;
1484 }
1485 if (skip_as)
1486 continue;
1487 newseg->as[done++] = srcseg->as[i];
1488 }
1489 /* At his point newlen must be equal to done, and both must be positive. Append
1490 * the filtered segment to the gross result. */
1491 if (!lastseg)
1492 newpath->segments = newseg;
1493 else
1494 lastseg->next = newseg;
1495 lastseg = newseg;
1496 }
1497 aspath_str_update (newpath);
1498 /* We are happy returning even an empty AS_PATH, because the administrator
1499 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1500 * by having a match rule against certain AS_PATH regexps in the route-map index.
1501 */
1502 aspath_free (source);
1503 return newpath;
1504}
1505
paul718e3742002-12-13 20:15:29 +00001506/* Add specified AS to the leftmost of aspath. */
1507static struct aspath *
Timo Teräs85c854a2014-09-30 11:31:53 +03001508aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num)
paul718e3742002-12-13 20:15:29 +00001509{
paulfe69a502005-09-10 16:55:02 +00001510 struct assegment *assegment = aspath->segments;
David Lamparter21401f32015-03-03 08:55:26 +01001511 unsigned i;
paul718e3742002-12-13 20:15:29 +00001512
Timo Teräs85c854a2014-09-30 11:31:53 +03001513 if (assegment && assegment->type == type)
paul718e3742002-12-13 20:15:29 +00001514 {
Timo Teräs85c854a2014-09-30 11:31:53 +03001515 /* extend existing segment */
1516 aspath->segments = assegment_prepend_asns (aspath->segments, asno, num);
paul718e3742002-12-13 20:15:29 +00001517 }
paulfe69a502005-09-10 16:55:02 +00001518 else
paul718e3742002-12-13 20:15:29 +00001519 {
Timo Teräs85c854a2014-09-30 11:31:53 +03001520 /* prepend with new segment */
1521 struct assegment *newsegment = assegment_new (type, num);
1522 for (i = 0; i < num; i++)
1523 newsegment->as[i] = asno;
1524
1525 /* insert potentially replacing empty segment */
1526 if (assegment && assegment->length == 0)
1527 {
1528 newsegment->next = assegment->next;
1529 assegment_free (assegment);
1530 }
1531 else
1532 newsegment->next = assegment;
paulfe69a502005-09-10 16:55:02 +00001533 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001534 }
1535
Timo Teräs85c854a2014-09-30 11:31:53 +03001536 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001537 return aspath;
1538}
1539
Timo Teräs85c854a2014-09-30 11:31:53 +03001540/* Add specified AS to the leftmost of aspath num times. */
1541struct aspath *
1542aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num)
1543{
1544 return aspath_add_asns (aspath, asno, AS_SEQUENCE, num);
1545}
1546
paul718e3742002-12-13 20:15:29 +00001547/* Add specified AS to the leftmost of aspath. */
1548struct aspath *
1549aspath_add_seq (struct aspath *aspath, as_t asno)
1550{
Timo Teräs85c854a2014-09-30 11:31:53 +03001551 return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1);
paul718e3742002-12-13 20:15:29 +00001552}
1553
1554/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1555 as2's leftmost AS is same return 1. */
1556int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001557aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001558{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001559 const struct assegment *seg1;
1560 const struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001561
paulfe69a502005-09-10 16:55:02 +00001562 if (!(aspath1 && aspath2))
1563 return 0;
paul718e3742002-12-13 20:15:29 +00001564
paulfe69a502005-09-10 16:55:02 +00001565 seg1 = aspath1->segments;
1566 seg2 = aspath2->segments;
1567
1568 /* find first non-confed segments for each */
1569 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1570 || (seg1->type == AS_CONFED_SET)))
1571 seg1 = seg1->next;
1572
1573 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1574 || (seg2->type == AS_CONFED_SET)))
1575 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001576
1577 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001578 if (!(seg1 && seg2
1579 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001580 return 0;
paulfe69a502005-09-10 16:55:02 +00001581
1582 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001583 return 1;
1584
1585 return 0;
1586}
1587
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001588/* Truncate an aspath after a number of hops, and put the hops remaining
1589 * at the front of another aspath. Needed for AS4 compat.
1590 *
1591 * Returned aspath is a /new/ aspath, which should either by free'd or
1592 * interned by the caller, as desired.
1593 */
1594struct aspath *
1595aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1596{
1597 struct assegment *seg, *newseg, *prevseg = NULL;
1598 struct aspath *newpath = NULL, *mergedpath;
1599 int hops, cpasns = 0;
1600
1601 if (!aspath)
1602 return NULL;
1603
1604 seg = aspath->segments;
1605
1606 /* CONFEDs should get reconciled too.. */
1607 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1608 - aspath_count_hops (as4path);
1609
1610 if (hops < 0)
1611 {
1612 if (BGP_DEBUG (as4, AS4))
1613 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1614 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1615 * which is daft behaviour - it contains vital loop-detection
1616 * information which must have been removed from AS_PATH.
1617 */
1618 hops = aspath_count_hops (aspath);
1619 }
1620
1621 if (!hops)
1622 return aspath_dup (as4path);
1623
1624 if ( BGP_DEBUG(as4, AS4))
1625 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1626 aspath->str, as4path->str);
1627
1628 while (seg && hops > 0)
1629 {
1630 switch (seg->type)
1631 {
1632 case AS_SET:
1633 case AS_CONFED_SET:
1634 hops--;
1635 cpasns = seg->length;
1636 break;
1637 case AS_CONFED_SEQUENCE:
1638 /* Should never split a confed-sequence, if hop-count
1639 * suggests we must then something's gone wrong somewhere.
1640 *
1641 * Most important goal is to preserve AS_PATHs prime function
1642 * as loop-detector, so we fudge the numbers so that the entire
1643 * confed-sequence is merged in.
1644 */
1645 if (hops < seg->length)
1646 {
1647 if (BGP_DEBUG (as4, AS4))
1648 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1649 " across 2/4 ASN boundary somewhere, broken..");
1650 hops = seg->length;
1651 }
1652 case AS_SEQUENCE:
1653 cpasns = MIN(seg->length, hops);
1654 hops -= seg->length;
1655 }
1656
1657 assert (cpasns <= seg->length);
1658
1659 newseg = assegment_new (seg->type, 0);
1660 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1661
1662 if (!newpath)
1663 {
1664 newpath = aspath_new ();
1665 newpath->segments = newseg;
1666 }
1667 else
1668 prevseg->next = newseg;
1669
1670 prevseg = newseg;
1671 seg = seg->next;
1672 }
1673
1674 /* We may be able to join some segments here, and we must
1675 * do this because... we want normalised aspaths in out hash
1676 * and we do not want to stumble in aspath_put.
1677 */
1678 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1679 aspath_free (newpath);
1680 mergedpath->segments = assegment_normalise (mergedpath->segments);
1681 aspath_str_update (mergedpath);
1682
1683 if ( BGP_DEBUG(as4, AS4))
1684 zlog_debug ("[AS4] result of synthesizing is %s",
1685 mergedpath->str);
1686
1687 return mergedpath;
1688}
1689
paul718e3742002-12-13 20:15:29 +00001690/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1691 as2's leftmost AS is same return 1. (confederation as-path
1692 only). */
1693int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001694aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001695{
paulfe69a502005-09-10 16:55:02 +00001696 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001697 return 0;
paulfe69a502005-09-10 16:55:02 +00001698
paulad727402005-11-23 02:47:02 +00001699 if ( !(aspath1->segments && aspath2->segments) )
1700 return 0;
1701
paulfe69a502005-09-10 16:55:02 +00001702 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1703 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001704 return 0;
paulfe69a502005-09-10 16:55:02 +00001705
1706 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001707 return 1;
1708
1709 return 0;
1710}
1711
paulfe69a502005-09-10 16:55:02 +00001712/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1713 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001714struct aspath *
1715aspath_delete_confed_seq (struct aspath *aspath)
1716{
paulfe69a502005-09-10 16:55:02 +00001717 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001718
paulfe69a502005-09-10 16:55:02 +00001719 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001720 return aspath;
1721
paulfe69a502005-09-10 16:55:02 +00001722 seg = aspath->segments;
1723
1724 /* "if the first path segment of the AS_PATH is
1725 * of type AS_CONFED_SEQUENCE,"
1726 */
1727 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1728 return aspath;
paul718e3742002-12-13 20:15:29 +00001729
paulfe69a502005-09-10 16:55:02 +00001730 /* "... that segment and any immediately following segments
1731 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1732 * from the AS_PATH attribute,"
1733 */
1734 while (seg &&
1735 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001736 {
paulfe69a502005-09-10 16:55:02 +00001737 aspath->segments = seg->next;
1738 assegment_free (seg);
1739 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001740 }
paulfe69a502005-09-10 16:55:02 +00001741 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001742 return aspath;
1743}
1744
1745/* Add new AS number to the leftmost part of the aspath as
1746 AS_CONFED_SEQUENCE. */
1747struct aspath*
1748aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1749{
Timo Teräs85c854a2014-09-30 11:31:53 +03001750 return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1);
paul718e3742002-12-13 20:15:29 +00001751}
1752
1753/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001754static void
paul718e3742002-12-13 20:15:29 +00001755aspath_as_add (struct aspath *as, as_t asno)
1756{
paulfe69a502005-09-10 16:55:02 +00001757 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001758
paulfe69a502005-09-10 16:55:02 +00001759 if (!seg)
1760 return;
1761
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001762 /* Last segment search procedure. */
1763 while (seg->next)
1764 seg = seg->next;
1765
paulfe69a502005-09-10 16:55:02 +00001766 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001767}
1768
1769/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001770static void
paul718e3742002-12-13 20:15:29 +00001771aspath_segment_add (struct aspath *as, int type)
1772{
paulfe69a502005-09-10 16:55:02 +00001773 struct assegment *seg = as->segments;
1774 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001775
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001776 if (seg)
1777 {
1778 while (seg->next)
1779 seg = seg->next;
1780 seg->next = new;
1781 }
paul718e3742002-12-13 20:15:29 +00001782 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001783 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001784}
1785
1786struct aspath *
paul94f2b392005-06-28 12:44:16 +00001787aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001788{
Paul Jakmaab005292010-11-27 22:48:34 +00001789 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001790}
1791
1792struct aspath *
paul94f2b392005-06-28 12:44:16 +00001793aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001794{
1795 struct aspath *aspath;
1796
1797 aspath = aspath_new ();
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001798 aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +00001799 return aspath;
1800}
1801
1802unsigned long
paulfe69a502005-09-10 16:55:02 +00001803aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001804{
1805 return ashash->count;
1806}
David Lamparter6b0655a2014-06-04 06:53:35 +02001807
paul718e3742002-12-13 20:15:29 +00001808/*
1809 Theoretically, one as path can have:
1810
1811 One BGP packet size should be less than 4096.
1812 One BGP attribute size should be less than 4096 - BGP header size.
1813 One BGP aspath size should be less than 4096 - BGP header size -
1814 BGP mandantry attribute size.
1815*/
1816
1817/* AS path string lexical token enum. */
1818enum as_token
1819{
1820 as_token_asval,
1821 as_token_set_start,
1822 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001823 as_token_confed_seq_start,
1824 as_token_confed_seq_end,
1825 as_token_confed_set_start,
1826 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001827 as_token_unknown
1828};
1829
1830/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001831static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001832aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001833{
paulfd79ac92004-10-13 05:06:08 +00001834 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001835
paulfe69a502005-09-10 16:55:02 +00001836 /* Skip seperators (space for sequences, ',' for sets). */
1837 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001838 p++;
1839
1840 /* Check the end of the string and type specify characters
1841 (e.g. {}()). */
1842 switch (*p)
1843 {
1844 case '\0':
1845 return NULL;
paul718e3742002-12-13 20:15:29 +00001846 case '{':
1847 *token = as_token_set_start;
1848 p++;
1849 return p;
paul718e3742002-12-13 20:15:29 +00001850 case '}':
1851 *token = as_token_set_end;
1852 p++;
1853 return p;
paul718e3742002-12-13 20:15:29 +00001854 case '(':
paulfe69a502005-09-10 16:55:02 +00001855 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001856 p++;
1857 return p;
paul718e3742002-12-13 20:15:29 +00001858 case ')':
paulfe69a502005-09-10 16:55:02 +00001859 *token = as_token_confed_seq_end;
1860 p++;
1861 return p;
paulfe69a502005-09-10 16:55:02 +00001862 case '[':
1863 *token = as_token_confed_set_start;
1864 p++;
1865 return p;
paulfe69a502005-09-10 16:55:02 +00001866 case ']':
1867 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001868 p++;
1869 return p;
paul718e3742002-12-13 20:15:29 +00001870 }
1871
1872 /* Check actual AS value. */
1873 if (isdigit ((int) *p))
1874 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001875 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001876
paul718e3742002-12-13 20:15:29 +00001877 *token = as_token_asval;
1878 asval = (*p - '0');
1879 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001880
paul718e3742002-12-13 20:15:29 +00001881 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001882 {
1883 asval *= 10;
1884 asval += (*p - '0');
1885 p++;
1886 }
paul718e3742002-12-13 20:15:29 +00001887 *asno = asval;
1888 return p;
1889 }
1890
1891 /* There is no match then return unknown token. */
1892 *token = as_token_unknown;
1893 return p++;
1894}
1895
1896struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001897aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001898{
paul3fff6ff2006-02-05 17:55:35 +00001899 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001900 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001901 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001902 struct aspath *aspath;
1903 int needtype;
1904
1905 aspath = aspath_new ();
1906
1907 /* We start default type as AS_SEQUENCE. */
1908 as_type = AS_SEQUENCE;
1909 needtype = 1;
1910
1911 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1912 {
1913 switch (token)
1914 {
1915 case as_token_asval:
1916 if (needtype)
1917 {
1918 aspath_segment_add (aspath, as_type);
1919 needtype = 0;
1920 }
1921 aspath_as_add (aspath, asno);
1922 break;
1923 case as_token_set_start:
1924 as_type = AS_SET;
1925 aspath_segment_add (aspath, as_type);
1926 needtype = 0;
1927 break;
1928 case as_token_set_end:
1929 as_type = AS_SEQUENCE;
1930 needtype = 1;
1931 break;
paulfe69a502005-09-10 16:55:02 +00001932 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001933 as_type = AS_CONFED_SEQUENCE;
1934 aspath_segment_add (aspath, as_type);
1935 needtype = 0;
1936 break;
paulfe69a502005-09-10 16:55:02 +00001937 case as_token_confed_seq_end:
1938 as_type = AS_SEQUENCE;
1939 needtype = 1;
1940 break;
1941 case as_token_confed_set_start:
1942 as_type = AS_CONFED_SET;
1943 aspath_segment_add (aspath, as_type);
1944 needtype = 0;
1945 break;
1946 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001947 as_type = AS_SEQUENCE;
1948 needtype = 1;
1949 break;
1950 case as_token_unknown:
1951 default:
paulfe69a502005-09-10 16:55:02 +00001952 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001953 return NULL;
paul718e3742002-12-13 20:15:29 +00001954 }
1955 }
1956
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001957 aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +00001958
1959 return aspath;
1960}
David Lamparter6b0655a2014-06-04 06:53:35 +02001961
paul718e3742002-12-13 20:15:29 +00001962/* Make hash value by raw aspath data. */
1963unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001964aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001965{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001966 struct aspath *aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001967 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001968
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001969 if (!aspath->str)
1970 aspath_str_update (aspath);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001971
1972 key = jhash (aspath->str, aspath->str_len, 2334325);
paul718e3742002-12-13 20:15:29 +00001973
1974 return key;
1975}
1976
1977/* If two aspath have same value then return 1 else return 0 */
Josh Bailey96450fa2011-07-20 20:45:12 -07001978int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001979aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001980{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001981 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1982 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001983
1984 while (seg1 || seg2)
1985 {
1986 int i;
1987 if ((!seg1 && seg2) || (seg1 && !seg2))
1988 return 0;
1989 if (seg1->type != seg2->type)
1990 return 0;
1991 if (seg1->length != seg2->length)
1992 return 0;
1993 for (i = 0; i < seg1->length; i++)
1994 if (seg1->as[i] != seg2->as[i])
1995 return 0;
1996 seg1 = seg1->next;
1997 seg2 = seg2->next;
1998 }
1999 return 1;
paul718e3742002-12-13 20:15:29 +00002000}
2001
2002/* AS path hash initialize. */
2003void
paul94f2b392005-06-28 12:44:16 +00002004aspath_init (void)
paul718e3742002-12-13 20:15:29 +00002005{
Stephen Hemminger90645f52013-01-04 22:29:21 +00002006 ashash = hash_create_size (32768, aspath_key_make, aspath_cmp);
paul718e3742002-12-13 20:15:29 +00002007}
paul8fdc32a2006-01-16 12:01:29 +00002008
2009void
2010aspath_finish (void)
2011{
Lou Berger056f3762013-04-10 12:30:04 -07002012 hash_clean (ashash, (void (*)(void *))aspath_free);
paul8fdc32a2006-01-16 12:01:29 +00002013 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00002014 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00002015
2016 if (snmp_stream)
2017 stream_free (snmp_stream);
2018}
David Lamparter6b0655a2014-06-04 06:53:35 +02002019
paul718e3742002-12-13 20:15:29 +00002020/* return and as path value */
2021const char *
2022aspath_print (struct aspath *as)
2023{
paulfe69a502005-09-10 16:55:02 +00002024 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00002025}
2026
2027/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00002028/* Feed the AS_PATH to the vty; the suffix string follows it only in case
2029 * AS_PATH wasn't empty.
2030 */
paul718e3742002-12-13 20:15:29 +00002031void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00002032aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00002033{
Paul Jakmab2518c12006-05-12 23:48:40 +00002034 assert (format);
2035 vty_out (vty, format, as->str);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00002036 if (as->str_len && strlen (suffix))
Denis Ovsienko841f7a52008-04-10 11:47:45 +00002037 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00002038}
2039
paul94f2b392005-06-28 12:44:16 +00002040static void
paul718e3742002-12-13 20:15:29 +00002041aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
2042{
2043 struct aspath *as;
2044
2045 as = (struct aspath *) backet->data;
2046
David Lampartereed3c482015-03-03 08:51:53 +01002047 vty_out (vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00002048 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
2049}
2050
2051/* Print all aspath and hash information. This function is used from
2052 `show ip bgp paths' command. */
2053void
2054aspath_print_all_vty (struct vty *vty)
2055{
2056 hash_iterate (ashash,
2057 (void (*) (struct hash_backet *, void *))
2058 aspath_show_all_iterator,
2059 vty);
2060}