blob: cf930427094ac06a2fe893267a44575e5c7ee93e [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* AS path management routines.
2 Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
paulfe69a502005-09-10 16:55:02 +00003 Copyright (C) 2005 Sun Microsystems, Inc.
paul718e3742002-12-13 20:15:29 +00004
5This file is part of GNU Zebra.
6
7GNU Zebra is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by the
9Free Software Foundation; either version 2, or (at your option) any
10later version.
11
12GNU Zebra is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Zebra; see the file COPYING. If not, write to the Free
19Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA. */
21
22#include <zebra.h>
23
24#include "hash.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "str.h"
29#include "log.h"
paulfe69a502005-09-10 16:55:02 +000030#include "stream.h"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000031#include "jhash.h"
paul718e3742002-12-13 20:15:29 +000032
33#include "bgpd/bgpd.h"
34#include "bgpd/bgp_aspath.h"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000035#include "bgpd/bgp_debug.h"
36#include "bgpd/bgp_attr.h"
paul718e3742002-12-13 20:15:29 +000037
38/* Attr. Flags and Attr. Type Code. */
39#define AS_HEADER_SIZE 2
40
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000041/* Now FOUR octets are used for AS value. */
paul718e3742002-12-13 20:15:29 +000042#define AS_VALUE_SIZE sizeof (as_t)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000043/* This is the old one */
44#define AS16_VALUE_SIZE sizeof (as16_t)
paul718e3742002-12-13 20:15:29 +000045
paulfe69a502005-09-10 16:55:02 +000046/* Maximum protocol segment length value */
47#define AS_SEGMENT_MAX 255
paul718e3742002-12-13 20:15:29 +000048
paulfe69a502005-09-10 16:55:02 +000049/* The following length and size macros relate specifically to Quagga's
50 * internal representation of AS-Segments, not per se to the on-wire
51 * sizes and lengths. At present (200508) they sort of match, however
52 * the ONLY functions which should now about the on-wire syntax are
53 * aspath_put, assegment_put and assegment_parse.
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000054 *
55 * aspath_put returns bytes written, the only definitive record of
56 * size of wire-format attribute..
paulfe69a502005-09-10 16:55:02 +000057 */
58
59/* Calculated size in bytes of ASN segment data to hold N ASN's */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000060#define ASSEGMENT_DATA_SIZE(N,S) \
61 ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )
paulfe69a502005-09-10 16:55:02 +000062
63/* Calculated size of segment struct to hold N ASN's */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000064#define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
paulfe69a502005-09-10 16:55:02 +000065
66/* AS segment octet length. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000067#define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
paulfe69a502005-09-10 16:55:02 +000068
69/* AS_SEQUENCE segments can be packed together */
70/* Can the types of X and Y be considered for packing? */
71#define ASSEGMENT_TYPES_PACKABLE(X,Y) \
72 ( ((X)->type == (Y)->type) \
73 && ((X)->type == AS_SEQUENCE))
74/* Types and length of X,Y suitable for packing? */
75#define ASSEGMENTS_PACKABLE(X,Y) \
76 ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \
77 && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) )
78
79/* As segment header - the on-wire representation
80 * NOT the internal representation!
81 */
82struct assegment_header
paul718e3742002-12-13 20:15:29 +000083{
84 u_char type;
85 u_char length;
paul718e3742002-12-13 20:15:29 +000086};
87
88/* Hash for aspath. This is the top level structure of AS path. */
Stephen Hemmingerda88ea82009-12-17 13:14:28 +030089static struct hash *ashash;
paul8fdc32a2006-01-16 12:01:29 +000090
91/* Stream for SNMP. See aspath_snmp_pathseg */
92static struct stream *snmp_stream;
paul718e3742002-12-13 20:15:29 +000093
paulfe69a502005-09-10 16:55:02 +000094static inline as_t *
95assegment_data_new (int num)
96{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000097 return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
paulfe69a502005-09-10 16:55:02 +000098}
99
100static inline void
101assegment_data_free (as_t *asdata)
102{
103 XFREE (MTYPE_AS_SEG_DATA,asdata);
104}
105
106/* Get a new segment. Note that 0 is an allowed length,
107 * and will result in a segment with no allocated data segment.
108 * the caller should immediately assign data to the segment, as the segment
109 * otherwise is not generally valid
110 */
111static struct assegment *
112assegment_new (u_char type, u_short length)
113{
114 struct assegment *new;
115
116 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
117
118 if (length)
119 new->as = assegment_data_new (length);
120
121 new->length = length;
122 new->type = type;
123
124 return new;
125}
126
127static void
128assegment_free (struct assegment *seg)
129{
130 if (!seg)
131 return;
132
133 if (seg->as)
134 XFREE (MTYPE_AS_SEG_DATA, seg->as);
135 memset (seg, 0xfe, sizeof(struct assegment));
136 XFREE (MTYPE_AS_SEG, seg);
137
138 return;
139}
140
141/* free entire chain of segments */
142static void
143assegment_free_all (struct assegment *seg)
144{
145 struct assegment *prev;
146
147 while (seg)
148 {
149 prev = seg;
150 seg = seg->next;
151 assegment_free (prev);
152 }
153}
154
155/* Duplicate just the given assegment and its data */
156static struct assegment *
157assegment_dup (struct assegment *seg)
158{
159 struct assegment *new;
160
161 new = assegment_new (seg->type, seg->length);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000162 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );
paulfe69a502005-09-10 16:55:02 +0000163
164 return new;
165}
166
167/* Duplicate entire chain of assegments, return the head */
168static struct assegment *
169assegment_dup_all (struct assegment *seg)
170{
171 struct assegment *new = NULL;
172 struct assegment *head = NULL;
173
174 while (seg)
175 {
176 if (head)
177 {
178 new->next = assegment_dup (seg);
179 new = new->next;
180 }
181 else
182 head = new = assegment_dup (seg);
183
184 seg = seg->next;
185 }
186 return head;
187}
188
189/* prepend the as number to given segment, given num of times */
190static struct assegment *
191assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
192{
193 as_t *newas;
194
195 if (!num)
196 return seg;
197
198 if (num >= AS_SEGMENT_MAX)
199 return seg; /* we don't do huge prepends */
200
201 newas = assegment_data_new (seg->length + num);
202
203 if (newas)
204 {
205 int i;
206 for (i = 0; i < num; i++)
207 newas[i] = asnum;
208
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000209 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
paulfe69a502005-09-10 16:55:02 +0000210 XFREE (MTYPE_AS_SEG_DATA, seg->as);
211 seg->as = newas;
212 seg->length += num;
213 return seg;
214 }
215
216 assegment_free_all (seg);
217 return NULL;
218}
219
220/* append given array of as numbers to the segment */
221static struct assegment *
222assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
223{
paul02335422006-01-16 11:13:27 +0000224 as_t *newas;
225
226 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000227 ASSEGMENT_DATA_SIZE (seg->length + num, 1));
paulfe69a502005-09-10 16:55:02 +0000228
paul02335422006-01-16 11:13:27 +0000229 if (newas)
paulfe69a502005-09-10 16:55:02 +0000230 {
paul02335422006-01-16 11:13:27 +0000231 seg->as = newas;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000232 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));
paulfe69a502005-09-10 16:55:02 +0000233 seg->length += num;
234 return seg;
235 }
236
237 assegment_free_all (seg);
238 return NULL;
239}
240
241static int
242int_cmp (const void *p1, const void *p2)
243{
244 const as_t *as1 = p1;
245 const as_t *as2 = p2;
246
247 return (*as1 == *as2)
248 ? 0 : ( (*as1 > *as2) ? 1 : -1);
249}
250
251/* normalise the segment.
252 * In particular, merge runs of AS_SEQUENCEs into one segment
253 * Internally, we do not care about the wire segment length limit, and
254 * we want each distinct AS_PATHs to have the exact same internal
255 * representation - eg, so that our hashing actually works..
256 */
257static struct assegment *
258assegment_normalise (struct assegment *head)
259{
260 struct assegment *seg = head, *pin;
261 struct assegment *tmp;
262
263 if (!head)
264 return head;
265
266 while (seg)
267 {
268 pin = seg;
269
270 /* Sort values SET segments, for determinism in paths to aid
271 * creation of hash values / path comparisons
272 * and because it helps other lesser implementations ;)
273 */
274 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000275 {
276 int tail = 0;
277 int i;
278
279 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
280
281 /* weed out dupes */
282 for (i=1; i < seg->length; i++)
283 {
284 if (seg->as[tail] == seg->as[i])
285 continue;
286
287 tail++;
288 if (tail < i)
289 seg->as[tail] = seg->as[i];
290 }
291 /* seg->length can be 0.. */
292 if (seg->length)
293 seg->length = tail + 1;
294 }
paulfe69a502005-09-10 16:55:02 +0000295
296 /* read ahead from the current, pinned segment while the segments
297 * are packable/mergeable. Append all following packable segments
298 * to the segment we have pinned and remove these appended
299 * segments.
300 */
301 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
302 {
303 tmp = pin->next;
304 seg = pin->next;
305
306 /* append the next sequence to the pinned sequence */
307 pin = assegment_append_asns (pin, seg->as, seg->length);
308
309 /* bypass the next sequence */
310 pin->next = seg->next;
311
312 /* get rid of the now referenceless segment */
313 assegment_free (tmp);
314
315 }
316
317 seg = pin->next;
318 }
319 return head;
320}
321
paul718e3742002-12-13 20:15:29 +0000322static struct aspath *
paulfe69a502005-09-10 16:55:02 +0000323aspath_new (void)
paul718e3742002-12-13 20:15:29 +0000324{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700325 return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000326}
327
328/* Free AS path structure. */
329void
330aspath_free (struct aspath *aspath)
331{
332 if (!aspath)
333 return;
paulfe69a502005-09-10 16:55:02 +0000334 if (aspath->segments)
335 assegment_free_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000336 if (aspath->str)
337 XFREE (MTYPE_AS_STR, aspath->str);
338 XFREE (MTYPE_AS_PATH, aspath);
339}
340
341/* Unintern aspath from AS path bucket. */
342void
343aspath_unintern (struct aspath *aspath)
344{
345 struct aspath *ret;
346
347 if (aspath->refcnt)
348 aspath->refcnt--;
349
350 if (aspath->refcnt == 0)
351 {
352 /* This aspath must exist in aspath hash table. */
353 ret = hash_release (ashash, aspath);
354 assert (ret != NULL);
355 aspath_free (aspath);
356 }
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
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000487/* Return 1 if there are any 4-byte ASes in the path */
488unsigned int
489aspath_has_as4 (struct aspath *aspath)
490{
491 struct assegment *seg = aspath->segments;
492 unsigned int i;
493
494 while (seg)
495 {
496 for (i = 0; i < seg->length; i++)
497 if (seg->as[i] > BGP_AS_MAX)
498 return 1;
499 seg = seg->next;
500 }
501 return 0;
502}
503
paul718e3742002-12-13 20:15:29 +0000504/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000505static char *
paul718e3742002-12-13 20:15:29 +0000506aspath_make_str_count (struct aspath *as)
507{
paulfe69a502005-09-10 16:55:02 +0000508 struct assegment *seg;
509 int str_size;
510 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000511 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000512
513 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000514 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000515 {
516 str_buf = XMALLOC (MTYPE_AS_STR, 1);
517 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000518 return str_buf;
519 }
paulfe69a502005-09-10 16:55:02 +0000520
521 seg = as->segments;
522
Denis Ovsienko014b6702009-06-23 21:10:45 +0400523 /* ASN takes 5 to 10 chars plus seperator, see below.
524 * If there is one differing segment type, we need an additional
525 * 2 chars for segment delimiters, and the final '\0'.
526 * Hopefully this is large enough to avoid hitting the realloc
527 * code below for most common sequences.
528 *
529 * This was changed to 10 after the well-known BGP assertion, which
530 * had hit some parts of the Internet in May of 2009.
531 */
532#define ASN_STR_LEN (10 + 1)
533 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
534 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000535 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000536
paulfe69a502005-09-10 16:55:02 +0000537 while (seg)
paul718e3742002-12-13 20:15:29 +0000538 {
539 int i;
paulfe69a502005-09-10 16:55:02 +0000540 char seperator;
paul718e3742002-12-13 20:15:29 +0000541
paulfe69a502005-09-10 16:55:02 +0000542 /* Check AS type validity. Set seperator for segment */
543 switch (seg->type)
544 {
545 case AS_SET:
546 case AS_CONFED_SET:
547 seperator = ',';
548 break;
549 case AS_SEQUENCE:
550 case AS_CONFED_SEQUENCE:
551 seperator = ' ';
552 break;
553 default:
554 XFREE (MTYPE_AS_STR, str_buf);
555 return NULL;
556 }
557
Denis Ovsienko014b6702009-06-23 21:10:45 +0400558 /* We might need to increase str_buf, particularly if path has
559 * differing segments types, our initial guesstimate above will
560 * have been wrong. Need 10 chars for ASN, a seperator each and
561 * potentially two segment delimiters, plus a space between each
562 * segment and trailing zero.
563 *
564 * This definitely didn't work with the value of 5 bytes and
565 * 32-bit ASNs.
566 */
567#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
568 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
569 {
570 str_size = len + SEGMENT_STR_LEN(seg);
571 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
572 }
573#undef ASN_STR_LEN
574#undef SEGMENT_STR_LEN
575
paulfe69a502005-09-10 16:55:02 +0000576 if (seg->type != AS_SEQUENCE)
Denis Ovsienko014b6702009-06-23 21:10:45 +0400577 len += snprintf (str_buf + len, str_size - len,
578 "%c",
579 aspath_delimiter_char (seg->type, AS_SEG_START));
paulfe69a502005-09-10 16:55:02 +0000580
581 /* write out the ASNs, with their seperators, bar the last one*/
582 for (i = 0; i < seg->length; i++)
583 {
584 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
585
586 if (i < (seg->length - 1))
587 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
588 }
589
590 if (seg->type != AS_SEQUENCE)
591 len += snprintf (str_buf + len, str_size - len, "%c",
592 aspath_delimiter_char (seg->type, AS_SEG_END));
593 if (seg->next)
594 len += snprintf (str_buf + len, str_size - len, " ");
595
596 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000597 }
paulfe69a502005-09-10 16:55:02 +0000598
599 assert (len < str_size);
600
601 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000602
603 return str_buf;
604}
605
paulfe69a502005-09-10 16:55:02 +0000606static void
607aspath_str_update (struct aspath *as)
608{
609 if (as->str)
610 XFREE (MTYPE_AS_STR, as->str);
611 as->str = aspath_make_str_count (as);
612}
613
paul718e3742002-12-13 20:15:29 +0000614/* Intern allocated AS path. */
615struct aspath *
616aspath_intern (struct aspath *aspath)
617{
618 struct aspath *find;
619
620 /* Assert this AS path structure is not interned. */
621 assert (aspath->refcnt == 0);
622
623 /* Check AS path hash. */
624 find = hash_get (ashash, aspath, hash_alloc_intern);
625
626 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000627 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000628
629 find->refcnt++;
630
631 if (! find->str)
632 find->str = aspath_make_str_count (find);
633
634 return find;
635}
636
637/* Duplicate aspath structure. Created same aspath structure but
638 reference count and AS path string is cleared. */
639struct aspath *
640aspath_dup (struct aspath *aspath)
641{
642 struct aspath *new;
643
paulfe69a502005-09-10 16:55:02 +0000644 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000645
paulfe69a502005-09-10 16:55:02 +0000646 if (aspath->segments)
647 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000648 else
paulfe69a502005-09-10 16:55:02 +0000649 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000650
paulfe69a502005-09-10 16:55:02 +0000651 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000652
653 return new;
654}
655
paul94f2b392005-06-28 12:44:16 +0000656static void *
paulfe69a502005-09-10 16:55:02 +0000657aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000658{
659 struct aspath *aspath;
660
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000661 /* New aspath structure is needed. */
paulfe69a502005-09-10 16:55:02 +0000662 aspath = aspath_dup (arg);
663
paul718e3742002-12-13 20:15:29 +0000664 /* Malformed AS path value. */
665 if (! aspath->str)
666 {
667 aspath_free (aspath);
668 return NULL;
669 }
670
671 return aspath;
672}
673
Chris Hallcddb8112010-08-09 22:31:37 +0400674/* parse as-segment byte stream in struct assegment
675 *
676 * Returns NULL if the AS_PATH or AS4_PATH is not valid.
677 */
paulad727402005-11-23 02:47:02 +0000678static struct assegment *
Chris Hallcddb8112010-08-09 22:31:37 +0400679assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path)
paulfe69a502005-09-10 16:55:02 +0000680{
681 struct assegment_header segh;
682 struct assegment *seg, *prev = NULL, *head = NULL;
paulfe69a502005-09-10 16:55:02 +0000683
Chris Hallcddb8112010-08-09 22:31:37 +0400684 assert (length > 0); /* does not expect empty AS_PATH or AS4_PATH */
paulfe69a502005-09-10 16:55:02 +0000685
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000686 if (BGP_DEBUG (as4, AS4_SEGMENT))
687 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
688 (unsigned long) length);
Chris Hallcddb8112010-08-09 22:31:37 +0400689
690 /* double check that length does not exceed stream */
691 if (STREAM_READABLE(s) < length)
paulfe69a502005-09-10 16:55:02 +0000692 return NULL;
693
Chris Hallcddb8112010-08-09 22:31:37 +0400694 /* deal with each segment in turn */
695 while (length > 0)
paulfe69a502005-09-10 16:55:02 +0000696 {
697 int i;
Chris Hallcddb8112010-08-09 22:31:37 +0400698 size_t seg_size;
paulfe69a502005-09-10 16:55:02 +0000699
700 /* softly softly, get the header first on its own */
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100701 if (length < AS_HEADER_SIZE)
Chris Hallcddb8112010-08-09 22:31:37 +0400702 {
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100703 assegment_free_all (head);
704 return NULL;
705 }
706
paulfe69a502005-09-10 16:55:02 +0000707 segh.type = stream_getc (s);
708 segh.length = stream_getc (s);
709
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000710 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
Chris Hallcddb8112010-08-09 22:31:37 +0400711 /* includes the header bytes */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000712
713 if (BGP_DEBUG (as4, AS4_SEGMENT))
714 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
715 segh.type, segh.length);
716
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100717 switch (segh.type)
718 {
719 case AS_SEQUENCE:
720 case AS_SET:
721 break ;
Chris Hallcddb8112010-08-09 22:31:37 +0400722
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100723 case AS_CONFED_SEQUENCE:
724 case AS_CONFED_SET:
725 if (!as4_path)
726 break ;
Chris Hallcddb8112010-08-09 22:31:37 +0400727 /* RFC4893 3: "invalid for the AS4_PATH attribute" */
728 /* fall through */
729
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100730 default: /* reject unknown or invalid AS_PATH segment types */
731 seg_size = 0 ;
Chris Hallcddb8112010-08-09 22:31:37 +0400732 }
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100733
Chris Hallcddb8112010-08-09 22:31:37 +0400734 /* Stop now if segment is not valid (discarding anything collected to date)
735 *
736 * RFC4271 4.3, Path Attributes, b) AS_PATH:
737 *
738 * "path segment value field contains one or more AS numbers"
Denis Ovsienko2eb445e2009-12-04 17:32:54 +0300739 */
Chris Hallcddb8112010-08-09 22:31:37 +0400740 if ((seg_size == 0) || (seg_size > length) || (segh.length == 0))
paulfe69a502005-09-10 16:55:02 +0000741 {
Paul Jakmafdbc8e72011-04-11 16:31:43 +0100742 assegment_free_all (head);
paulfe69a502005-09-10 16:55:02 +0000743 return NULL;
744 }
745
Chris Hallcddb8112010-08-09 22:31:37 +0400746 length -= seg_size ;
747
paulfe69a502005-09-10 16:55:02 +0000748 /* now its safe to trust lengths */
749 seg = assegment_new (segh.type, segh.length);
750
751 if (head)
752 prev->next = seg;
753 else /* it's the first segment */
754 head = prev = seg;
755
756 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000757 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
758
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000759 if (BGP_DEBUG (as4, AS4_SEGMENT))
Chris Hallcddb8112010-08-09 22:31:37 +0400760 zlog_debug ("[AS4SEG] Parse aspath segment: length left: %lu",
761 (unsigned long) length);
paulfe69a502005-09-10 16:55:02 +0000762
763 prev = seg;
764 }
765
766 return assegment_normalise (head);
767}
768
Chris Hallcddb8112010-08-09 22:31:37 +0400769/* AS path parse function -- parses AS_PATH and AS4_PATH attributes
770 *
771 * Requires: s -- stream, currently positioned before first segment
772 * of AS_PATH or AS4_PATH (ie after attribute header)
773 * length -- length of the value of the AS_PATH or AS4_PATH
774 * use32bit -- true <=> 4Byte ASN, otherwise 2Byte ASN
775 * as4_path -- true <=> AS4_PATH, otherwise AS_PATH
776 *
777 * Returns: if valid: address of struct aspath in the hash of known aspaths,
778 * with reference count incremented.
779 * else: NULL
780 *
781 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
782 * have segments == NULL and str == zero length string (unique).
783 */
paul718e3742002-12-13 20:15:29 +0000784struct aspath *
Chris Hallcddb8112010-08-09 22:31:37 +0400785aspath_parse (struct stream *s, size_t length, int use32bit, int as4_path)
paul718e3742002-12-13 20:15:29 +0000786{
787 struct aspath as;
788 struct aspath *find;
789
Chris Hallcddb8112010-08-09 22:31:37 +0400790 /* Parse each segment and construct normalised list of struct assegment */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000791 memset (&as, 0, sizeof (struct aspath));
Chris Hallcddb8112010-08-09 22:31:37 +0400792 if (length != 0)
793 {
794 as.segments = assegments_parse (s, length, use32bit, as4_path);
795
796 if (as.segments == NULL)
797 return NULL ; /* Invalid AS_PATH or AS4_PATH */
798 } ;
paulfe69a502005-09-10 16:55:02 +0000799
paul718e3742002-12-13 20:15:29 +0000800 /* If already same aspath exist then return it. */
801 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000802
Chris Hallcddb8112010-08-09 22:31:37 +0400803 assert(find) ; /* valid aspath, so must find or create */
804
paul02335422006-01-16 11:13:27 +0000805 /* aspath_hash_alloc dupes segments too. that probably could be
806 * optimised out.
807 */
808 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000809 if (as.str)
810 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000811
paul718e3742002-12-13 20:15:29 +0000812 find->refcnt++;
813
814 return find;
815}
816
paulfe69a502005-09-10 16:55:02 +0000817static inline void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000818assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000819{
paulfe69a502005-09-10 16:55:02 +0000820 int i;
821 assert (num <= AS_SEGMENT_MAX);
822
823 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000824 if ( use32bit )
825 stream_putl (s, as[i]);
826 else
827 {
828 if ( as[i] <= BGP_AS_MAX )
829 stream_putw(s, as[i]);
830 else
831 stream_putw(s, BGP_AS_TRANS);
832 }
paul718e3742002-12-13 20:15:29 +0000833}
834
paulfe69a502005-09-10 16:55:02 +0000835static inline size_t
836assegment_header_put (struct stream *s, u_char type, int length)
837{
838 size_t lenp;
839 assert (length <= AS_SEGMENT_MAX);
840 stream_putc (s, type);
841 lenp = stream_get_endp (s);
842 stream_putc (s, length);
843 return lenp;
844}
845
846/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000847size_t
848aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000849{
850 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000851 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000852
853 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000854 return 0;
paulfe69a502005-09-10 16:55:02 +0000855
856 if (seg)
857 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000858 /*
859 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
860 * At the moment, we would write out a partial aspath, and our peer
861 * will complain and drop the session :-/
862 *
863 * The general assumption here is that many things tested will
864 * never happen. And, in real live, up to now, they have not.
865 */
866 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000867 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000868 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000869 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000870 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000871 size_t lenp;
872
873 /* Overlength segments have to be split up */
874 while ( (seg->length - written) > AS_SEGMENT_MAX)
875 {
876 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000877 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000878 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000879 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000880 }
881
882 /* write the final segment, probably is also the first */
883 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000884 assegment_data_put (s, (seg->as + written), seg->length - written,
885 use32bit);
paulfe69a502005-09-10 16:55:02 +0000886
887 /* Sequence-type segments can be 'packed' together
888 * Case of a segment which was overlength and split up
889 * will be missed here, but that doesn't matter.
890 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000891 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000892 {
893 /* NB: We should never normally get here given we
894 * normalise aspath data when parse them. However, better
895 * safe than sorry. We potentially could call
896 * assegment_normalise here instead, but it's cheaper and
897 * easier to do it on the fly here rather than go through
898 * the segment list twice every time we write out
899 * aspath's.
900 */
901
902 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000903 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000904
905 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000906 stream_putc_at (s, lenp, seg->length - written + next->length);
907 asns_packed += next->length;
908
909 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000910 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000911
912 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
913 use32bit);
914 seg = next;
paulfe69a502005-09-10 16:55:02 +0000915 }
916 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000917 return bytes;
paulfe69a502005-09-10 16:55:02 +0000918}
919
920/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
921 * We have no way to manage the storage, so we use a static stream
922 * wrapper around aspath_put.
923 */
924u_char *
925aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
926{
927#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000928
929 if (!snmp_stream)
930 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000931 else
paul8fdc32a2006-01-16 12:01:29 +0000932 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000933
934 if (!as)
935 {
936 *varlen = 0;
937 return NULL;
938 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000939 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000940
paul8fdc32a2006-01-16 12:01:29 +0000941 *varlen = stream_get_endp (snmp_stream);
942 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000943}
944
945#define min(A,B) ((A) < (B) ? (A) : (B))
946
paul94f2b392005-06-28 12:44:16 +0000947static struct assegment *
paul718e3742002-12-13 20:15:29 +0000948aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
949 as_t as)
950{
951 int i;
952
953 /* If this is first AS set member, create new as-set segment. */
954 if (asset == NULL)
955 {
paulfe69a502005-09-10 16:55:02 +0000956 asset = assegment_new (AS_SET, 1);
957 if (! aspath->segments)
958 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000959 else
paulfe69a502005-09-10 16:55:02 +0000960 {
961 struct assegment *seg = aspath->segments;
962 while (seg->next)
963 seg = seg->next;
964 seg->next = asset;
965 }
paul718e3742002-12-13 20:15:29 +0000966 asset->type = AS_SET;
967 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000968 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000969 }
970 else
971 {
paul718e3742002-12-13 20:15:29 +0000972 /* Check this AS value already exists or not. */
973 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000974 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000975 return asset;
paulfe69a502005-09-10 16:55:02 +0000976
paul718e3742002-12-13 20:15:29 +0000977 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000978 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
979 asset->length * AS_VALUE_SIZE);
980 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000981 }
paulfe69a502005-09-10 16:55:02 +0000982
paul718e3742002-12-13 20:15:29 +0000983
984 return asset;
985}
986
987/* Modify as1 using as2 for aggregation. */
988struct aspath *
989aspath_aggregate (struct aspath *as1, struct aspath *as2)
990{
991 int i;
992 int minlen;
993 int match;
paulfe69a502005-09-10 16:55:02 +0000994 int from;
995 struct assegment *seg1 = as1->segments;
996 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000997 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000998 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000999 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +00001000
1001 match = 0;
1002 minlen = 0;
1003 aspath = NULL;
1004 asset = NULL;
paul718e3742002-12-13 20:15:29 +00001005
1006 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +00001007 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001008 {
paul718e3742002-12-13 20:15:29 +00001009 /* Check segment type. */
1010 if (seg1->type != seg2->type)
1011 break;
1012
1013 /* Minimum segment length. */
1014 minlen = min (seg1->length, seg2->length);
1015
1016 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001017 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001018 break;
1019
1020 if (match)
1021 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001022 struct assegment *seg = assegment_new (seg1->type, 0);
1023
1024 seg = assegment_append_asns (seg, seg1->as, match);
1025
paul718e3742002-12-13 20:15:29 +00001026 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001027 {
1028 aspath = aspath_new ();
1029 aspath->segments = seg;
1030 }
1031 else
1032 prevseg->next = seg;
1033
1034 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001035 }
1036
1037 if (match != minlen || match != seg1->length
1038 || seg1->length != seg2->length)
1039 break;
paulfe69a502005-09-10 16:55:02 +00001040
1041 seg1 = seg1->next;
1042 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001043 }
1044
1045 if (! aspath)
1046 aspath = aspath_new();
1047
1048 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001049 from = match;
1050 while (seg1)
paul718e3742002-12-13 20:15:29 +00001051 {
paulfe69a502005-09-10 16:55:02 +00001052 for (i = from; i < seg1->length; i++)
1053 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1054
1055 from = 0;
1056 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001057 }
1058
paulfe69a502005-09-10 16:55:02 +00001059 from = match;
1060 while (seg2)
paul718e3742002-12-13 20:15:29 +00001061 {
paulfe69a502005-09-10 16:55:02 +00001062 for (i = from; i < seg2->length; i++)
1063 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001064
paulfe69a502005-09-10 16:55:02 +00001065 from = 0;
1066 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001067 }
paulfe69a502005-09-10 16:55:02 +00001068
1069 assegment_normalise (aspath->segments);
1070 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001071 return aspath;
1072}
1073
1074/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1075 attribute, check the leftmost AS number in the AS_PATH attribute is
1076 or not the peer's AS number. */
1077int
1078aspath_firstas_check (struct aspath *aspath, as_t asno)
1079{
paulfe69a502005-09-10 16:55:02 +00001080 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001081 return 0;
paulfe69a502005-09-10 16:55:02 +00001082
1083 if (aspath->segments
1084 && (aspath->segments->type == AS_SEQUENCE)
1085 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001086 return 1;
1087
1088 return 0;
1089}
1090
Paul Jakma1f742f22006-08-06 15:52:11 +00001091/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001092int
1093aspath_loop_check (struct aspath *aspath, as_t asno)
1094{
paulfe69a502005-09-10 16:55:02 +00001095 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001096 int count = 0;
1097
Paul Jakma1f742f22006-08-06 15:52:11 +00001098 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001099 return 0;
paulfe69a502005-09-10 16:55:02 +00001100
1101 seg = aspath->segments;
1102
1103 while (seg)
paul718e3742002-12-13 20:15:29 +00001104 {
1105 int i;
paul718e3742002-12-13 20:15:29 +00001106
paulfe69a502005-09-10 16:55:02 +00001107 for (i = 0; i < seg->length; i++)
1108 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001109 count++;
paulfe69a502005-09-10 16:55:02 +00001110
1111 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001112 }
1113 return count;
1114}
1115
1116/* When all of AS path is private AS return 1. */
1117int
1118aspath_private_as_check (struct aspath *aspath)
1119{
paulfe69a502005-09-10 16:55:02 +00001120 struct assegment *seg;
1121
1122 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001123 return 0;
paulfe69a502005-09-10 16:55:02 +00001124
1125 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001126
paulfe69a502005-09-10 16:55:02 +00001127 while (seg)
paul718e3742002-12-13 20:15:29 +00001128 {
1129 int i;
paul718e3742002-12-13 20:15:29 +00001130
paulfe69a502005-09-10 16:55:02 +00001131 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001132 {
paulfe69a502005-09-10 16:55:02 +00001133 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1134 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001135 return 0;
1136 }
paulfe69a502005-09-10 16:55:02 +00001137 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001138 }
1139 return 1;
1140}
1141
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001142/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1143int
1144aspath_confed_check (struct aspath *aspath)
1145{
1146 struct assegment *seg;
1147
1148 if ( !(aspath && aspath->segments) )
1149 return 0;
1150
1151 seg = aspath->segments;
1152
1153 while (seg)
1154 {
1155 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1156 return 1;
1157 seg = seg->next;
1158 }
1159 return 0;
1160}
1161
1162/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1163 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1164int
1165aspath_left_confed_check (struct aspath *aspath)
1166{
1167
1168 if ( !(aspath && aspath->segments) )
1169 return 0;
1170
1171 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1172 || (aspath->segments->type == AS_CONFED_SET) )
1173 return 1;
1174
1175 return 0;
1176}
1177
paul718e3742002-12-13 20:15:29 +00001178/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001179static struct aspath *
paul718e3742002-12-13 20:15:29 +00001180aspath_merge (struct aspath *as1, struct aspath *as2)
1181{
paulfe69a502005-09-10 16:55:02 +00001182 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001183
1184 if (! as1 || ! as2)
1185 return NULL;
1186
paulfe69a502005-09-10 16:55:02 +00001187 last = new = assegment_dup_all (as1->segments);
1188
1189 /* find the last valid segment */
1190 while (last && last->next)
1191 last = last->next;
1192
1193 last->next = as2->segments;
1194 as2->segments = new;
1195 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001196 return as2;
1197}
1198
1199/* Prepend as1 to as2. as2 should be uninterned aspath. */
1200struct aspath *
1201aspath_prepend (struct aspath *as1, struct aspath *as2)
1202{
paulfe69a502005-09-10 16:55:02 +00001203 struct assegment *seg1;
1204 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001205
1206 if (! as1 || ! as2)
1207 return NULL;
paulfe69a502005-09-10 16:55:02 +00001208
1209 seg1 = as1->segments;
1210 seg2 = as2->segments;
1211
1212 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001213 if (seg2 == NULL)
1214 {
paulfe69a502005-09-10 16:55:02 +00001215 as2->segments = assegment_dup_all (as1->segments);
1216 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001217 return as2;
1218 }
paulfe69a502005-09-10 16:55:02 +00001219
1220 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001221 if (seg1 == NULL)
1222 return as2;
paulfe69a502005-09-10 16:55:02 +00001223
1224 /* find the tail as1's segment chain. */
1225 while (seg1 && seg1->next)
1226 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001227
Vasilis Tsiligiannis736d4402009-07-20 01:59:10 +03001228 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1229 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1230 as2 = aspath_delete_confed_seq (as2);
1231
paul718e3742002-12-13 20:15:29 +00001232 /* Compare last segment type of as1 and first segment type of as2. */
1233 if (seg1->type != seg2->type)
1234 return aspath_merge (as1, as2);
1235
1236 if (seg1->type == AS_SEQUENCE)
1237 {
paulfe69a502005-09-10 16:55:02 +00001238 /* We have two chains of segments, as1->segments and seg2,
1239 * and we have to attach them together, merging the attaching
1240 * segments together into one.
1241 *
1242 * 1. dupe as1->segments onto head of as2
1243 * 2. merge seg2's asns onto last segment of this new chain
1244 * 3. attach chain after seg2
1245 */
paul718e3742002-12-13 20:15:29 +00001246
paulfe69a502005-09-10 16:55:02 +00001247 /* dupe as1 onto as2's head */
1248 seg1 = as2->segments = assegment_dup_all (as1->segments);
1249
1250 /* refind the tail of as2, reusing seg1 */
1251 while (seg1 && seg1->next)
1252 seg1 = seg1->next;
1253
1254 /* merge the old head, seg2, into tail, seg1 */
1255 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1256
1257 /* bypass the merged seg2, and attach any chain after it to
1258 * chain descending from as2's head
1259 */
1260 seg1->next = seg2->next;
1261
1262 /* seg2 is now referenceless and useless*/
1263 assegment_free (seg2);
1264
1265 /* we've now prepended as1's segment chain to as2, merging
1266 * the inbetween AS_SEQUENCE of seg2 in the process
1267 */
1268 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001269 return as2;
1270 }
1271 else
1272 {
1273 /* AS_SET merge code is needed at here. */
1274 return aspath_merge (as1, as2);
1275 }
paulfe69a502005-09-10 16:55:02 +00001276 /* XXX: Ermmm, what if as1 has multiple segments?? */
1277
paul718e3742002-12-13 20:15:29 +00001278 /* Not reached */
1279}
1280
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001281/* Iterate over AS_PATH segments and wipe all occurences of the
1282 * listed AS numbers. Hence some segments may lose some or even
1283 * all data on the way, the operation is implemented as a smarter
1284 * version of aspath_dup(), which allocates memory to hold the new
1285 * data, not the original. The new AS path is returned.
1286 */
1287struct aspath *
1288aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1289{
1290 struct assegment * srcseg, * exclseg, * lastseg;
1291 struct aspath * newpath;
1292
1293 newpath = aspath_new();
1294 lastseg = NULL;
1295
1296 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1297 {
1298 unsigned i, y, newlen = 0, done = 0, skip_as;
1299 struct assegment * newseg;
1300
1301 /* Find out, how much ASns are we going to pick from this segment.
1302 * We can't perform filtering right inline, because the size of
1303 * the new segment isn't known at the moment yet.
1304 */
1305 for (i = 0; i < srcseg->length; i++)
1306 {
1307 skip_as = 0;
1308 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1309 for (y = 0; y < exclseg->length; y++)
1310 if (srcseg->as[i] == exclseg->as[y])
1311 {
1312 skip_as = 1;
1313 // There's no sense in testing the rest of exclusion list, bail out.
1314 break;
1315 }
1316 if (!skip_as)
1317 newlen++;
1318 }
1319 /* newlen is now the number of ASns to copy */
1320 if (!newlen)
1321 continue;
1322
1323 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1324 newseg = assegment_new (srcseg->type, newlen);
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 break;
1334 }
1335 if (skip_as)
1336 continue;
1337 newseg->as[done++] = srcseg->as[i];
1338 }
1339 /* At his point newlen must be equal to done, and both must be positive. Append
1340 * the filtered segment to the gross result. */
1341 if (!lastseg)
1342 newpath->segments = newseg;
1343 else
1344 lastseg->next = newseg;
1345 lastseg = newseg;
1346 }
1347 aspath_str_update (newpath);
1348 /* We are happy returning even an empty AS_PATH, because the administrator
1349 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1350 * by having a match rule against certain AS_PATH regexps in the route-map index.
1351 */
1352 aspath_free (source);
1353 return newpath;
1354}
1355
paul718e3742002-12-13 20:15:29 +00001356/* Add specified AS to the leftmost of aspath. */
1357static struct aspath *
1358aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1359{
paulfe69a502005-09-10 16:55:02 +00001360 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001361
1362 /* In case of empty aspath. */
1363 if (assegment == NULL || assegment->length == 0)
1364 {
paulfe69a502005-09-10 16:55:02 +00001365 aspath->segments = assegment_new (type, 1);
1366 aspath->segments->as[0] = asno;
1367
paul718e3742002-12-13 20:15:29 +00001368 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001369 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001370
1371 return aspath;
1372 }
1373
1374 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001375 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1376 else
paul718e3742002-12-13 20:15:29 +00001377 {
paulfe69a502005-09-10 16:55:02 +00001378 /* create new segment
1379 * push it onto head of aspath's segment chain
1380 */
paul718e3742002-12-13 20:15:29 +00001381 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001382
1383 newsegment = assegment_new (type, 1);
1384 newsegment->as[0] = asno;
1385
1386 newsegment->next = assegment;
1387 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001388 }
1389
1390 return aspath;
1391}
1392
1393/* Add specified AS to the leftmost of aspath. */
1394struct aspath *
1395aspath_add_seq (struct aspath *aspath, as_t asno)
1396{
1397 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1398}
1399
1400/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1401 as2's leftmost AS is same return 1. */
1402int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001403aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001404{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001405 const struct assegment *seg1 = NULL;
1406 const struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001407
paulfe69a502005-09-10 16:55:02 +00001408 if (!(aspath1 && aspath2))
1409 return 0;
paul718e3742002-12-13 20:15:29 +00001410
paulfe69a502005-09-10 16:55:02 +00001411 seg1 = aspath1->segments;
1412 seg2 = aspath2->segments;
1413
1414 /* find first non-confed segments for each */
1415 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1416 || (seg1->type == AS_CONFED_SET)))
1417 seg1 = seg1->next;
1418
1419 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1420 || (seg2->type == AS_CONFED_SET)))
1421 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001422
1423 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001424 if (!(seg1 && seg2
1425 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001426 return 0;
paulfe69a502005-09-10 16:55:02 +00001427
1428 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001429 return 1;
1430
1431 return 0;
1432}
1433
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001434/* Truncate an aspath after a number of hops, and put the hops remaining
1435 * at the front of another aspath. Needed for AS4 compat.
1436 *
1437 * Returned aspath is a /new/ aspath, which should either by free'd or
1438 * interned by the caller, as desired.
1439 */
1440struct aspath *
1441aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1442{
1443 struct assegment *seg, *newseg, *prevseg = NULL;
1444 struct aspath *newpath = NULL, *mergedpath;
1445 int hops, cpasns = 0;
1446
1447 if (!aspath)
1448 return NULL;
1449
1450 seg = aspath->segments;
1451
1452 /* CONFEDs should get reconciled too.. */
1453 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1454 - aspath_count_hops (as4path);
1455
1456 if (hops < 0)
1457 {
1458 if (BGP_DEBUG (as4, AS4))
1459 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1460 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1461 * which is daft behaviour - it contains vital loop-detection
1462 * information which must have been removed from AS_PATH.
1463 */
1464 hops = aspath_count_hops (aspath);
1465 }
1466
1467 if (!hops)
1468 return aspath_dup (as4path);
1469
1470 if ( BGP_DEBUG(as4, AS4))
1471 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1472 aspath->str, as4path->str);
1473
1474 while (seg && hops > 0)
1475 {
1476 switch (seg->type)
1477 {
1478 case AS_SET:
1479 case AS_CONFED_SET:
1480 hops--;
1481 cpasns = seg->length;
1482 break;
1483 case AS_CONFED_SEQUENCE:
1484 /* Should never split a confed-sequence, if hop-count
1485 * suggests we must then something's gone wrong somewhere.
1486 *
1487 * Most important goal is to preserve AS_PATHs prime function
1488 * as loop-detector, so we fudge the numbers so that the entire
1489 * confed-sequence is merged in.
1490 */
1491 if (hops < seg->length)
1492 {
1493 if (BGP_DEBUG (as4, AS4))
1494 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1495 " across 2/4 ASN boundary somewhere, broken..");
1496 hops = seg->length;
1497 }
1498 case AS_SEQUENCE:
1499 cpasns = MIN(seg->length, hops);
1500 hops -= seg->length;
1501 }
1502
1503 assert (cpasns <= seg->length);
1504
1505 newseg = assegment_new (seg->type, 0);
1506 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1507
1508 if (!newpath)
1509 {
1510 newpath = aspath_new ();
1511 newpath->segments = newseg;
1512 }
1513 else
1514 prevseg->next = newseg;
1515
1516 prevseg = newseg;
1517 seg = seg->next;
1518 }
1519
1520 /* We may be able to join some segments here, and we must
1521 * do this because... we want normalised aspaths in out hash
1522 * and we do not want to stumble in aspath_put.
1523 */
1524 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1525 aspath_free (newpath);
1526 mergedpath->segments = assegment_normalise (mergedpath->segments);
1527 aspath_str_update (mergedpath);
1528
1529 if ( BGP_DEBUG(as4, AS4))
1530 zlog_debug ("[AS4] result of synthesizing is %s",
1531 mergedpath->str);
1532
1533 return mergedpath;
1534}
1535
paul718e3742002-12-13 20:15:29 +00001536/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1537 as2's leftmost AS is same return 1. (confederation as-path
1538 only). */
1539int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001540aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001541{
paulfe69a502005-09-10 16:55:02 +00001542 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001543 return 0;
paulfe69a502005-09-10 16:55:02 +00001544
paulad727402005-11-23 02:47:02 +00001545 if ( !(aspath1->segments && aspath2->segments) )
1546 return 0;
1547
paulfe69a502005-09-10 16:55:02 +00001548 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1549 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001550 return 0;
paulfe69a502005-09-10 16:55:02 +00001551
1552 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001553 return 1;
1554
1555 return 0;
1556}
1557
paulfe69a502005-09-10 16:55:02 +00001558/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1559 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001560struct aspath *
1561aspath_delete_confed_seq (struct aspath *aspath)
1562{
paulfe69a502005-09-10 16:55:02 +00001563 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001564
paulfe69a502005-09-10 16:55:02 +00001565 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001566 return aspath;
1567
paulfe69a502005-09-10 16:55:02 +00001568 seg = aspath->segments;
1569
1570 /* "if the first path segment of the AS_PATH is
1571 * of type AS_CONFED_SEQUENCE,"
1572 */
1573 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1574 return aspath;
paul718e3742002-12-13 20:15:29 +00001575
paulfe69a502005-09-10 16:55:02 +00001576 /* "... that segment and any immediately following segments
1577 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1578 * from the AS_PATH attribute,"
1579 */
1580 while (seg &&
1581 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001582 {
paulfe69a502005-09-10 16:55:02 +00001583 aspath->segments = seg->next;
1584 assegment_free (seg);
1585 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001586 }
paulfe69a502005-09-10 16:55:02 +00001587 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001588 return aspath;
1589}
1590
1591/* Add new AS number to the leftmost part of the aspath as
1592 AS_CONFED_SEQUENCE. */
1593struct aspath*
1594aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1595{
1596 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1597}
1598
1599/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001600static void
paul718e3742002-12-13 20:15:29 +00001601aspath_as_add (struct aspath *as, as_t asno)
1602{
paulfe69a502005-09-10 16:55:02 +00001603 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001604
paulfe69a502005-09-10 16:55:02 +00001605 if (!seg)
1606 return;
1607
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001608 /* Last segment search procedure. */
1609 while (seg->next)
1610 seg = seg->next;
1611
paulfe69a502005-09-10 16:55:02 +00001612 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001613}
1614
1615/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001616static void
paul718e3742002-12-13 20:15:29 +00001617aspath_segment_add (struct aspath *as, int type)
1618{
paulfe69a502005-09-10 16:55:02 +00001619 struct assegment *seg = as->segments;
1620 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001621
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001622 if (seg)
1623 {
1624 while (seg->next)
1625 seg = seg->next;
1626 seg->next = new;
1627 }
paul718e3742002-12-13 20:15:29 +00001628 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001629 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001630}
1631
1632struct aspath *
paul94f2b392005-06-28 12:44:16 +00001633aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001634{
Chris Hallcddb8112010-08-09 22:31:37 +04001635 return aspath_parse (NULL, 0, 1, 0); /* 32Bit ;-) not AS4_PATH */
paul718e3742002-12-13 20:15:29 +00001636}
1637
1638struct aspath *
paul94f2b392005-06-28 12:44:16 +00001639aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001640{
1641 struct aspath *aspath;
1642
1643 aspath = aspath_new ();
1644 aspath->str = aspath_make_str_count (aspath);
1645 return aspath;
1646}
1647
1648unsigned long
paulfe69a502005-09-10 16:55:02 +00001649aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001650{
1651 return ashash->count;
1652}
1653
1654/*
1655 Theoretically, one as path can have:
1656
1657 One BGP packet size should be less than 4096.
1658 One BGP attribute size should be less than 4096 - BGP header size.
1659 One BGP aspath size should be less than 4096 - BGP header size -
1660 BGP mandantry attribute size.
1661*/
1662
1663/* AS path string lexical token enum. */
1664enum as_token
1665{
1666 as_token_asval,
1667 as_token_set_start,
1668 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001669 as_token_confed_seq_start,
1670 as_token_confed_seq_end,
1671 as_token_confed_set_start,
1672 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001673 as_token_unknown
1674};
1675
1676/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001677static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001678aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001679{
paulfd79ac92004-10-13 05:06:08 +00001680 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001681
paulfe69a502005-09-10 16:55:02 +00001682 /* Skip seperators (space for sequences, ',' for sets). */
1683 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001684 p++;
1685
1686 /* Check the end of the string and type specify characters
1687 (e.g. {}()). */
1688 switch (*p)
1689 {
1690 case '\0':
1691 return NULL;
paul718e3742002-12-13 20:15:29 +00001692 case '{':
1693 *token = as_token_set_start;
1694 p++;
1695 return p;
paul718e3742002-12-13 20:15:29 +00001696 case '}':
1697 *token = as_token_set_end;
1698 p++;
1699 return p;
paul718e3742002-12-13 20:15:29 +00001700 case '(':
paulfe69a502005-09-10 16:55:02 +00001701 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001702 p++;
1703 return p;
paul718e3742002-12-13 20:15:29 +00001704 case ')':
paulfe69a502005-09-10 16:55:02 +00001705 *token = as_token_confed_seq_end;
1706 p++;
1707 return p;
paulfe69a502005-09-10 16:55:02 +00001708 case '[':
1709 *token = as_token_confed_set_start;
1710 p++;
1711 return p;
paulfe69a502005-09-10 16:55:02 +00001712 case ']':
1713 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001714 p++;
1715 return p;
paul718e3742002-12-13 20:15:29 +00001716 }
1717
1718 /* Check actual AS value. */
1719 if (isdigit ((int) *p))
1720 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001721 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001722
paul718e3742002-12-13 20:15:29 +00001723 *token = as_token_asval;
1724 asval = (*p - '0');
1725 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001726
paul718e3742002-12-13 20:15:29 +00001727 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001728 {
1729 asval *= 10;
1730 asval += (*p - '0');
1731 p++;
1732 }
paul718e3742002-12-13 20:15:29 +00001733 *asno = asval;
1734 return p;
1735 }
1736
1737 /* There is no match then return unknown token. */
1738 *token = as_token_unknown;
1739 return p++;
1740}
1741
1742struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001743aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001744{
paul3fff6ff2006-02-05 17:55:35 +00001745 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001746 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001747 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001748 struct aspath *aspath;
1749 int needtype;
1750
1751 aspath = aspath_new ();
1752
1753 /* We start default type as AS_SEQUENCE. */
1754 as_type = AS_SEQUENCE;
1755 needtype = 1;
1756
1757 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1758 {
1759 switch (token)
1760 {
1761 case as_token_asval:
1762 if (needtype)
1763 {
1764 aspath_segment_add (aspath, as_type);
1765 needtype = 0;
1766 }
1767 aspath_as_add (aspath, asno);
1768 break;
1769 case as_token_set_start:
1770 as_type = AS_SET;
1771 aspath_segment_add (aspath, as_type);
1772 needtype = 0;
1773 break;
1774 case as_token_set_end:
1775 as_type = AS_SEQUENCE;
1776 needtype = 1;
1777 break;
paulfe69a502005-09-10 16:55:02 +00001778 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001779 as_type = AS_CONFED_SEQUENCE;
1780 aspath_segment_add (aspath, as_type);
1781 needtype = 0;
1782 break;
paulfe69a502005-09-10 16:55:02 +00001783 case as_token_confed_seq_end:
1784 as_type = AS_SEQUENCE;
1785 needtype = 1;
1786 break;
1787 case as_token_confed_set_start:
1788 as_type = AS_CONFED_SET;
1789 aspath_segment_add (aspath, as_type);
1790 needtype = 0;
1791 break;
1792 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001793 as_type = AS_SEQUENCE;
1794 needtype = 1;
1795 break;
1796 case as_token_unknown:
1797 default:
paulfe69a502005-09-10 16:55:02 +00001798 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001799 return NULL;
paul718e3742002-12-13 20:15:29 +00001800 }
1801 }
1802
1803 aspath->str = aspath_make_str_count (aspath);
1804
1805 return aspath;
1806}
1807
1808/* Make hash value by raw aspath data. */
1809unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001810aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001811{
Paul Jakma923de652007-04-29 18:25:17 +00001812 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001813 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001814
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001815 if (!aspath->str)
1816 aspath_str_update (aspath);
1817
1818 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001819
1820 return key;
1821}
1822
1823/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001824static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001825aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001826{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001827 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1828 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001829
1830 while (seg1 || seg2)
1831 {
1832 int i;
1833 if ((!seg1 && seg2) || (seg1 && !seg2))
1834 return 0;
1835 if (seg1->type != seg2->type)
1836 return 0;
1837 if (seg1->length != seg2->length)
1838 return 0;
1839 for (i = 0; i < seg1->length; i++)
1840 if (seg1->as[i] != seg2->as[i])
1841 return 0;
1842 seg1 = seg1->next;
1843 seg2 = seg2->next;
1844 }
1845 return 1;
paul718e3742002-12-13 20:15:29 +00001846}
1847
1848/* AS path hash initialize. */
1849void
paul94f2b392005-06-28 12:44:16 +00001850aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001851{
1852 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1853}
paul8fdc32a2006-01-16 12:01:29 +00001854
1855void
1856aspath_finish (void)
1857{
1858 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00001859 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00001860
1861 if (snmp_stream)
1862 stream_free (snmp_stream);
1863}
paul718e3742002-12-13 20:15:29 +00001864
1865/* return and as path value */
1866const char *
1867aspath_print (struct aspath *as)
1868{
paulfe69a502005-09-10 16:55:02 +00001869 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001870}
1871
1872/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001873/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1874 * AS_PATH wasn't empty.
1875 */
paul718e3742002-12-13 20:15:29 +00001876void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001877aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001878{
Paul Jakmab2518c12006-05-12 23:48:40 +00001879 assert (format);
1880 vty_out (vty, format, as->str);
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001881 if (strlen (as->str) && strlen (suffix))
1882 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001883}
1884
paul94f2b392005-06-28 12:44:16 +00001885static void
paul718e3742002-12-13 20:15:29 +00001886aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1887{
1888 struct aspath *as;
1889
1890 as = (struct aspath *) backet->data;
1891
paulefa9f832002-12-13 21:47:59 +00001892 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001893 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1894}
1895
1896/* Print all aspath and hash information. This function is used from
1897 `show ip bgp paths' command. */
1898void
1899aspath_print_all_vty (struct vty *vty)
1900{
1901 hash_iterate (ashash,
1902 (void (*) (struct hash_backet *, void *))
1903 aspath_show_all_iterator,
1904 vty);
1905}