blob: a9602d9092d9457da7f90b4b28457c0a0520727f [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
paulfe69a502005-09-10 16:55:02 +0000674/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000675static struct assegment *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000676assegments_parse (struct stream *s, size_t length, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000677{
678 struct assegment_header segh;
679 struct assegment *seg, *prev = NULL, *head = NULL;
680 size_t bytes = 0;
681
682 /* empty aspath (ie iBGP or somesuch) */
683 if (length == 0)
684 return NULL;
685
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);
paulfe69a502005-09-10 16:55:02 +0000689 /* basic checks */
690 if ( (STREAM_READABLE(s) < length)
691 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000692 || (length % AS16_VALUE_SIZE ))
paulfe69a502005-09-10 16:55:02 +0000693 return NULL;
694
695 while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
696 && (bytes < length))
697 {
698 int i;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000699 int seg_size;
paulfe69a502005-09-10 16:55:02 +0000700
701 /* softly softly, get the header first on its own */
702 segh.type = stream_getc (s);
703 segh.length = stream_getc (s);
704
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000705 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
706
707 if (BGP_DEBUG (as4, AS4_SEGMENT))
708 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
709 segh.type, segh.length);
710
paulfe69a502005-09-10 16:55:02 +0000711 /* check it.. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000712 if ( ((bytes + seg_size) > length)
paulfe69a502005-09-10 16:55:02 +0000713 /* 1771bis 4.3b: seg length contains one or more */
714 || (segh.length == 0)
Denis Ovsienko2eb445e2009-12-04 17:32:54 +0300715 /* Paranoia in case someone changes type of segment length.
716 * Shift both values by 0x10 to make the comparison operate
717 * on more, than 8 bits (otherwise it's a warning, bug #564).
718 */
719 || ((sizeof segh.length > 1) && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)) )
paulfe69a502005-09-10 16:55:02 +0000720 {
721 if (head)
722 assegment_free_all (head);
723 return NULL;
724 }
725
726 /* now its safe to trust lengths */
727 seg = assegment_new (segh.type, segh.length);
728
729 if (head)
730 prev->next = seg;
731 else /* it's the first segment */
732 head = prev = seg;
733
734 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000735 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
736
737 bytes += seg_size;
paulfe69a502005-09-10 16:55:02 +0000738
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000739 if (BGP_DEBUG (as4, AS4_SEGMENT))
740 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
741 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000742
743 prev = seg;
744 }
745
746 return assegment_normalise (head);
747}
748
paul718e3742002-12-13 20:15:29 +0000749/* AS path parse function. pnt is a pointer to byte stream and length
750 is length of byte stream. If there is same AS path in the the AS
751 path hash then return it else make new AS path structure. */
752struct aspath *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000753aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000754{
755 struct aspath as;
756 struct aspath *find;
757
758 /* If length is odd it's malformed AS path. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000759 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
760 * otherwise its malformed when length is larger than 2 and (length-2)
761 * is not dividable by 4.
762 * But... this time we're lazy
763 */
764 if (length % AS16_VALUE_SIZE )
paul718e3742002-12-13 20:15:29 +0000765 return NULL;
766
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000767 memset (&as, 0, sizeof (struct aspath));
768 as.segments = assegments_parse (s, length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000769
paul718e3742002-12-13 20:15:29 +0000770 /* If already same aspath exist then return it. */
771 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000772
773 /* aspath_hash_alloc dupes segments too. that probably could be
774 * optimised out.
775 */
776 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000777 if (as.str)
778 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000779
paul718e3742002-12-13 20:15:29 +0000780 if (! find)
781 return NULL;
782 find->refcnt++;
783
784 return find;
785}
786
paulfe69a502005-09-10 16:55:02 +0000787static inline void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000788assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000789{
paulfe69a502005-09-10 16:55:02 +0000790 int i;
791 assert (num <= AS_SEGMENT_MAX);
792
793 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000794 if ( use32bit )
795 stream_putl (s, as[i]);
796 else
797 {
798 if ( as[i] <= BGP_AS_MAX )
799 stream_putw(s, as[i]);
800 else
801 stream_putw(s, BGP_AS_TRANS);
802 }
paul718e3742002-12-13 20:15:29 +0000803}
804
paulfe69a502005-09-10 16:55:02 +0000805static inline size_t
806assegment_header_put (struct stream *s, u_char type, int length)
807{
808 size_t lenp;
809 assert (length <= AS_SEGMENT_MAX);
810 stream_putc (s, type);
811 lenp = stream_get_endp (s);
812 stream_putc (s, length);
813 return lenp;
814}
815
816/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000817size_t
818aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000819{
820 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000821 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000822
823 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000824 return 0;
paulfe69a502005-09-10 16:55:02 +0000825
826 if (seg)
827 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000828 /*
829 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
830 * At the moment, we would write out a partial aspath, and our peer
831 * will complain and drop the session :-/
832 *
833 * The general assumption here is that many things tested will
834 * never happen. And, in real live, up to now, they have not.
835 */
836 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000837 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000838 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000839 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000840 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000841 size_t lenp;
842
843 /* Overlength segments have to be split up */
844 while ( (seg->length - written) > AS_SEGMENT_MAX)
845 {
846 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000847 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000848 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000849 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000850 }
851
852 /* write the final segment, probably is also the first */
853 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000854 assegment_data_put (s, (seg->as + written), seg->length - written,
855 use32bit);
paulfe69a502005-09-10 16:55:02 +0000856
857 /* Sequence-type segments can be 'packed' together
858 * Case of a segment which was overlength and split up
859 * will be missed here, but that doesn't matter.
860 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000861 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000862 {
863 /* NB: We should never normally get here given we
864 * normalise aspath data when parse them. However, better
865 * safe than sorry. We potentially could call
866 * assegment_normalise here instead, but it's cheaper and
867 * easier to do it on the fly here rather than go through
868 * the segment list twice every time we write out
869 * aspath's.
870 */
871
872 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000873 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000874
875 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000876 stream_putc_at (s, lenp, seg->length - written + next->length);
877 asns_packed += next->length;
878
879 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000880 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000881
882 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
883 use32bit);
884 seg = next;
paulfe69a502005-09-10 16:55:02 +0000885 }
886 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000887 return bytes;
paulfe69a502005-09-10 16:55:02 +0000888}
889
890/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
891 * We have no way to manage the storage, so we use a static stream
892 * wrapper around aspath_put.
893 */
894u_char *
895aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
896{
897#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000898
899 if (!snmp_stream)
900 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000901 else
paul8fdc32a2006-01-16 12:01:29 +0000902 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000903
904 if (!as)
905 {
906 *varlen = 0;
907 return NULL;
908 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000909 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000910
paul8fdc32a2006-01-16 12:01:29 +0000911 *varlen = stream_get_endp (snmp_stream);
912 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000913}
914
915#define min(A,B) ((A) < (B) ? (A) : (B))
916
paul94f2b392005-06-28 12:44:16 +0000917static struct assegment *
paul718e3742002-12-13 20:15:29 +0000918aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
919 as_t as)
920{
921 int i;
922
923 /* If this is first AS set member, create new as-set segment. */
924 if (asset == NULL)
925 {
paulfe69a502005-09-10 16:55:02 +0000926 asset = assegment_new (AS_SET, 1);
927 if (! aspath->segments)
928 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000929 else
paulfe69a502005-09-10 16:55:02 +0000930 {
931 struct assegment *seg = aspath->segments;
932 while (seg->next)
933 seg = seg->next;
934 seg->next = asset;
935 }
paul718e3742002-12-13 20:15:29 +0000936 asset->type = AS_SET;
937 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000938 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000939 }
940 else
941 {
paul718e3742002-12-13 20:15:29 +0000942 /* Check this AS value already exists or not. */
943 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000944 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000945 return asset;
paulfe69a502005-09-10 16:55:02 +0000946
paul718e3742002-12-13 20:15:29 +0000947 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000948 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
949 asset->length * AS_VALUE_SIZE);
950 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000951 }
paulfe69a502005-09-10 16:55:02 +0000952
paul718e3742002-12-13 20:15:29 +0000953
954 return asset;
955}
956
957/* Modify as1 using as2 for aggregation. */
958struct aspath *
959aspath_aggregate (struct aspath *as1, struct aspath *as2)
960{
961 int i;
962 int minlen;
963 int match;
paulfe69a502005-09-10 16:55:02 +0000964 int from;
965 struct assegment *seg1 = as1->segments;
966 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000967 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000968 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000969 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +0000970
971 match = 0;
972 minlen = 0;
973 aspath = NULL;
974 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000975
976 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000977 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000978 {
paul718e3742002-12-13 20:15:29 +0000979 /* Check segment type. */
980 if (seg1->type != seg2->type)
981 break;
982
983 /* Minimum segment length. */
984 minlen = min (seg1->length, seg2->length);
985
986 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +0000987 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +0000988 break;
989
990 if (match)
991 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000992 struct assegment *seg = assegment_new (seg1->type, 0);
993
994 seg = assegment_append_asns (seg, seg1->as, match);
995
paul718e3742002-12-13 20:15:29 +0000996 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000997 {
998 aspath = aspath_new ();
999 aspath->segments = seg;
1000 }
1001 else
1002 prevseg->next = seg;
1003
1004 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001005 }
1006
1007 if (match != minlen || match != seg1->length
1008 || seg1->length != seg2->length)
1009 break;
paulfe69a502005-09-10 16:55:02 +00001010
1011 seg1 = seg1->next;
1012 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001013 }
1014
1015 if (! aspath)
1016 aspath = aspath_new();
1017
1018 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001019 from = match;
1020 while (seg1)
paul718e3742002-12-13 20:15:29 +00001021 {
paulfe69a502005-09-10 16:55:02 +00001022 for (i = from; i < seg1->length; i++)
1023 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1024
1025 from = 0;
1026 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001027 }
1028
paulfe69a502005-09-10 16:55:02 +00001029 from = match;
1030 while (seg2)
paul718e3742002-12-13 20:15:29 +00001031 {
paulfe69a502005-09-10 16:55:02 +00001032 for (i = from; i < seg2->length; i++)
1033 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001034
paulfe69a502005-09-10 16:55:02 +00001035 from = 0;
1036 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001037 }
paulfe69a502005-09-10 16:55:02 +00001038
1039 assegment_normalise (aspath->segments);
1040 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001041 return aspath;
1042}
1043
1044/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1045 attribute, check the leftmost AS number in the AS_PATH attribute is
1046 or not the peer's AS number. */
1047int
1048aspath_firstas_check (struct aspath *aspath, as_t asno)
1049{
paulfe69a502005-09-10 16:55:02 +00001050 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001051 return 0;
paulfe69a502005-09-10 16:55:02 +00001052
1053 if (aspath->segments
1054 && (aspath->segments->type == AS_SEQUENCE)
1055 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001056 return 1;
1057
1058 return 0;
1059}
1060
Paul Jakma1f742f22006-08-06 15:52:11 +00001061/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001062int
1063aspath_loop_check (struct aspath *aspath, as_t asno)
1064{
paulfe69a502005-09-10 16:55:02 +00001065 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001066 int count = 0;
1067
Paul Jakma1f742f22006-08-06 15:52:11 +00001068 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001069 return 0;
paulfe69a502005-09-10 16:55:02 +00001070
1071 seg = aspath->segments;
1072
1073 while (seg)
paul718e3742002-12-13 20:15:29 +00001074 {
1075 int i;
paul718e3742002-12-13 20:15:29 +00001076
paulfe69a502005-09-10 16:55:02 +00001077 for (i = 0; i < seg->length; i++)
1078 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001079 count++;
paulfe69a502005-09-10 16:55:02 +00001080
1081 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001082 }
1083 return count;
1084}
1085
1086/* When all of AS path is private AS return 1. */
1087int
1088aspath_private_as_check (struct aspath *aspath)
1089{
paulfe69a502005-09-10 16:55:02 +00001090 struct assegment *seg;
1091
1092 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001093 return 0;
paulfe69a502005-09-10 16:55:02 +00001094
1095 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001096
paulfe69a502005-09-10 16:55:02 +00001097 while (seg)
paul718e3742002-12-13 20:15:29 +00001098 {
1099 int i;
paul718e3742002-12-13 20:15:29 +00001100
paulfe69a502005-09-10 16:55:02 +00001101 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001102 {
paulfe69a502005-09-10 16:55:02 +00001103 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1104 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001105 return 0;
1106 }
paulfe69a502005-09-10 16:55:02 +00001107 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001108 }
1109 return 1;
1110}
1111
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001112/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1113int
1114aspath_confed_check (struct aspath *aspath)
1115{
1116 struct assegment *seg;
1117
1118 if ( !(aspath && aspath->segments) )
1119 return 0;
1120
1121 seg = aspath->segments;
1122
1123 while (seg)
1124 {
1125 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1126 return 1;
1127 seg = seg->next;
1128 }
1129 return 0;
1130}
1131
1132/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1133 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1134int
1135aspath_left_confed_check (struct aspath *aspath)
1136{
1137
1138 if ( !(aspath && aspath->segments) )
1139 return 0;
1140
1141 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1142 || (aspath->segments->type == AS_CONFED_SET) )
1143 return 1;
1144
1145 return 0;
1146}
1147
paul718e3742002-12-13 20:15:29 +00001148/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001149static struct aspath *
paul718e3742002-12-13 20:15:29 +00001150aspath_merge (struct aspath *as1, struct aspath *as2)
1151{
paulfe69a502005-09-10 16:55:02 +00001152 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001153
1154 if (! as1 || ! as2)
1155 return NULL;
1156
paulfe69a502005-09-10 16:55:02 +00001157 last = new = assegment_dup_all (as1->segments);
1158
1159 /* find the last valid segment */
1160 while (last && last->next)
1161 last = last->next;
1162
1163 last->next = as2->segments;
1164 as2->segments = new;
1165 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001166 return as2;
1167}
1168
1169/* Prepend as1 to as2. as2 should be uninterned aspath. */
1170struct aspath *
1171aspath_prepend (struct aspath *as1, struct aspath *as2)
1172{
paulfe69a502005-09-10 16:55:02 +00001173 struct assegment *seg1;
1174 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001175
1176 if (! as1 || ! as2)
1177 return NULL;
paulfe69a502005-09-10 16:55:02 +00001178
1179 seg1 = as1->segments;
1180 seg2 = as2->segments;
1181
1182 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001183 if (seg2 == NULL)
1184 {
paulfe69a502005-09-10 16:55:02 +00001185 as2->segments = assegment_dup_all (as1->segments);
1186 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001187 return as2;
1188 }
paulfe69a502005-09-10 16:55:02 +00001189
1190 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001191 if (seg1 == NULL)
1192 return as2;
paulfe69a502005-09-10 16:55:02 +00001193
1194 /* find the tail as1's segment chain. */
1195 while (seg1 && seg1->next)
1196 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001197
Vasilis Tsiligiannis736d4402009-07-20 01:59:10 +03001198 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1199 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1200 as2 = aspath_delete_confed_seq (as2);
1201
paul718e3742002-12-13 20:15:29 +00001202 /* Compare last segment type of as1 and first segment type of as2. */
1203 if (seg1->type != seg2->type)
1204 return aspath_merge (as1, as2);
1205
1206 if (seg1->type == AS_SEQUENCE)
1207 {
paulfe69a502005-09-10 16:55:02 +00001208 /* We have two chains of segments, as1->segments and seg2,
1209 * and we have to attach them together, merging the attaching
1210 * segments together into one.
1211 *
1212 * 1. dupe as1->segments onto head of as2
1213 * 2. merge seg2's asns onto last segment of this new chain
1214 * 3. attach chain after seg2
1215 */
paul718e3742002-12-13 20:15:29 +00001216
paulfe69a502005-09-10 16:55:02 +00001217 /* dupe as1 onto as2's head */
1218 seg1 = as2->segments = assegment_dup_all (as1->segments);
1219
1220 /* refind the tail of as2, reusing seg1 */
1221 while (seg1 && seg1->next)
1222 seg1 = seg1->next;
1223
1224 /* merge the old head, seg2, into tail, seg1 */
1225 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1226
1227 /* bypass the merged seg2, and attach any chain after it to
1228 * chain descending from as2's head
1229 */
1230 seg1->next = seg2->next;
1231
1232 /* seg2 is now referenceless and useless*/
1233 assegment_free (seg2);
1234
1235 /* we've now prepended as1's segment chain to as2, merging
1236 * the inbetween AS_SEQUENCE of seg2 in the process
1237 */
1238 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001239 return as2;
1240 }
1241 else
1242 {
1243 /* AS_SET merge code is needed at here. */
1244 return aspath_merge (as1, as2);
1245 }
paulfe69a502005-09-10 16:55:02 +00001246 /* XXX: Ermmm, what if as1 has multiple segments?? */
1247
paul718e3742002-12-13 20:15:29 +00001248 /* Not reached */
1249}
1250
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001251/* Iterate over AS_PATH segments and wipe all occurences of the
1252 * listed AS numbers. Hence some segments may lose some or even
1253 * all data on the way, the operation is implemented as a smarter
1254 * version of aspath_dup(), which allocates memory to hold the new
1255 * data, not the original. The new AS path is returned.
1256 */
1257struct aspath *
1258aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1259{
1260 struct assegment * srcseg, * exclseg, * lastseg;
1261 struct aspath * newpath;
1262
1263 newpath = aspath_new();
1264 lastseg = NULL;
1265
1266 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1267 {
1268 unsigned i, y, newlen = 0, done = 0, skip_as;
1269 struct assegment * newseg;
1270
1271 /* Find out, how much ASns are we going to pick from this segment.
1272 * We can't perform filtering right inline, because the size of
1273 * the new segment isn't known at the moment yet.
1274 */
1275 for (i = 0; i < srcseg->length; i++)
1276 {
1277 skip_as = 0;
1278 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1279 for (y = 0; y < exclseg->length; y++)
1280 if (srcseg->as[i] == exclseg->as[y])
1281 {
1282 skip_as = 1;
1283 // There's no sense in testing the rest of exclusion list, bail out.
1284 break;
1285 }
1286 if (!skip_as)
1287 newlen++;
1288 }
1289 /* newlen is now the number of ASns to copy */
1290 if (!newlen)
1291 continue;
1292
1293 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1294 newseg = assegment_new (srcseg->type, newlen);
1295 for (i = 0; i < srcseg->length; i++)
1296 {
1297 skip_as = 0;
1298 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1299 for (y = 0; y < exclseg->length; y++)
1300 if (srcseg->as[i] == exclseg->as[y])
1301 {
1302 skip_as = 1;
1303 break;
1304 }
1305 if (skip_as)
1306 continue;
1307 newseg->as[done++] = srcseg->as[i];
1308 }
1309 /* At his point newlen must be equal to done, and both must be positive. Append
1310 * the filtered segment to the gross result. */
1311 if (!lastseg)
1312 newpath->segments = newseg;
1313 else
1314 lastseg->next = newseg;
1315 lastseg = newseg;
1316 }
1317 aspath_str_update (newpath);
1318 /* We are happy returning even an empty AS_PATH, because the administrator
1319 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1320 * by having a match rule against certain AS_PATH regexps in the route-map index.
1321 */
1322 aspath_free (source);
1323 return newpath;
1324}
1325
paul718e3742002-12-13 20:15:29 +00001326/* Add specified AS to the leftmost of aspath. */
1327static struct aspath *
1328aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1329{
paulfe69a502005-09-10 16:55:02 +00001330 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001331
1332 /* In case of empty aspath. */
1333 if (assegment == NULL || assegment->length == 0)
1334 {
paulfe69a502005-09-10 16:55:02 +00001335 aspath->segments = assegment_new (type, 1);
1336 aspath->segments->as[0] = asno;
1337
paul718e3742002-12-13 20:15:29 +00001338 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001339 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001340
1341 return aspath;
1342 }
1343
1344 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001345 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1346 else
paul718e3742002-12-13 20:15:29 +00001347 {
paulfe69a502005-09-10 16:55:02 +00001348 /* create new segment
1349 * push it onto head of aspath's segment chain
1350 */
paul718e3742002-12-13 20:15:29 +00001351 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001352
1353 newsegment = assegment_new (type, 1);
1354 newsegment->as[0] = asno;
1355
1356 newsegment->next = assegment;
1357 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001358 }
1359
1360 return aspath;
1361}
1362
1363/* Add specified AS to the leftmost of aspath. */
1364struct aspath *
1365aspath_add_seq (struct aspath *aspath, as_t asno)
1366{
1367 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1368}
1369
1370/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1371 as2's leftmost AS is same return 1. */
1372int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001373aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001374{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001375 const struct assegment *seg1 = NULL;
1376 const struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001377
paulfe69a502005-09-10 16:55:02 +00001378 if (!(aspath1 && aspath2))
1379 return 0;
paul718e3742002-12-13 20:15:29 +00001380
paulfe69a502005-09-10 16:55:02 +00001381 seg1 = aspath1->segments;
1382 seg2 = aspath2->segments;
1383
1384 /* find first non-confed segments for each */
1385 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1386 || (seg1->type == AS_CONFED_SET)))
1387 seg1 = seg1->next;
1388
1389 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1390 || (seg2->type == AS_CONFED_SET)))
1391 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001392
1393 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001394 if (!(seg1 && seg2
1395 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001396 return 0;
paulfe69a502005-09-10 16:55:02 +00001397
1398 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001399 return 1;
1400
1401 return 0;
1402}
1403
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001404/* Truncate an aspath after a number of hops, and put the hops remaining
1405 * at the front of another aspath. Needed for AS4 compat.
1406 *
1407 * Returned aspath is a /new/ aspath, which should either by free'd or
1408 * interned by the caller, as desired.
1409 */
1410struct aspath *
1411aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1412{
1413 struct assegment *seg, *newseg, *prevseg = NULL;
1414 struct aspath *newpath = NULL, *mergedpath;
1415 int hops, cpasns = 0;
1416
1417 if (!aspath)
1418 return NULL;
1419
1420 seg = aspath->segments;
1421
1422 /* CONFEDs should get reconciled too.. */
1423 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1424 - aspath_count_hops (as4path);
1425
1426 if (hops < 0)
1427 {
1428 if (BGP_DEBUG (as4, AS4))
1429 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1430 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1431 * which is daft behaviour - it contains vital loop-detection
1432 * information which must have been removed from AS_PATH.
1433 */
1434 hops = aspath_count_hops (aspath);
1435 }
1436
1437 if (!hops)
1438 return aspath_dup (as4path);
1439
1440 if ( BGP_DEBUG(as4, AS4))
1441 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1442 aspath->str, as4path->str);
1443
1444 while (seg && hops > 0)
1445 {
1446 switch (seg->type)
1447 {
1448 case AS_SET:
1449 case AS_CONFED_SET:
1450 hops--;
1451 cpasns = seg->length;
1452 break;
1453 case AS_CONFED_SEQUENCE:
1454 /* Should never split a confed-sequence, if hop-count
1455 * suggests we must then something's gone wrong somewhere.
1456 *
1457 * Most important goal is to preserve AS_PATHs prime function
1458 * as loop-detector, so we fudge the numbers so that the entire
1459 * confed-sequence is merged in.
1460 */
1461 if (hops < seg->length)
1462 {
1463 if (BGP_DEBUG (as4, AS4))
1464 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1465 " across 2/4 ASN boundary somewhere, broken..");
1466 hops = seg->length;
1467 }
1468 case AS_SEQUENCE:
1469 cpasns = MIN(seg->length, hops);
1470 hops -= seg->length;
1471 }
1472
1473 assert (cpasns <= seg->length);
1474
1475 newseg = assegment_new (seg->type, 0);
1476 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1477
1478 if (!newpath)
1479 {
1480 newpath = aspath_new ();
1481 newpath->segments = newseg;
1482 }
1483 else
1484 prevseg->next = newseg;
1485
1486 prevseg = newseg;
1487 seg = seg->next;
1488 }
1489
1490 /* We may be able to join some segments here, and we must
1491 * do this because... we want normalised aspaths in out hash
1492 * and we do not want to stumble in aspath_put.
1493 */
1494 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1495 aspath_free (newpath);
1496 mergedpath->segments = assegment_normalise (mergedpath->segments);
1497 aspath_str_update (mergedpath);
1498
1499 if ( BGP_DEBUG(as4, AS4))
1500 zlog_debug ("[AS4] result of synthesizing is %s",
1501 mergedpath->str);
1502
1503 return mergedpath;
1504}
1505
paul718e3742002-12-13 20:15:29 +00001506/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1507 as2's leftmost AS is same return 1. (confederation as-path
1508 only). */
1509int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001510aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001511{
paulfe69a502005-09-10 16:55:02 +00001512 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001513 return 0;
paulfe69a502005-09-10 16:55:02 +00001514
paulad727402005-11-23 02:47:02 +00001515 if ( !(aspath1->segments && aspath2->segments) )
1516 return 0;
1517
paulfe69a502005-09-10 16:55:02 +00001518 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1519 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001520 return 0;
paulfe69a502005-09-10 16:55:02 +00001521
1522 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001523 return 1;
1524
1525 return 0;
1526}
1527
paulfe69a502005-09-10 16:55:02 +00001528/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1529 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001530struct aspath *
1531aspath_delete_confed_seq (struct aspath *aspath)
1532{
paulfe69a502005-09-10 16:55:02 +00001533 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001534
paulfe69a502005-09-10 16:55:02 +00001535 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001536 return aspath;
1537
paulfe69a502005-09-10 16:55:02 +00001538 seg = aspath->segments;
1539
1540 /* "if the first path segment of the AS_PATH is
1541 * of type AS_CONFED_SEQUENCE,"
1542 */
1543 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1544 return aspath;
paul718e3742002-12-13 20:15:29 +00001545
paulfe69a502005-09-10 16:55:02 +00001546 /* "... that segment and any immediately following segments
1547 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1548 * from the AS_PATH attribute,"
1549 */
1550 while (seg &&
1551 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001552 {
paulfe69a502005-09-10 16:55:02 +00001553 aspath->segments = seg->next;
1554 assegment_free (seg);
1555 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001556 }
paulfe69a502005-09-10 16:55:02 +00001557 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001558 return aspath;
1559}
1560
1561/* Add new AS number to the leftmost part of the aspath as
1562 AS_CONFED_SEQUENCE. */
1563struct aspath*
1564aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1565{
1566 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1567}
1568
1569/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001570static void
paul718e3742002-12-13 20:15:29 +00001571aspath_as_add (struct aspath *as, as_t asno)
1572{
paulfe69a502005-09-10 16:55:02 +00001573 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001574
paulfe69a502005-09-10 16:55:02 +00001575 if (!seg)
1576 return;
1577
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001578 /* Last segment search procedure. */
1579 while (seg->next)
1580 seg = seg->next;
1581
paulfe69a502005-09-10 16:55:02 +00001582 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001583}
1584
1585/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001586static void
paul718e3742002-12-13 20:15:29 +00001587aspath_segment_add (struct aspath *as, int type)
1588{
paulfe69a502005-09-10 16:55:02 +00001589 struct assegment *seg = as->segments;
1590 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001591
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001592 if (seg)
1593 {
1594 while (seg->next)
1595 seg = seg->next;
1596 seg->next = new;
1597 }
paul718e3742002-12-13 20:15:29 +00001598 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001599 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001600}
1601
1602struct aspath *
paul94f2b392005-06-28 12:44:16 +00001603aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001604{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001605 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001606}
1607
1608struct aspath *
paul94f2b392005-06-28 12:44:16 +00001609aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001610{
1611 struct aspath *aspath;
1612
1613 aspath = aspath_new ();
1614 aspath->str = aspath_make_str_count (aspath);
1615 return aspath;
1616}
1617
1618unsigned long
paulfe69a502005-09-10 16:55:02 +00001619aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001620{
1621 return ashash->count;
1622}
1623
1624/*
1625 Theoretically, one as path can have:
1626
1627 One BGP packet size should be less than 4096.
1628 One BGP attribute size should be less than 4096 - BGP header size.
1629 One BGP aspath size should be less than 4096 - BGP header size -
1630 BGP mandantry attribute size.
1631*/
1632
1633/* AS path string lexical token enum. */
1634enum as_token
1635{
1636 as_token_asval,
1637 as_token_set_start,
1638 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001639 as_token_confed_seq_start,
1640 as_token_confed_seq_end,
1641 as_token_confed_set_start,
1642 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001643 as_token_unknown
1644};
1645
1646/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001647static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001648aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001649{
paulfd79ac92004-10-13 05:06:08 +00001650 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001651
paulfe69a502005-09-10 16:55:02 +00001652 /* Skip seperators (space for sequences, ',' for sets). */
1653 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001654 p++;
1655
1656 /* Check the end of the string and type specify characters
1657 (e.g. {}()). */
1658 switch (*p)
1659 {
1660 case '\0':
1661 return NULL;
paul718e3742002-12-13 20:15:29 +00001662 case '{':
1663 *token = as_token_set_start;
1664 p++;
1665 return p;
paul718e3742002-12-13 20:15:29 +00001666 case '}':
1667 *token = as_token_set_end;
1668 p++;
1669 return p;
paul718e3742002-12-13 20:15:29 +00001670 case '(':
paulfe69a502005-09-10 16:55:02 +00001671 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001672 p++;
1673 return p;
paul718e3742002-12-13 20:15:29 +00001674 case ')':
paulfe69a502005-09-10 16:55:02 +00001675 *token = as_token_confed_seq_end;
1676 p++;
1677 return p;
paulfe69a502005-09-10 16:55:02 +00001678 case '[':
1679 *token = as_token_confed_set_start;
1680 p++;
1681 return p;
paulfe69a502005-09-10 16:55:02 +00001682 case ']':
1683 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001684 p++;
1685 return p;
paul718e3742002-12-13 20:15:29 +00001686 }
1687
1688 /* Check actual AS value. */
1689 if (isdigit ((int) *p))
1690 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001691 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001692
paul718e3742002-12-13 20:15:29 +00001693 *token = as_token_asval;
1694 asval = (*p - '0');
1695 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001696
paul718e3742002-12-13 20:15:29 +00001697 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001698 {
1699 asval *= 10;
1700 asval += (*p - '0');
1701 p++;
1702 }
paul718e3742002-12-13 20:15:29 +00001703 *asno = asval;
1704 return p;
1705 }
1706
1707 /* There is no match then return unknown token. */
1708 *token = as_token_unknown;
1709 return p++;
1710}
1711
1712struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001713aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001714{
paul3fff6ff2006-02-05 17:55:35 +00001715 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001716 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001717 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001718 struct aspath *aspath;
1719 int needtype;
1720
1721 aspath = aspath_new ();
1722
1723 /* We start default type as AS_SEQUENCE. */
1724 as_type = AS_SEQUENCE;
1725 needtype = 1;
1726
1727 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1728 {
1729 switch (token)
1730 {
1731 case as_token_asval:
1732 if (needtype)
1733 {
1734 aspath_segment_add (aspath, as_type);
1735 needtype = 0;
1736 }
1737 aspath_as_add (aspath, asno);
1738 break;
1739 case as_token_set_start:
1740 as_type = AS_SET;
1741 aspath_segment_add (aspath, as_type);
1742 needtype = 0;
1743 break;
1744 case as_token_set_end:
1745 as_type = AS_SEQUENCE;
1746 needtype = 1;
1747 break;
paulfe69a502005-09-10 16:55:02 +00001748 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001749 as_type = AS_CONFED_SEQUENCE;
1750 aspath_segment_add (aspath, as_type);
1751 needtype = 0;
1752 break;
paulfe69a502005-09-10 16:55:02 +00001753 case as_token_confed_seq_end:
1754 as_type = AS_SEQUENCE;
1755 needtype = 1;
1756 break;
1757 case as_token_confed_set_start:
1758 as_type = AS_CONFED_SET;
1759 aspath_segment_add (aspath, as_type);
1760 needtype = 0;
1761 break;
1762 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001763 as_type = AS_SEQUENCE;
1764 needtype = 1;
1765 break;
1766 case as_token_unknown:
1767 default:
paulfe69a502005-09-10 16:55:02 +00001768 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001769 return NULL;
paul718e3742002-12-13 20:15:29 +00001770 }
1771 }
1772
1773 aspath->str = aspath_make_str_count (aspath);
1774
1775 return aspath;
1776}
1777
1778/* Make hash value by raw aspath data. */
1779unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001780aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001781{
Paul Jakma923de652007-04-29 18:25:17 +00001782 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001783 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001784
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001785 if (!aspath->str)
1786 aspath_str_update (aspath);
1787
1788 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001789
1790 return key;
1791}
1792
1793/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001794static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001795aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001796{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001797 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1798 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001799
1800 while (seg1 || seg2)
1801 {
1802 int i;
1803 if ((!seg1 && seg2) || (seg1 && !seg2))
1804 return 0;
1805 if (seg1->type != seg2->type)
1806 return 0;
1807 if (seg1->length != seg2->length)
1808 return 0;
1809 for (i = 0; i < seg1->length; i++)
1810 if (seg1->as[i] != seg2->as[i])
1811 return 0;
1812 seg1 = seg1->next;
1813 seg2 = seg2->next;
1814 }
1815 return 1;
paul718e3742002-12-13 20:15:29 +00001816}
1817
1818/* AS path hash initialize. */
1819void
paul94f2b392005-06-28 12:44:16 +00001820aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001821{
1822 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1823}
paul8fdc32a2006-01-16 12:01:29 +00001824
1825void
1826aspath_finish (void)
1827{
1828 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00001829 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00001830
1831 if (snmp_stream)
1832 stream_free (snmp_stream);
1833}
paul718e3742002-12-13 20:15:29 +00001834
1835/* return and as path value */
1836const char *
1837aspath_print (struct aspath *as)
1838{
paulfe69a502005-09-10 16:55:02 +00001839 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001840}
1841
1842/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001843/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1844 * AS_PATH wasn't empty.
1845 */
paul718e3742002-12-13 20:15:29 +00001846void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001847aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001848{
Paul Jakmab2518c12006-05-12 23:48:40 +00001849 assert (format);
1850 vty_out (vty, format, as->str);
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001851 if (strlen (as->str) && strlen (suffix))
1852 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001853}
1854
paul94f2b392005-06-28 12:44:16 +00001855static void
paul718e3742002-12-13 20:15:29 +00001856aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1857{
1858 struct aspath *as;
1859
1860 as = (struct aspath *) backet->data;
1861
paulefa9f832002-12-13 21:47:59 +00001862 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001863 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1864}
1865
1866/* Print all aspath and hash information. This function is used from
1867 `show ip bgp paths' command. */
1868void
1869aspath_print_all_vty (struct vty *vty)
1870{
1871 hash_iterate (ashash,
1872 (void (*) (struct hash_backet *, void *))
1873 aspath_show_all_iterator,
1874 vty);
1875}