blob: 0aec3ef1c60dbabea76067039554f27e27e08123 [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
101/* Get a new segment. Note that 0 is an allowed length,
102 * and will result in a segment with no allocated data segment.
103 * the caller should immediately assign data to the segment, as the segment
104 * otherwise is not generally valid
105 */
106static struct assegment *
107assegment_new (u_char type, u_short length)
108{
109 struct assegment *new;
110
111 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
112
113 if (length)
114 new->as = assegment_data_new (length);
115
116 new->length = length;
117 new->type = type;
118
119 return new;
120}
121
122static void
123assegment_free (struct assegment *seg)
124{
125 if (!seg)
126 return;
127
128 if (seg->as)
129 XFREE (MTYPE_AS_SEG_DATA, seg->as);
130 memset (seg, 0xfe, sizeof(struct assegment));
131 XFREE (MTYPE_AS_SEG, seg);
132
133 return;
134}
135
136/* free entire chain of segments */
137static void
138assegment_free_all (struct assegment *seg)
139{
140 struct assegment *prev;
141
142 while (seg)
143 {
144 prev = seg;
145 seg = seg->next;
146 assegment_free (prev);
147 }
148}
149
150/* Duplicate just the given assegment and its data */
151static struct assegment *
152assegment_dup (struct assegment *seg)
153{
154 struct assegment *new;
155
156 new = assegment_new (seg->type, seg->length);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000157 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );
paulfe69a502005-09-10 16:55:02 +0000158
159 return new;
160}
161
162/* Duplicate entire chain of assegments, return the head */
163static struct assegment *
164assegment_dup_all (struct assegment *seg)
165{
166 struct assegment *new = NULL;
167 struct assegment *head = NULL;
168
169 while (seg)
170 {
171 if (head)
172 {
173 new->next = assegment_dup (seg);
174 new = new->next;
175 }
176 else
177 head = new = assegment_dup (seg);
178
179 seg = seg->next;
180 }
181 return head;
182}
183
184/* prepend the as number to given segment, given num of times */
185static struct assegment *
186assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
187{
188 as_t *newas;
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000189 int i;
paulfe69a502005-09-10 16:55:02 +0000190
191 if (!num)
192 return seg;
193
194 if (num >= AS_SEGMENT_MAX)
195 return seg; /* we don't do huge prepends */
196
197 newas = assegment_data_new (seg->length + num);
paulfe69a502005-09-10 16:55:02 +0000198
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000199 for (i = 0; i < num; i++)
200 newas[i] = asnum;
201
202 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
203 XFREE (MTYPE_AS_SEG_DATA, seg->as);
204 seg->as = newas;
205 seg->length += num;
206
207 return seg;
paulfe69a502005-09-10 16:55:02 +0000208}
209
210/* append given array of as numbers to the segment */
211static struct assegment *
212assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
213{
paul02335422006-01-16 11:13:27 +0000214 as_t *newas;
215
216 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000217 ASSEGMENT_DATA_SIZE (seg->length + num, 1));
paulfe69a502005-09-10 16:55:02 +0000218
paul02335422006-01-16 11:13:27 +0000219 if (newas)
paulfe69a502005-09-10 16:55:02 +0000220 {
paul02335422006-01-16 11:13:27 +0000221 seg->as = newas;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000222 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));
paulfe69a502005-09-10 16:55:02 +0000223 seg->length += num;
224 return seg;
225 }
226
227 assegment_free_all (seg);
228 return NULL;
229}
230
231static int
232int_cmp (const void *p1, const void *p2)
233{
234 const as_t *as1 = p1;
235 const as_t *as2 = p2;
236
237 return (*as1 == *as2)
238 ? 0 : ( (*as1 > *as2) ? 1 : -1);
239}
240
241/* normalise the segment.
242 * In particular, merge runs of AS_SEQUENCEs into one segment
243 * Internally, we do not care about the wire segment length limit, and
244 * we want each distinct AS_PATHs to have the exact same internal
245 * representation - eg, so that our hashing actually works..
246 */
247static struct assegment *
248assegment_normalise (struct assegment *head)
249{
250 struct assegment *seg = head, *pin;
251 struct assegment *tmp;
252
253 if (!head)
254 return head;
255
256 while (seg)
257 {
258 pin = seg;
259
260 /* Sort values SET segments, for determinism in paths to aid
261 * creation of hash values / path comparisons
262 * and because it helps other lesser implementations ;)
263 */
264 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000265 {
266 int tail = 0;
267 int i;
268
269 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
270
271 /* weed out dupes */
272 for (i=1; i < seg->length; i++)
273 {
274 if (seg->as[tail] == seg->as[i])
275 continue;
276
277 tail++;
278 if (tail < i)
279 seg->as[tail] = seg->as[i];
280 }
281 /* seg->length can be 0.. */
282 if (seg->length)
283 seg->length = tail + 1;
284 }
paulfe69a502005-09-10 16:55:02 +0000285
286 /* read ahead from the current, pinned segment while the segments
287 * are packable/mergeable. Append all following packable segments
288 * to the segment we have pinned and remove these appended
289 * segments.
290 */
291 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
292 {
293 tmp = pin->next;
294 seg = pin->next;
295
296 /* append the next sequence to the pinned sequence */
297 pin = assegment_append_asns (pin, seg->as, seg->length);
298
299 /* bypass the next sequence */
300 pin->next = seg->next;
301
302 /* get rid of the now referenceless segment */
303 assegment_free (tmp);
304
305 }
306
307 seg = pin->next;
308 }
309 return head;
310}
David Lamparter6b0655a2014-06-04 06:53:35 +0200311
paul718e3742002-12-13 20:15:29 +0000312static struct aspath *
paulfe69a502005-09-10 16:55:02 +0000313aspath_new (void)
paul718e3742002-12-13 20:15:29 +0000314{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700315 return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000316}
317
318/* Free AS path structure. */
319void
320aspath_free (struct aspath *aspath)
321{
322 if (!aspath)
323 return;
paulfe69a502005-09-10 16:55:02 +0000324 if (aspath->segments)
325 assegment_free_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000326 if (aspath->str)
327 XFREE (MTYPE_AS_STR, aspath->str);
328 XFREE (MTYPE_AS_PATH, aspath);
329}
330
331/* Unintern aspath from AS path bucket. */
332void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000333aspath_unintern (struct aspath **aspath)
paul718e3742002-12-13 20:15:29 +0000334{
335 struct aspath *ret;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000336 struct aspath *asp = *aspath;
337
338 if (asp->refcnt)
339 asp->refcnt--;
paul718e3742002-12-13 20:15:29 +0000340
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000341 if (asp->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000342 {
343 /* This aspath must exist in aspath hash table. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000344 ret = hash_release (ashash, asp);
paul718e3742002-12-13 20:15:29 +0000345 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000346 aspath_free (asp);
347 *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000348 }
349}
350
351/* Return the start or end delimiters for a particular Segment type */
352#define AS_SEG_START 0
353#define AS_SEG_END 1
354static char
355aspath_delimiter_char (u_char type, u_char which)
356{
357 int i;
358 struct
359 {
360 int type;
361 char start;
362 char end;
363 } aspath_delim_char [] =
364 {
365 { AS_SET, '{', '}' },
paul718e3742002-12-13 20:15:29 +0000366 { AS_CONFED_SET, '[', ']' },
367 { AS_CONFED_SEQUENCE, '(', ')' },
368 { 0 }
369 };
370
371 for (i = 0; aspath_delim_char[i].type != 0; i++)
372 {
373 if (aspath_delim_char[i].type == type)
374 {
375 if (which == AS_SEG_START)
376 return aspath_delim_char[i].start;
377 else if (which == AS_SEG_END)
378 return aspath_delim_char[i].end;
379 }
380 }
381 return ' ';
382}
383
Denis Ovsienko014b6702009-06-23 21:10:45 +0400384/* countup asns from this segment and index onward */
385static int
386assegment_count_asns (struct assegment *seg, int from)
387{
388 int count = 0;
389 while (seg)
390 {
391 if (!from)
392 count += seg->length;
393 else
394 {
395 count += (seg->length - from);
396 from = 0;
397 }
398 seg = seg->next;
399 }
400 return count;
401}
402
paulfe69a502005-09-10 16:55:02 +0000403unsigned int
404aspath_count_confeds (struct aspath *aspath)
405{
406 int count = 0;
407 struct assegment *seg = aspath->segments;
408
409 while (seg)
410 {
411 if (seg->type == AS_CONFED_SEQUENCE)
412 count += seg->length;
413 else if (seg->type == AS_CONFED_SET)
414 count++;
415
416 seg = seg->next;
417 }
418 return count;
419}
420
421unsigned int
422aspath_count_hops (struct aspath *aspath)
423{
424 int count = 0;
425 struct assegment *seg = aspath->segments;
426
427 while (seg)
428 {
429 if (seg->type == AS_SEQUENCE)
430 count += seg->length;
431 else if (seg->type == AS_SET)
432 count++;
433
434 seg = seg->next;
435 }
436 return count;
437}
438
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000439/* Estimate size aspath /might/ take if encoded into an
440 * ASPATH attribute.
441 *
442 * This is a quick estimate, not definitive! aspath_put()
443 * may return a different number!!
444 */
paulfe69a502005-09-10 16:55:02 +0000445unsigned int
446aspath_size (struct aspath *aspath)
447{
448 int size = 0;
449 struct assegment *seg = aspath->segments;
450
451 while (seg)
452 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000453 size += ASSEGMENT_SIZE(seg->length, 1);
paulfe69a502005-09-10 16:55:02 +0000454 seg = seg->next;
455 }
456 return size;
457}
458
Paul Jakma2815e612006-09-14 02:56:07 +0000459/* Return highest public ASN in path */
460as_t
461aspath_highest (struct aspath *aspath)
462{
463 struct assegment *seg = aspath->segments;
464 as_t highest = 0;
465 unsigned int i;
466
467 while (seg)
468 {
469 for (i = 0; i < seg->length; i++)
470 if (seg->as[i] > highest
471 && (seg->as[i] < BGP_PRIVATE_AS_MIN
472 || seg->as[i] > BGP_PRIVATE_AS_MAX))
473 highest = seg->as[i];
474 seg = seg->next;
475 }
476 return highest;
477}
478
Timo Teräs85c854a2014-09-30 11:31:53 +0300479/* Return the left-most ASN in path */
480as_t
481aspath_leftmost (struct aspath *aspath)
482{
483 struct assegment *seg = aspath->segments;
484 as_t leftmost = 0;
485
486 if (seg && seg->length && seg->type == AS_SEQUENCE)
487 leftmost = seg->as[0];
488
489 return leftmost;
490}
491
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000492/* Return 1 if there are any 4-byte ASes in the path */
493unsigned int
494aspath_has_as4 (struct aspath *aspath)
495{
496 struct assegment *seg = aspath->segments;
497 unsigned int i;
498
499 while (seg)
500 {
501 for (i = 0; i < seg->length; i++)
502 if (seg->as[i] > BGP_AS_MAX)
503 return 1;
504 seg = seg->next;
505 }
506 return 0;
507}
508
paul718e3742002-12-13 20:15:29 +0000509/* Convert aspath structure to string expression. */
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000510static void
paul718e3742002-12-13 20:15:29 +0000511aspath_make_str_count (struct aspath *as)
512{
paulfe69a502005-09-10 16:55:02 +0000513 struct assegment *seg;
514 int str_size;
515 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000516 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000517
518 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000519 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000520 {
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000521 as->str = XMALLOC (MTYPE_AS_STR, 1);
522 as->str[0] = '\0';
523 as->str_len = 0;
524 return;
paul718e3742002-12-13 20:15:29 +0000525 }
paulfe69a502005-09-10 16:55:02 +0000526
527 seg = as->segments;
528
Denis Ovsienko014b6702009-06-23 21:10:45 +0400529 /* ASN takes 5 to 10 chars plus seperator, see below.
530 * If there is one differing segment type, we need an additional
531 * 2 chars for segment delimiters, and the final '\0'.
532 * Hopefully this is large enough to avoid hitting the realloc
533 * code below for most common sequences.
534 *
535 * This was changed to 10 after the well-known BGP assertion, which
536 * had hit some parts of the Internet in May of 2009.
537 */
538#define ASN_STR_LEN (10 + 1)
539 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
540 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000541 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000542
paulfe69a502005-09-10 16:55:02 +0000543 while (seg)
paul718e3742002-12-13 20:15:29 +0000544 {
545 int i;
paulfe69a502005-09-10 16:55:02 +0000546 char seperator;
paul718e3742002-12-13 20:15:29 +0000547
paulfe69a502005-09-10 16:55:02 +0000548 /* Check AS type validity. Set seperator for segment */
549 switch (seg->type)
550 {
551 case AS_SET:
552 case AS_CONFED_SET:
553 seperator = ',';
554 break;
555 case AS_SEQUENCE:
556 case AS_CONFED_SEQUENCE:
557 seperator = ' ';
558 break;
559 default:
560 XFREE (MTYPE_AS_STR, str_buf);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000561 as->str = NULL;
562 as->str_len = 0;
563 return;
paulfe69a502005-09-10 16:55:02 +0000564 }
565
Denis Ovsienko014b6702009-06-23 21:10:45 +0400566 /* We might need to increase str_buf, particularly if path has
567 * differing segments types, our initial guesstimate above will
568 * have been wrong. Need 10 chars for ASN, a seperator each and
569 * potentially two segment delimiters, plus a space between each
570 * segment and trailing zero.
571 *
572 * This definitely didn't work with the value of 5 bytes and
573 * 32-bit ASNs.
574 */
575#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
576 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
577 {
578 str_size = len + SEGMENT_STR_LEN(seg);
579 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
580 }
581#undef ASN_STR_LEN
582#undef SEGMENT_STR_LEN
583
paulfe69a502005-09-10 16:55:02 +0000584 if (seg->type != AS_SEQUENCE)
Denis Ovsienko014b6702009-06-23 21:10:45 +0400585 len += snprintf (str_buf + len, str_size - len,
586 "%c",
587 aspath_delimiter_char (seg->type, AS_SEG_START));
paulfe69a502005-09-10 16:55:02 +0000588
589 /* write out the ASNs, with their seperators, bar the last one*/
590 for (i = 0; i < seg->length; i++)
591 {
592 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
593
594 if (i < (seg->length - 1))
595 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
596 }
597
598 if (seg->type != AS_SEQUENCE)
599 len += snprintf (str_buf + len, str_size - len, "%c",
600 aspath_delimiter_char (seg->type, AS_SEG_END));
601 if (seg->next)
602 len += snprintf (str_buf + len, str_size - len, " ");
603
604 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000605 }
paulfe69a502005-09-10 16:55:02 +0000606
607 assert (len < str_size);
608
609 str_buf[len] = '\0';
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000610 as->str = str_buf;
611 as->str_len = len;
paul718e3742002-12-13 20:15:29 +0000612
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000613 return;
paul718e3742002-12-13 20:15:29 +0000614}
615
paulfe69a502005-09-10 16:55:02 +0000616static void
617aspath_str_update (struct aspath *as)
618{
619 if (as->str)
620 XFREE (MTYPE_AS_STR, as->str);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000621 aspath_make_str_count (as);
paulfe69a502005-09-10 16:55:02 +0000622}
623
paul718e3742002-12-13 20:15:29 +0000624/* Intern allocated AS path. */
625struct aspath *
626aspath_intern (struct aspath *aspath)
627{
628 struct aspath *find;
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000629
630 /* Assert this AS path structure is not interned and has the string
631 representation built. */
paul718e3742002-12-13 20:15:29 +0000632 assert (aspath->refcnt == 0);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000633 assert (aspath->str);
paul718e3742002-12-13 20:15:29 +0000634
635 /* Check AS path hash. */
636 find = hash_get (ashash, aspath, hash_alloc_intern);
paul718e3742002-12-13 20:15:29 +0000637 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000638 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000639
640 find->refcnt++;
641
paul718e3742002-12-13 20:15:29 +0000642 return find;
643}
644
645/* Duplicate aspath structure. Created same aspath structure but
646 reference count and AS path string is cleared. */
647struct aspath *
648aspath_dup (struct aspath *aspath)
649{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000650 unsigned short buflen = aspath->str_len + 1;
paul718e3742002-12-13 20:15:29 +0000651 struct aspath *new;
652
paulfe69a502005-09-10 16:55:02 +0000653 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000654
paulfe69a502005-09-10 16:55:02 +0000655 if (aspath->segments)
656 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000657
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000658 if (!aspath->str)
659 return new;
660
661 new->str = XMALLOC (MTYPE_AS_STR, buflen);
662 new->str_len = aspath->str_len;
663
664 /* copy the string data */
665 if (aspath->str_len > 0)
666 memcpy (new->str, aspath->str, buflen);
667 else
668 new->str[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000669
670 return new;
671}
672
paul94f2b392005-06-28 12:44:16 +0000673static void *
paulfe69a502005-09-10 16:55:02 +0000674aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000675{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000676 const struct aspath *aspath = arg;
677 struct aspath *new;
678
679 /* Malformed AS path value. */
680 assert (aspath->str);
681 if (! aspath->str)
682 return NULL;
paul718e3742002-12-13 20:15:29 +0000683
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000684 /* New aspath structure is needed. */
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000685 new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000686
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000687 /* Reuse segments and string representation */
688 new->refcnt = 0;
689 new->segments = aspath->segments;
690 new->str = aspath->str;
691 new->str_len = aspath->str_len;
692
693 return new;
paul718e3742002-12-13 20:15:29 +0000694}
695
Paul Jakmaab005292010-11-27 22:48:34 +0000696/* parse as-segment byte stream in struct assegment */
Paul Jakmab881c702010-11-23 16:35:42 +0000697static int
698assegments_parse (struct stream *s, size_t length,
699 struct assegment **result, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000700{
701 struct assegment_header segh;
702 struct assegment *seg, *prev = NULL, *head = NULL;
Paul Jakmaab005292010-11-27 22:48:34 +0000703 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000704
Paul Jakmaab005292010-11-27 22:48:34 +0000705 /* empty aspath (ie iBGP or somesuch) */
706 if (length == 0)
Paul Jakmab881c702010-11-23 16:35:42 +0000707 return 0;
paulfe69a502005-09-10 16:55:02 +0000708
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000709 if (BGP_DEBUG (as4, AS4_SEGMENT))
710 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
711 (unsigned long) length);
Paul Jakmaab005292010-11-27 22:48:34 +0000712 /* basic checks */
713 if ((STREAM_READABLE(s) < length)
714 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
715 || (length % AS16_VALUE_SIZE ))
Paul Jakmab881c702010-11-23 16:35:42 +0000716 return -1;
paulfe69a502005-09-10 16:55:02 +0000717
Paul Jakmaab005292010-11-27 22:48:34 +0000718 while (bytes < length)
paulfe69a502005-09-10 16:55:02 +0000719 {
720 int i;
Chris Hallcddb8112010-08-09 22:31:37 +0400721 size_t seg_size;
paulfe69a502005-09-10 16:55:02 +0000722
Paul Jakmaab005292010-11-27 22:48:34 +0000723 if ((length - bytes) <= AS_HEADER_SIZE)
Chris Hallcddb8112010-08-09 22:31:37 +0400724 {
Paul Jakmaab005292010-11-27 22:48:34 +0000725 if (head)
726 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000727 return -1;
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100728 }
729
Paul Jakmaab005292010-11-27 22:48:34 +0000730 /* softly softly, get the header first on its own */
paulfe69a502005-09-10 16:55:02 +0000731 segh.type = stream_getc (s);
732 segh.length = stream_getc (s);
733
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000734 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
735
736 if (BGP_DEBUG (as4, AS4_SEGMENT))
737 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
738 segh.type, segh.length);
739
Paul Jakmaab005292010-11-27 22:48:34 +0000740 /* check it.. */
741 if ( ((bytes + seg_size) > length)
742 /* 1771bis 4.3b: seg length contains one or more */
743 || (segh.length == 0)
744 /* Paranoia in case someone changes type of segment length.
745 * Shift both values by 0x10 to make the comparison operate
746 * on more, than 8 bits (otherwise it's a warning, bug #564).
Denis Ovsienko2eb445e2009-12-04 17:32:54 +0300747 */
Paul Jakmaab005292010-11-27 22:48:34 +0000748 || ((sizeof segh.length > 1)
749 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
paulfe69a502005-09-10 16:55:02 +0000750 {
Paul Jakmaab005292010-11-27 22:48:34 +0000751 if (head)
paulfe69a502005-09-10 16:55:02 +0000752 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000753 return -1;
paulfe69a502005-09-10 16:55:02 +0000754 }
755
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100756 switch (segh.type)
757 {
758 case AS_SEQUENCE:
759 case AS_SET:
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100760 case AS_CONFED_SEQUENCE:
761 case AS_CONFED_SET:
Paul Jakmaab005292010-11-27 22:48:34 +0000762 break;
763 default:
764 if (head)
765 assegment_free_all (head);
Paul Jakmab881c702010-11-23 16:35:42 +0000766 return -1;
paulfe69a502005-09-10 16:55:02 +0000767 }
Chris Hallcddb8112010-08-09 22:31:37 +0400768
paulfe69a502005-09-10 16:55:02 +0000769 /* now its safe to trust lengths */
770 seg = assegment_new (segh.type, segh.length);
771
772 if (head)
773 prev->next = seg;
774 else /* it's the first segment */
775 head = prev = seg;
776
777 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000778 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
779
Paul Jakmaab005292010-11-27 22:48:34 +0000780 bytes += seg_size;
781
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000782 if (BGP_DEBUG (as4, AS4_SEGMENT))
Paul Jakmaab005292010-11-27 22:48:34 +0000783 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
784 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000785
786 prev = seg;
787 }
788
Paul Jakmab881c702010-11-23 16:35:42 +0000789 *result = assegment_normalise (head);
790 return 0;
paulfe69a502005-09-10 16:55:02 +0000791}
792
Paul Jakmaab005292010-11-27 22:48:34 +0000793/* AS path parse function. pnt is a pointer to byte stream and length
794 is length of byte stream. If there is same AS path in the the AS
Paul Jakmab881c702010-11-23 16:35:42 +0000795 path hash then return it else make new AS path structure.
796
797 On error NULL is returned.
Chris Hallcddb8112010-08-09 22:31:37 +0400798 */
paul718e3742002-12-13 20:15:29 +0000799struct aspath *
Paul Jakmaab005292010-11-27 22:48:34 +0000800aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000801{
802 struct aspath as;
803 struct aspath *find;
804
Paul Jakmaab005292010-11-27 22:48:34 +0000805 /* If length is odd it's malformed AS path. */
806 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
807 * otherwise its malformed when length is larger than 2 and (length-2)
808 * is not dividable by 4.
809 * But... this time we're lazy
810 */
811 if (length % AS16_VALUE_SIZE )
812 return NULL;
Chris Hallcddb8112010-08-09 22:31:37 +0400813
Paul Jakmaab005292010-11-27 22:48:34 +0000814 memset (&as, 0, sizeof (struct aspath));
Paul Jakmab881c702010-11-23 16:35:42 +0000815 if (assegments_parse (s, length, &as.segments, use32bit) < 0)
816 return NULL;
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000817
paul718e3742002-12-13 20:15:29 +0000818 /* If already same aspath exist then return it. */
819 find = hash_get (ashash, &as, aspath_hash_alloc);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +0000820
821 /* bug! should not happen, let the daemon crash below */
822 assert (find);
823
824 /* if the aspath was already hashed free temporary memory. */
825 if (find->refcnt)
826 {
827 assegment_free_all (as.segments);
828 /* aspath_key_make() always updates the string */
829 XFREE (MTYPE_AS_STR, as.str);
830 }
831
paul718e3742002-12-13 20:15:29 +0000832 find->refcnt++;
833
834 return find;
835}
836
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100837static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000838assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000839{
paulfe69a502005-09-10 16:55:02 +0000840 int i;
841 assert (num <= AS_SEGMENT_MAX);
842
843 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000844 if ( use32bit )
845 stream_putl (s, as[i]);
846 else
847 {
848 if ( as[i] <= BGP_AS_MAX )
849 stream_putw(s, as[i]);
850 else
851 stream_putw(s, BGP_AS_TRANS);
852 }
paul718e3742002-12-13 20:15:29 +0000853}
854
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100855static size_t
paulfe69a502005-09-10 16:55:02 +0000856assegment_header_put (struct stream *s, u_char type, int length)
857{
858 size_t lenp;
859 assert (length <= AS_SEGMENT_MAX);
860 stream_putc (s, type);
861 lenp = stream_get_endp (s);
862 stream_putc (s, length);
863 return lenp;
864}
865
866/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000867size_t
868aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000869{
870 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000871 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000872
873 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000874 return 0;
paulfe69a502005-09-10 16:55:02 +0000875
876 if (seg)
877 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000878 /*
879 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
880 * At the moment, we would write out a partial aspath, and our peer
881 * will complain and drop the session :-/
882 *
883 * The general assumption here is that many things tested will
884 * never happen. And, in real live, up to now, they have not.
885 */
886 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000887 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000888 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000889 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000890 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000891 size_t lenp;
892
893 /* Overlength segments have to be split up */
894 while ( (seg->length - written) > AS_SEGMENT_MAX)
895 {
896 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000897 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000898 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000899 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000900 }
901
902 /* write the final segment, probably is also the first */
903 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000904 assegment_data_put (s, (seg->as + written), seg->length - written,
905 use32bit);
paulfe69a502005-09-10 16:55:02 +0000906
907 /* Sequence-type segments can be 'packed' together
908 * Case of a segment which was overlength and split up
909 * will be missed here, but that doesn't matter.
910 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000911 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000912 {
913 /* NB: We should never normally get here given we
914 * normalise aspath data when parse them. However, better
915 * safe than sorry. We potentially could call
916 * assegment_normalise here instead, but it's cheaper and
917 * easier to do it on the fly here rather than go through
918 * the segment list twice every time we write out
919 * aspath's.
920 */
921
922 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000923 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000924
925 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000926 stream_putc_at (s, lenp, seg->length - written + next->length);
927 asns_packed += next->length;
928
929 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000930 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000931
932 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
933 use32bit);
934 seg = next;
paulfe69a502005-09-10 16:55:02 +0000935 }
936 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000937 return bytes;
paulfe69a502005-09-10 16:55:02 +0000938}
939
940/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
941 * We have no way to manage the storage, so we use a static stream
942 * wrapper around aspath_put.
943 */
944u_char *
945aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
946{
947#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000948
949 if (!snmp_stream)
950 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000951 else
paul8fdc32a2006-01-16 12:01:29 +0000952 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000953
954 if (!as)
955 {
956 *varlen = 0;
957 return NULL;
958 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000959 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000960
paul8fdc32a2006-01-16 12:01:29 +0000961 *varlen = stream_get_endp (snmp_stream);
962 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000963}
964
965#define min(A,B) ((A) < (B) ? (A) : (B))
966
paul94f2b392005-06-28 12:44:16 +0000967static struct assegment *
paul718e3742002-12-13 20:15:29 +0000968aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
969 as_t as)
970{
971 int i;
972
973 /* If this is first AS set member, create new as-set segment. */
974 if (asset == NULL)
975 {
paulfe69a502005-09-10 16:55:02 +0000976 asset = assegment_new (AS_SET, 1);
977 if (! aspath->segments)
978 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000979 else
paulfe69a502005-09-10 16:55:02 +0000980 {
981 struct assegment *seg = aspath->segments;
982 while (seg->next)
983 seg = seg->next;
984 seg->next = asset;
985 }
paul718e3742002-12-13 20:15:29 +0000986 asset->type = AS_SET;
987 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000988 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000989 }
990 else
991 {
paul718e3742002-12-13 20:15:29 +0000992 /* Check this AS value already exists or not. */
993 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000994 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000995 return asset;
paulfe69a502005-09-10 16:55:02 +0000996
paul718e3742002-12-13 20:15:29 +0000997 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000998 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
999 asset->length * AS_VALUE_SIZE);
1000 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +00001001 }
paulfe69a502005-09-10 16:55:02 +00001002
paul718e3742002-12-13 20:15:29 +00001003
1004 return asset;
1005}
1006
1007/* Modify as1 using as2 for aggregation. */
1008struct aspath *
1009aspath_aggregate (struct aspath *as1, struct aspath *as2)
1010{
1011 int i;
1012 int minlen;
1013 int match;
paulfe69a502005-09-10 16:55:02 +00001014 int from;
1015 struct assegment *seg1 = as1->segments;
1016 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001017 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +00001018 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001019 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +00001020
1021 match = 0;
1022 minlen = 0;
1023 aspath = NULL;
1024 asset = NULL;
paul718e3742002-12-13 20:15:29 +00001025
1026 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +00001027 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001028 {
paul718e3742002-12-13 20:15:29 +00001029 /* Check segment type. */
1030 if (seg1->type != seg2->type)
1031 break;
1032
1033 /* Minimum segment length. */
1034 minlen = min (seg1->length, seg2->length);
1035
1036 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001037 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001038 break;
1039
1040 if (match)
1041 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001042 struct assegment *seg = assegment_new (seg1->type, 0);
1043
1044 seg = assegment_append_asns (seg, seg1->as, match);
1045
paul718e3742002-12-13 20:15:29 +00001046 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001047 {
1048 aspath = aspath_new ();
1049 aspath->segments = seg;
1050 }
1051 else
1052 prevseg->next = seg;
1053
1054 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001055 }
1056
1057 if (match != minlen || match != seg1->length
1058 || seg1->length != seg2->length)
1059 break;
paulfe69a502005-09-10 16:55:02 +00001060
1061 seg1 = seg1->next;
1062 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001063 }
1064
1065 if (! aspath)
1066 aspath = aspath_new();
1067
1068 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001069 from = match;
1070 while (seg1)
paul718e3742002-12-13 20:15:29 +00001071 {
paulfe69a502005-09-10 16:55:02 +00001072 for (i = from; i < seg1->length; i++)
1073 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1074
1075 from = 0;
1076 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001077 }
1078
paulfe69a502005-09-10 16:55:02 +00001079 from = match;
1080 while (seg2)
paul718e3742002-12-13 20:15:29 +00001081 {
paulfe69a502005-09-10 16:55:02 +00001082 for (i = from; i < seg2->length; i++)
1083 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001084
paulfe69a502005-09-10 16:55:02 +00001085 from = 0;
1086 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001087 }
paulfe69a502005-09-10 16:55:02 +00001088
1089 assegment_normalise (aspath->segments);
1090 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001091 return aspath;
1092}
1093
1094/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1095 attribute, check the leftmost AS number in the AS_PATH attribute is
1096 or not the peer's AS number. */
1097int
1098aspath_firstas_check (struct aspath *aspath, as_t asno)
1099{
paulfe69a502005-09-10 16:55:02 +00001100 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001101 return 0;
paulfe69a502005-09-10 16:55:02 +00001102
1103 if (aspath->segments
1104 && (aspath->segments->type == AS_SEQUENCE)
1105 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001106 return 1;
1107
1108 return 0;
1109}
1110
Paul Jakma1f742f22006-08-06 15:52:11 +00001111/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001112int
1113aspath_loop_check (struct aspath *aspath, as_t asno)
1114{
paulfe69a502005-09-10 16:55:02 +00001115 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001116 int count = 0;
1117
Paul Jakma1f742f22006-08-06 15:52:11 +00001118 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001119 return 0;
paulfe69a502005-09-10 16:55:02 +00001120
1121 seg = aspath->segments;
1122
1123 while (seg)
paul718e3742002-12-13 20:15:29 +00001124 {
1125 int i;
paul718e3742002-12-13 20:15:29 +00001126
paulfe69a502005-09-10 16:55:02 +00001127 for (i = 0; i < seg->length; i++)
1128 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001129 count++;
paulfe69a502005-09-10 16:55:02 +00001130
1131 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001132 }
1133 return count;
1134}
1135
1136/* When all of AS path is private AS return 1. */
1137int
1138aspath_private_as_check (struct aspath *aspath)
1139{
paulfe69a502005-09-10 16:55:02 +00001140 struct assegment *seg;
1141
1142 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001143 return 0;
paulfe69a502005-09-10 16:55:02 +00001144
1145 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001146
paulfe69a502005-09-10 16:55:02 +00001147 while (seg)
paul718e3742002-12-13 20:15:29 +00001148 {
1149 int i;
paul718e3742002-12-13 20:15:29 +00001150
paulfe69a502005-09-10 16:55:02 +00001151 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001152 {
paulfe69a502005-09-10 16:55:02 +00001153 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1154 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001155 return 0;
1156 }
paulfe69a502005-09-10 16:55:02 +00001157 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001158 }
1159 return 1;
1160}
1161
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001162/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1163int
1164aspath_confed_check (struct aspath *aspath)
1165{
1166 struct assegment *seg;
1167
1168 if ( !(aspath && aspath->segments) )
1169 return 0;
1170
1171 seg = aspath->segments;
1172
1173 while (seg)
1174 {
1175 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1176 return 1;
1177 seg = seg->next;
1178 }
1179 return 0;
1180}
1181
1182/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1183 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1184int
1185aspath_left_confed_check (struct aspath *aspath)
1186{
1187
1188 if ( !(aspath && aspath->segments) )
1189 return 0;
1190
1191 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1192 || (aspath->segments->type == AS_CONFED_SET) )
1193 return 1;
1194
1195 return 0;
1196}
1197
paul718e3742002-12-13 20:15:29 +00001198/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001199static struct aspath *
paul718e3742002-12-13 20:15:29 +00001200aspath_merge (struct aspath *as1, struct aspath *as2)
1201{
paulfe69a502005-09-10 16:55:02 +00001202 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001203
1204 if (! as1 || ! as2)
1205 return NULL;
1206
paulfe69a502005-09-10 16:55:02 +00001207 last = new = assegment_dup_all (as1->segments);
1208
1209 /* find the last valid segment */
1210 while (last && last->next)
1211 last = last->next;
1212
1213 last->next = as2->segments;
1214 as2->segments = new;
1215 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001216 return as2;
1217}
1218
1219/* Prepend as1 to as2. as2 should be uninterned aspath. */
1220struct aspath *
1221aspath_prepend (struct aspath *as1, struct aspath *as2)
1222{
paulfe69a502005-09-10 16:55:02 +00001223 struct assegment *seg1;
1224 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001225
1226 if (! as1 || ! as2)
1227 return NULL;
paulfe69a502005-09-10 16:55:02 +00001228
1229 seg1 = as1->segments;
1230 seg2 = as2->segments;
1231
1232 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001233 if (seg2 == NULL)
1234 {
paulfe69a502005-09-10 16:55:02 +00001235 as2->segments = assegment_dup_all (as1->segments);
1236 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001237 return as2;
1238 }
paulfe69a502005-09-10 16:55:02 +00001239
1240 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001241 if (seg1 == NULL)
1242 return as2;
paulfe69a502005-09-10 16:55:02 +00001243
1244 /* find the tail as1's segment chain. */
1245 while (seg1 && seg1->next)
1246 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001247
Vasilis Tsiligiannis736d4402009-07-20 01:59:10 +03001248 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1249 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1250 as2 = aspath_delete_confed_seq (as2);
1251
paul718e3742002-12-13 20:15:29 +00001252 /* Compare last segment type of as1 and first segment type of as2. */
1253 if (seg1->type != seg2->type)
1254 return aspath_merge (as1, as2);
1255
1256 if (seg1->type == AS_SEQUENCE)
1257 {
paulfe69a502005-09-10 16:55:02 +00001258 /* We have two chains of segments, as1->segments and seg2,
1259 * and we have to attach them together, merging the attaching
1260 * segments together into one.
1261 *
1262 * 1. dupe as1->segments onto head of as2
1263 * 2. merge seg2's asns onto last segment of this new chain
1264 * 3. attach chain after seg2
1265 */
paul718e3742002-12-13 20:15:29 +00001266
paulfe69a502005-09-10 16:55:02 +00001267 /* dupe as1 onto as2's head */
1268 seg1 = as2->segments = assegment_dup_all (as1->segments);
1269
1270 /* refind the tail of as2, reusing seg1 */
1271 while (seg1 && seg1->next)
1272 seg1 = seg1->next;
1273
1274 /* merge the old head, seg2, into tail, seg1 */
1275 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1276
1277 /* bypass the merged seg2, and attach any chain after it to
1278 * chain descending from as2's head
1279 */
1280 seg1->next = seg2->next;
1281
1282 /* seg2 is now referenceless and useless*/
1283 assegment_free (seg2);
1284
1285 /* we've now prepended as1's segment chain to as2, merging
1286 * the inbetween AS_SEQUENCE of seg2 in the process
1287 */
1288 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001289 return as2;
1290 }
1291 else
1292 {
1293 /* AS_SET merge code is needed at here. */
1294 return aspath_merge (as1, as2);
1295 }
paulfe69a502005-09-10 16:55:02 +00001296 /* XXX: Ermmm, what if as1 has multiple segments?? */
1297
paul718e3742002-12-13 20:15:29 +00001298 /* Not reached */
1299}
1300
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001301/* Iterate over AS_PATH segments and wipe all occurences of the
1302 * listed AS numbers. Hence some segments may lose some or even
1303 * all data on the way, the operation is implemented as a smarter
1304 * version of aspath_dup(), which allocates memory to hold the new
1305 * data, not the original. The new AS path is returned.
1306 */
1307struct aspath *
1308aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1309{
1310 struct assegment * srcseg, * exclseg, * lastseg;
1311 struct aspath * newpath;
1312
1313 newpath = aspath_new();
1314 lastseg = NULL;
1315
1316 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1317 {
1318 unsigned i, y, newlen = 0, done = 0, skip_as;
1319 struct assegment * newseg;
1320
1321 /* Find out, how much ASns are we going to pick from this segment.
1322 * We can't perform filtering right inline, because the size of
1323 * the new segment isn't known at the moment yet.
1324 */
1325 for (i = 0; i < srcseg->length; i++)
1326 {
1327 skip_as = 0;
1328 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1329 for (y = 0; y < exclseg->length; y++)
1330 if (srcseg->as[i] == exclseg->as[y])
1331 {
1332 skip_as = 1;
1333 // There's no sense in testing the rest of exclusion list, bail out.
1334 break;
1335 }
1336 if (!skip_as)
1337 newlen++;
1338 }
1339 /* newlen is now the number of ASns to copy */
1340 if (!newlen)
1341 continue;
1342
1343 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1344 newseg = assegment_new (srcseg->type, newlen);
1345 for (i = 0; i < srcseg->length; i++)
1346 {
1347 skip_as = 0;
1348 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1349 for (y = 0; y < exclseg->length; y++)
1350 if (srcseg->as[i] == exclseg->as[y])
1351 {
1352 skip_as = 1;
1353 break;
1354 }
1355 if (skip_as)
1356 continue;
1357 newseg->as[done++] = srcseg->as[i];
1358 }
1359 /* At his point newlen must be equal to done, and both must be positive. Append
1360 * the filtered segment to the gross result. */
1361 if (!lastseg)
1362 newpath->segments = newseg;
1363 else
1364 lastseg->next = newseg;
1365 lastseg = newseg;
1366 }
1367 aspath_str_update (newpath);
1368 /* We are happy returning even an empty AS_PATH, because the administrator
1369 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1370 * by having a match rule against certain AS_PATH regexps in the route-map index.
1371 */
1372 aspath_free (source);
1373 return newpath;
1374}
1375
paul718e3742002-12-13 20:15:29 +00001376/* Add specified AS to the leftmost of aspath. */
1377static struct aspath *
Timo Teräs85c854a2014-09-30 11:31:53 +03001378aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num)
paul718e3742002-12-13 20:15:29 +00001379{
paulfe69a502005-09-10 16:55:02 +00001380 struct assegment *assegment = aspath->segments;
David Lamparter21401f32015-03-03 08:55:26 +01001381 unsigned i;
paul718e3742002-12-13 20:15:29 +00001382
Timo Teräs85c854a2014-09-30 11:31:53 +03001383 if (assegment && assegment->type == type)
paul718e3742002-12-13 20:15:29 +00001384 {
Timo Teräs85c854a2014-09-30 11:31:53 +03001385 /* extend existing segment */
1386 aspath->segments = assegment_prepend_asns (aspath->segments, asno, num);
paul718e3742002-12-13 20:15:29 +00001387 }
paulfe69a502005-09-10 16:55:02 +00001388 else
paul718e3742002-12-13 20:15:29 +00001389 {
Timo Teräs85c854a2014-09-30 11:31:53 +03001390 /* prepend with new segment */
1391 struct assegment *newsegment = assegment_new (type, num);
1392 for (i = 0; i < num; i++)
1393 newsegment->as[i] = asno;
1394
1395 /* insert potentially replacing empty segment */
1396 if (assegment && assegment->length == 0)
1397 {
1398 newsegment->next = assegment->next;
1399 assegment_free (assegment);
1400 }
1401 else
1402 newsegment->next = assegment;
paulfe69a502005-09-10 16:55:02 +00001403 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001404 }
1405
Timo Teräs85c854a2014-09-30 11:31:53 +03001406 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001407 return aspath;
1408}
1409
Timo Teräs85c854a2014-09-30 11:31:53 +03001410/* Add specified AS to the leftmost of aspath num times. */
1411struct aspath *
1412aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num)
1413{
1414 return aspath_add_asns (aspath, asno, AS_SEQUENCE, num);
1415}
1416
paul718e3742002-12-13 20:15:29 +00001417/* Add specified AS to the leftmost of aspath. */
1418struct aspath *
1419aspath_add_seq (struct aspath *aspath, as_t asno)
1420{
Timo Teräs85c854a2014-09-30 11:31:53 +03001421 return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1);
paul718e3742002-12-13 20:15:29 +00001422}
1423
1424/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1425 as2's leftmost AS is same return 1. */
1426int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001427aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001428{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001429 const struct assegment *seg1;
1430 const struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001431
paulfe69a502005-09-10 16:55:02 +00001432 if (!(aspath1 && aspath2))
1433 return 0;
paul718e3742002-12-13 20:15:29 +00001434
paulfe69a502005-09-10 16:55:02 +00001435 seg1 = aspath1->segments;
1436 seg2 = aspath2->segments;
1437
1438 /* find first non-confed segments for each */
1439 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1440 || (seg1->type == AS_CONFED_SET)))
1441 seg1 = seg1->next;
1442
1443 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1444 || (seg2->type == AS_CONFED_SET)))
1445 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001446
1447 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001448 if (!(seg1 && seg2
1449 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001450 return 0;
paulfe69a502005-09-10 16:55:02 +00001451
1452 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001453 return 1;
1454
1455 return 0;
1456}
1457
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001458/* Truncate an aspath after a number of hops, and put the hops remaining
1459 * at the front of another aspath. Needed for AS4 compat.
1460 *
1461 * Returned aspath is a /new/ aspath, which should either by free'd or
1462 * interned by the caller, as desired.
1463 */
1464struct aspath *
1465aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1466{
1467 struct assegment *seg, *newseg, *prevseg = NULL;
1468 struct aspath *newpath = NULL, *mergedpath;
1469 int hops, cpasns = 0;
1470
1471 if (!aspath)
1472 return NULL;
1473
1474 seg = aspath->segments;
1475
1476 /* CONFEDs should get reconciled too.. */
1477 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1478 - aspath_count_hops (as4path);
1479
1480 if (hops < 0)
1481 {
1482 if (BGP_DEBUG (as4, AS4))
1483 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1484 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1485 * which is daft behaviour - it contains vital loop-detection
1486 * information which must have been removed from AS_PATH.
1487 */
1488 hops = aspath_count_hops (aspath);
1489 }
1490
1491 if (!hops)
1492 return aspath_dup (as4path);
1493
1494 if ( BGP_DEBUG(as4, AS4))
1495 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1496 aspath->str, as4path->str);
1497
1498 while (seg && hops > 0)
1499 {
1500 switch (seg->type)
1501 {
1502 case AS_SET:
1503 case AS_CONFED_SET:
1504 hops--;
1505 cpasns = seg->length;
1506 break;
1507 case AS_CONFED_SEQUENCE:
1508 /* Should never split a confed-sequence, if hop-count
1509 * suggests we must then something's gone wrong somewhere.
1510 *
1511 * Most important goal is to preserve AS_PATHs prime function
1512 * as loop-detector, so we fudge the numbers so that the entire
1513 * confed-sequence is merged in.
1514 */
1515 if (hops < seg->length)
1516 {
1517 if (BGP_DEBUG (as4, AS4))
1518 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1519 " across 2/4 ASN boundary somewhere, broken..");
1520 hops = seg->length;
1521 }
1522 case AS_SEQUENCE:
1523 cpasns = MIN(seg->length, hops);
1524 hops -= seg->length;
1525 }
1526
1527 assert (cpasns <= seg->length);
1528
1529 newseg = assegment_new (seg->type, 0);
1530 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1531
1532 if (!newpath)
1533 {
1534 newpath = aspath_new ();
1535 newpath->segments = newseg;
1536 }
1537 else
1538 prevseg->next = newseg;
1539
1540 prevseg = newseg;
1541 seg = seg->next;
1542 }
1543
1544 /* We may be able to join some segments here, and we must
1545 * do this because... we want normalised aspaths in out hash
1546 * and we do not want to stumble in aspath_put.
1547 */
1548 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1549 aspath_free (newpath);
1550 mergedpath->segments = assegment_normalise (mergedpath->segments);
1551 aspath_str_update (mergedpath);
1552
1553 if ( BGP_DEBUG(as4, AS4))
1554 zlog_debug ("[AS4] result of synthesizing is %s",
1555 mergedpath->str);
1556
1557 return mergedpath;
1558}
1559
paul718e3742002-12-13 20:15:29 +00001560/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1561 as2's leftmost AS is same return 1. (confederation as-path
1562 only). */
1563int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001564aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001565{
paulfe69a502005-09-10 16:55:02 +00001566 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001567 return 0;
paulfe69a502005-09-10 16:55:02 +00001568
paulad727402005-11-23 02:47:02 +00001569 if ( !(aspath1->segments && aspath2->segments) )
1570 return 0;
1571
paulfe69a502005-09-10 16:55:02 +00001572 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1573 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001574 return 0;
paulfe69a502005-09-10 16:55:02 +00001575
1576 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001577 return 1;
1578
1579 return 0;
1580}
1581
paulfe69a502005-09-10 16:55:02 +00001582/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1583 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001584struct aspath *
1585aspath_delete_confed_seq (struct aspath *aspath)
1586{
paulfe69a502005-09-10 16:55:02 +00001587 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001588
paulfe69a502005-09-10 16:55:02 +00001589 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001590 return aspath;
1591
paulfe69a502005-09-10 16:55:02 +00001592 seg = aspath->segments;
1593
1594 /* "if the first path segment of the AS_PATH is
1595 * of type AS_CONFED_SEQUENCE,"
1596 */
1597 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1598 return aspath;
paul718e3742002-12-13 20:15:29 +00001599
paulfe69a502005-09-10 16:55:02 +00001600 /* "... that segment and any immediately following segments
1601 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1602 * from the AS_PATH attribute,"
1603 */
1604 while (seg &&
1605 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001606 {
paulfe69a502005-09-10 16:55:02 +00001607 aspath->segments = seg->next;
1608 assegment_free (seg);
1609 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001610 }
paulfe69a502005-09-10 16:55:02 +00001611 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001612 return aspath;
1613}
1614
1615/* Add new AS number to the leftmost part of the aspath as
1616 AS_CONFED_SEQUENCE. */
1617struct aspath*
1618aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1619{
Timo Teräs85c854a2014-09-30 11:31:53 +03001620 return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1);
paul718e3742002-12-13 20:15:29 +00001621}
1622
1623/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001624static void
paul718e3742002-12-13 20:15:29 +00001625aspath_as_add (struct aspath *as, as_t asno)
1626{
paulfe69a502005-09-10 16:55:02 +00001627 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001628
paulfe69a502005-09-10 16:55:02 +00001629 if (!seg)
1630 return;
1631
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001632 /* Last segment search procedure. */
1633 while (seg->next)
1634 seg = seg->next;
1635
paulfe69a502005-09-10 16:55:02 +00001636 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001637}
1638
1639/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001640static void
paul718e3742002-12-13 20:15:29 +00001641aspath_segment_add (struct aspath *as, int type)
1642{
paulfe69a502005-09-10 16:55:02 +00001643 struct assegment *seg = as->segments;
1644 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001645
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001646 if (seg)
1647 {
1648 while (seg->next)
1649 seg = seg->next;
1650 seg->next = new;
1651 }
paul718e3742002-12-13 20:15:29 +00001652 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001653 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001654}
1655
1656struct aspath *
paul94f2b392005-06-28 12:44:16 +00001657aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001658{
Paul Jakmaab005292010-11-27 22:48:34 +00001659 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001660}
1661
1662struct aspath *
paul94f2b392005-06-28 12:44:16 +00001663aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001664{
1665 struct aspath *aspath;
1666
1667 aspath = aspath_new ();
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001668 aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +00001669 return aspath;
1670}
1671
1672unsigned long
paulfe69a502005-09-10 16:55:02 +00001673aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001674{
1675 return ashash->count;
1676}
David Lamparter6b0655a2014-06-04 06:53:35 +02001677
paul718e3742002-12-13 20:15:29 +00001678/*
1679 Theoretically, one as path can have:
1680
1681 One BGP packet size should be less than 4096.
1682 One BGP attribute size should be less than 4096 - BGP header size.
1683 One BGP aspath size should be less than 4096 - BGP header size -
1684 BGP mandantry attribute size.
1685*/
1686
1687/* AS path string lexical token enum. */
1688enum as_token
1689{
1690 as_token_asval,
1691 as_token_set_start,
1692 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001693 as_token_confed_seq_start,
1694 as_token_confed_seq_end,
1695 as_token_confed_set_start,
1696 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001697 as_token_unknown
1698};
1699
1700/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001701static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001702aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001703{
paulfd79ac92004-10-13 05:06:08 +00001704 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001705
paulfe69a502005-09-10 16:55:02 +00001706 /* Skip seperators (space for sequences, ',' for sets). */
1707 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001708 p++;
1709
1710 /* Check the end of the string and type specify characters
1711 (e.g. {}()). */
1712 switch (*p)
1713 {
1714 case '\0':
1715 return NULL;
paul718e3742002-12-13 20:15:29 +00001716 case '{':
1717 *token = as_token_set_start;
1718 p++;
1719 return p;
paul718e3742002-12-13 20:15:29 +00001720 case '}':
1721 *token = as_token_set_end;
1722 p++;
1723 return p;
paul718e3742002-12-13 20:15:29 +00001724 case '(':
paulfe69a502005-09-10 16:55:02 +00001725 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001726 p++;
1727 return p;
paul718e3742002-12-13 20:15:29 +00001728 case ')':
paulfe69a502005-09-10 16:55:02 +00001729 *token = as_token_confed_seq_end;
1730 p++;
1731 return p;
paulfe69a502005-09-10 16:55:02 +00001732 case '[':
1733 *token = as_token_confed_set_start;
1734 p++;
1735 return p;
paulfe69a502005-09-10 16:55:02 +00001736 case ']':
1737 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001738 p++;
1739 return p;
paul718e3742002-12-13 20:15:29 +00001740 }
1741
1742 /* Check actual AS value. */
1743 if (isdigit ((int) *p))
1744 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001745 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001746
paul718e3742002-12-13 20:15:29 +00001747 *token = as_token_asval;
1748 asval = (*p - '0');
1749 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001750
paul718e3742002-12-13 20:15:29 +00001751 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001752 {
1753 asval *= 10;
1754 asval += (*p - '0');
1755 p++;
1756 }
paul718e3742002-12-13 20:15:29 +00001757 *asno = asval;
1758 return p;
1759 }
1760
1761 /* There is no match then return unknown token. */
1762 *token = as_token_unknown;
1763 return p++;
1764}
1765
1766struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001767aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001768{
paul3fff6ff2006-02-05 17:55:35 +00001769 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001770 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001771 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001772 struct aspath *aspath;
1773 int needtype;
1774
1775 aspath = aspath_new ();
1776
1777 /* We start default type as AS_SEQUENCE. */
1778 as_type = AS_SEQUENCE;
1779 needtype = 1;
1780
1781 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1782 {
1783 switch (token)
1784 {
1785 case as_token_asval:
1786 if (needtype)
1787 {
1788 aspath_segment_add (aspath, as_type);
1789 needtype = 0;
1790 }
1791 aspath_as_add (aspath, asno);
1792 break;
1793 case as_token_set_start:
1794 as_type = AS_SET;
1795 aspath_segment_add (aspath, as_type);
1796 needtype = 0;
1797 break;
1798 case as_token_set_end:
1799 as_type = AS_SEQUENCE;
1800 needtype = 1;
1801 break;
paulfe69a502005-09-10 16:55:02 +00001802 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001803 as_type = AS_CONFED_SEQUENCE;
1804 aspath_segment_add (aspath, as_type);
1805 needtype = 0;
1806 break;
paulfe69a502005-09-10 16:55:02 +00001807 case as_token_confed_seq_end:
1808 as_type = AS_SEQUENCE;
1809 needtype = 1;
1810 break;
1811 case as_token_confed_set_start:
1812 as_type = AS_CONFED_SET;
1813 aspath_segment_add (aspath, as_type);
1814 needtype = 0;
1815 break;
1816 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001817 as_type = AS_SEQUENCE;
1818 needtype = 1;
1819 break;
1820 case as_token_unknown:
1821 default:
paulfe69a502005-09-10 16:55:02 +00001822 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001823 return NULL;
paul718e3742002-12-13 20:15:29 +00001824 }
1825 }
1826
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001827 aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +00001828
1829 return aspath;
1830}
David Lamparter6b0655a2014-06-04 06:53:35 +02001831
paul718e3742002-12-13 20:15:29 +00001832/* Make hash value by raw aspath data. */
1833unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001834aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001835{
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001836 struct aspath *aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001837 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001838
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001839 if (!aspath->str)
1840 aspath_str_update (aspath);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001841
1842 key = jhash (aspath->str, aspath->str_len, 2334325);
paul718e3742002-12-13 20:15:29 +00001843
1844 return key;
1845}
1846
1847/* If two aspath have same value then return 1 else return 0 */
Josh Bailey96450fa2011-07-20 20:45:12 -07001848int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001849aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001850{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001851 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1852 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001853
1854 while (seg1 || seg2)
1855 {
1856 int i;
1857 if ((!seg1 && seg2) || (seg1 && !seg2))
1858 return 0;
1859 if (seg1->type != seg2->type)
1860 return 0;
1861 if (seg1->length != seg2->length)
1862 return 0;
1863 for (i = 0; i < seg1->length; i++)
1864 if (seg1->as[i] != seg2->as[i])
1865 return 0;
1866 seg1 = seg1->next;
1867 seg2 = seg2->next;
1868 }
1869 return 1;
paul718e3742002-12-13 20:15:29 +00001870}
1871
1872/* AS path hash initialize. */
1873void
paul94f2b392005-06-28 12:44:16 +00001874aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001875{
Stephen Hemminger90645f52013-01-04 22:29:21 +00001876 ashash = hash_create_size (32768, aspath_key_make, aspath_cmp);
paul718e3742002-12-13 20:15:29 +00001877}
paul8fdc32a2006-01-16 12:01:29 +00001878
1879void
1880aspath_finish (void)
1881{
1882 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00001883 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00001884
1885 if (snmp_stream)
1886 stream_free (snmp_stream);
1887}
David Lamparter6b0655a2014-06-04 06:53:35 +02001888
paul718e3742002-12-13 20:15:29 +00001889/* return and as path value */
1890const char *
1891aspath_print (struct aspath *as)
1892{
paulfe69a502005-09-10 16:55:02 +00001893 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001894}
1895
1896/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001897/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1898 * AS_PATH wasn't empty.
1899 */
paul718e3742002-12-13 20:15:29 +00001900void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001901aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001902{
Paul Jakmab2518c12006-05-12 23:48:40 +00001903 assert (format);
1904 vty_out (vty, format, as->str);
Jorge Boncompte [DTI2]f669f7d2012-05-07 16:52:51 +00001905 if (as->str_len && strlen (suffix))
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001906 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001907}
1908
paul94f2b392005-06-28 12:44:16 +00001909static void
paul718e3742002-12-13 20:15:29 +00001910aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1911{
1912 struct aspath *as;
1913
1914 as = (struct aspath *) backet->data;
1915
David Lampartereed3c482015-03-03 08:51:53 +01001916 vty_out (vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001917 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1918}
1919
1920/* Print all aspath and hash information. This function is used from
1921 `show ip bgp paths' command. */
1922void
1923aspath_print_all_vty (struct vty *vty)
1924{
1925 hash_iterate (ashash,
1926 (void (*) (struct hash_backet *, void *))
1927 aspath_show_all_iterator,
1928 vty);
1929}