blob: 89a27531851c0a76ccac0a8d0361ae3ea4728b53 [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
Paul Jakmaab005292010-11-27 22:48:34 +0000674/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000675static struct assegment *
Paul Jakmaab005292010-11-27 22:48:34 +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;
Paul Jakmaab005292010-11-27 22:48:34 +0000680 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000681
Paul Jakmaab005292010-11-27 22:48:34 +0000682 /* empty aspath (ie iBGP or somesuch) */
683 if (length == 0)
684 return NULL;
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);
Paul Jakmaab005292010-11-27 22:48:34 +0000689 /* basic checks */
690 if ((STREAM_READABLE(s) < length)
691 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
692 || (length % AS16_VALUE_SIZE ))
paulfe69a502005-09-10 16:55:02 +0000693 return NULL;
694
Paul Jakmaab005292010-11-27 22:48:34 +0000695 while (bytes < length)
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
Paul Jakmaab005292010-11-27 22:48:34 +0000700 if ((length - bytes) <= AS_HEADER_SIZE)
Chris Hallcddb8112010-08-09 22:31:37 +0400701 {
Paul Jakmaab005292010-11-27 22:48:34 +0000702 if (head)
703 assegment_free_all (head);
704 return NULL;
705 }
706
707 /* softly softly, get the header first on its own */
paulfe69a502005-09-10 16:55:02 +0000708 segh.type = stream_getc (s);
709 segh.length = stream_getc (s);
710
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000711 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
712
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 Jakmaab005292010-11-27 22:48:34 +0000717 /* check it.. */
718 if ( ((bytes + seg_size) > length)
719 /* 1771bis 4.3b: seg length contains one or more */
720 || (segh.length == 0)
721 /* Paranoia in case someone changes type of segment length.
722 * Shift both values by 0x10 to make the comparison operate
723 * on more, than 8 bits (otherwise it's a warning, bug #564).
Denis Ovsienko2eb445e2009-12-04 17:32:54 +0300724 */
Paul Jakmaab005292010-11-27 22:48:34 +0000725 || ((sizeof segh.length > 1)
726 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
paulfe69a502005-09-10 16:55:02 +0000727 {
Paul Jakmaab005292010-11-27 22:48:34 +0000728 if (head)
paulfe69a502005-09-10 16:55:02 +0000729 assegment_free_all (head);
730 return NULL;
731 }
732
Paul Jakmaab005292010-11-27 22:48:34 +0000733 switch (segh.type)
734 {
735 case AS_SEQUENCE:
736 case AS_SET:
737 case AS_CONFED_SEQUENCE:
738 case AS_CONFED_SET:
739 break;
740 default:
741 if (head)
742 assegment_free_all (head);
743 return NULL;
744 }
Chris Hallcddb8112010-08-09 22:31:37 +0400745
paulfe69a502005-09-10 16:55:02 +0000746 /* now its safe to trust lengths */
747 seg = assegment_new (segh.type, segh.length);
748
749 if (head)
750 prev->next = seg;
751 else /* it's the first segment */
752 head = prev = seg;
753
754 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000755 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
756
Paul Jakmaab005292010-11-27 22:48:34 +0000757 bytes += seg_size;
758
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000759 if (BGP_DEBUG (as4, AS4_SEGMENT))
Paul Jakmaab005292010-11-27 22:48:34 +0000760 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
761 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000762
763 prev = seg;
764 }
765
766 return assegment_normalise (head);
767}
768
Paul Jakmaab005292010-11-27 22:48:34 +0000769/* AS path parse function. pnt is a pointer to byte stream and length
770 is length of byte stream. If there is same AS path in the the AS
771 path hash then return it else make new AS path structure. */
paul718e3742002-12-13 20:15:29 +0000772struct aspath *
Paul Jakmaab005292010-11-27 22:48:34 +0000773aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000774{
775 struct aspath as;
776 struct aspath *find;
777
Paul Jakmaab005292010-11-27 22:48:34 +0000778 /* If length is odd it's malformed AS path. */
779 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
780 * otherwise its malformed when length is larger than 2 and (length-2)
781 * is not dividable by 4.
782 * But... this time we're lazy
783 */
784 if (length % AS16_VALUE_SIZE )
785 return NULL;
Chris Hallcddb8112010-08-09 22:31:37 +0400786
Paul Jakmaab005292010-11-27 22:48:34 +0000787 memset (&as, 0, sizeof (struct aspath));
788 as.segments = assegments_parse (s, length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000789
paul718e3742002-12-13 20:15:29 +0000790 /* If already same aspath exist then return it. */
791 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000792
793 /* aspath_hash_alloc dupes segments too. that probably could be
794 * optimised out.
795 */
796 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000797 if (as.str)
798 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000799
Paul Jakmaab005292010-11-27 22:48:34 +0000800 if (! find)
801 return NULL;
paul718e3742002-12-13 20:15:29 +0000802 find->refcnt++;
803
804 return find;
805}
806
paulfe69a502005-09-10 16:55:02 +0000807static inline void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000808assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000809{
paulfe69a502005-09-10 16:55:02 +0000810 int i;
811 assert (num <= AS_SEGMENT_MAX);
812
813 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000814 if ( use32bit )
815 stream_putl (s, as[i]);
816 else
817 {
818 if ( as[i] <= BGP_AS_MAX )
819 stream_putw(s, as[i]);
820 else
821 stream_putw(s, BGP_AS_TRANS);
822 }
paul718e3742002-12-13 20:15:29 +0000823}
824
paulfe69a502005-09-10 16:55:02 +0000825static inline size_t
826assegment_header_put (struct stream *s, u_char type, int length)
827{
828 size_t lenp;
829 assert (length <= AS_SEGMENT_MAX);
830 stream_putc (s, type);
831 lenp = stream_get_endp (s);
832 stream_putc (s, length);
833 return lenp;
834}
835
836/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000837size_t
838aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000839{
840 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000841 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000842
843 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000844 return 0;
paulfe69a502005-09-10 16:55:02 +0000845
846 if (seg)
847 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000848 /*
849 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
850 * At the moment, we would write out a partial aspath, and our peer
851 * will complain and drop the session :-/
852 *
853 * The general assumption here is that many things tested will
854 * never happen. And, in real live, up to now, they have not.
855 */
856 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000857 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000858 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000859 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000860 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000861 size_t lenp;
862
863 /* Overlength segments have to be split up */
864 while ( (seg->length - written) > AS_SEGMENT_MAX)
865 {
866 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000867 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000868 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000869 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000870 }
871
872 /* write the final segment, probably is also the first */
873 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000874 assegment_data_put (s, (seg->as + written), seg->length - written,
875 use32bit);
paulfe69a502005-09-10 16:55:02 +0000876
877 /* Sequence-type segments can be 'packed' together
878 * Case of a segment which was overlength and split up
879 * will be missed here, but that doesn't matter.
880 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000881 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000882 {
883 /* NB: We should never normally get here given we
884 * normalise aspath data when parse them. However, better
885 * safe than sorry. We potentially could call
886 * assegment_normalise here instead, but it's cheaper and
887 * easier to do it on the fly here rather than go through
888 * the segment list twice every time we write out
889 * aspath's.
890 */
891
892 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000893 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000894
895 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000896 stream_putc_at (s, lenp, seg->length - written + next->length);
897 asns_packed += next->length;
898
899 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000900 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000901
902 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
903 use32bit);
904 seg = next;
paulfe69a502005-09-10 16:55:02 +0000905 }
906 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000907 return bytes;
paulfe69a502005-09-10 16:55:02 +0000908}
909
910/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
911 * We have no way to manage the storage, so we use a static stream
912 * wrapper around aspath_put.
913 */
914u_char *
915aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
916{
917#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000918
919 if (!snmp_stream)
920 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000921 else
paul8fdc32a2006-01-16 12:01:29 +0000922 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000923
924 if (!as)
925 {
926 *varlen = 0;
927 return NULL;
928 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000929 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000930
paul8fdc32a2006-01-16 12:01:29 +0000931 *varlen = stream_get_endp (snmp_stream);
932 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000933}
934
935#define min(A,B) ((A) < (B) ? (A) : (B))
936
paul94f2b392005-06-28 12:44:16 +0000937static struct assegment *
paul718e3742002-12-13 20:15:29 +0000938aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
939 as_t as)
940{
941 int i;
942
943 /* If this is first AS set member, create new as-set segment. */
944 if (asset == NULL)
945 {
paulfe69a502005-09-10 16:55:02 +0000946 asset = assegment_new (AS_SET, 1);
947 if (! aspath->segments)
948 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000949 else
paulfe69a502005-09-10 16:55:02 +0000950 {
951 struct assegment *seg = aspath->segments;
952 while (seg->next)
953 seg = seg->next;
954 seg->next = asset;
955 }
paul718e3742002-12-13 20:15:29 +0000956 asset->type = AS_SET;
957 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000958 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000959 }
960 else
961 {
paul718e3742002-12-13 20:15:29 +0000962 /* Check this AS value already exists or not. */
963 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000964 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000965 return asset;
paulfe69a502005-09-10 16:55:02 +0000966
paul718e3742002-12-13 20:15:29 +0000967 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000968 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
969 asset->length * AS_VALUE_SIZE);
970 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000971 }
paulfe69a502005-09-10 16:55:02 +0000972
paul718e3742002-12-13 20:15:29 +0000973
974 return asset;
975}
976
977/* Modify as1 using as2 for aggregation. */
978struct aspath *
979aspath_aggregate (struct aspath *as1, struct aspath *as2)
980{
981 int i;
982 int minlen;
983 int match;
paulfe69a502005-09-10 16:55:02 +0000984 int from;
985 struct assegment *seg1 = as1->segments;
986 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000987 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000988 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000989 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +0000990
991 match = 0;
992 minlen = 0;
993 aspath = NULL;
994 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000995
996 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000997 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000998 {
paul718e3742002-12-13 20:15:29 +0000999 /* Check segment type. */
1000 if (seg1->type != seg2->type)
1001 break;
1002
1003 /* Minimum segment length. */
1004 minlen = min (seg1->length, seg2->length);
1005
1006 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001007 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001008 break;
1009
1010 if (match)
1011 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001012 struct assegment *seg = assegment_new (seg1->type, 0);
1013
1014 seg = assegment_append_asns (seg, seg1->as, match);
1015
paul718e3742002-12-13 20:15:29 +00001016 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001017 {
1018 aspath = aspath_new ();
1019 aspath->segments = seg;
1020 }
1021 else
1022 prevseg->next = seg;
1023
1024 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001025 }
1026
1027 if (match != minlen || match != seg1->length
1028 || seg1->length != seg2->length)
1029 break;
paulfe69a502005-09-10 16:55:02 +00001030
1031 seg1 = seg1->next;
1032 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001033 }
1034
1035 if (! aspath)
1036 aspath = aspath_new();
1037
1038 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001039 from = match;
1040 while (seg1)
paul718e3742002-12-13 20:15:29 +00001041 {
paulfe69a502005-09-10 16:55:02 +00001042 for (i = from; i < seg1->length; i++)
1043 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1044
1045 from = 0;
1046 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001047 }
1048
paulfe69a502005-09-10 16:55:02 +00001049 from = match;
1050 while (seg2)
paul718e3742002-12-13 20:15:29 +00001051 {
paulfe69a502005-09-10 16:55:02 +00001052 for (i = from; i < seg2->length; i++)
1053 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001054
paulfe69a502005-09-10 16:55:02 +00001055 from = 0;
1056 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001057 }
paulfe69a502005-09-10 16:55:02 +00001058
1059 assegment_normalise (aspath->segments);
1060 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001061 return aspath;
1062}
1063
1064/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1065 attribute, check the leftmost AS number in the AS_PATH attribute is
1066 or not the peer's AS number. */
1067int
1068aspath_firstas_check (struct aspath *aspath, as_t asno)
1069{
paulfe69a502005-09-10 16:55:02 +00001070 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001071 return 0;
paulfe69a502005-09-10 16:55:02 +00001072
1073 if (aspath->segments
1074 && (aspath->segments->type == AS_SEQUENCE)
1075 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001076 return 1;
1077
1078 return 0;
1079}
1080
Paul Jakma1f742f22006-08-06 15:52:11 +00001081/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001082int
1083aspath_loop_check (struct aspath *aspath, as_t asno)
1084{
paulfe69a502005-09-10 16:55:02 +00001085 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001086 int count = 0;
1087
Paul Jakma1f742f22006-08-06 15:52:11 +00001088 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001089 return 0;
paulfe69a502005-09-10 16:55:02 +00001090
1091 seg = aspath->segments;
1092
1093 while (seg)
paul718e3742002-12-13 20:15:29 +00001094 {
1095 int i;
paul718e3742002-12-13 20:15:29 +00001096
paulfe69a502005-09-10 16:55:02 +00001097 for (i = 0; i < seg->length; i++)
1098 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001099 count++;
paulfe69a502005-09-10 16:55:02 +00001100
1101 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001102 }
1103 return count;
1104}
1105
1106/* When all of AS path is private AS return 1. */
1107int
1108aspath_private_as_check (struct aspath *aspath)
1109{
paulfe69a502005-09-10 16:55:02 +00001110 struct assegment *seg;
1111
1112 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001113 return 0;
paulfe69a502005-09-10 16:55:02 +00001114
1115 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001116
paulfe69a502005-09-10 16:55:02 +00001117 while (seg)
paul718e3742002-12-13 20:15:29 +00001118 {
1119 int i;
paul718e3742002-12-13 20:15:29 +00001120
paulfe69a502005-09-10 16:55:02 +00001121 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001122 {
paulfe69a502005-09-10 16:55:02 +00001123 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1124 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001125 return 0;
1126 }
paulfe69a502005-09-10 16:55:02 +00001127 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001128 }
1129 return 1;
1130}
1131
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001132/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1133int
1134aspath_confed_check (struct aspath *aspath)
1135{
1136 struct assegment *seg;
1137
1138 if ( !(aspath && aspath->segments) )
1139 return 0;
1140
1141 seg = aspath->segments;
1142
1143 while (seg)
1144 {
1145 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1146 return 1;
1147 seg = seg->next;
1148 }
1149 return 0;
1150}
1151
1152/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1153 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1154int
1155aspath_left_confed_check (struct aspath *aspath)
1156{
1157
1158 if ( !(aspath && aspath->segments) )
1159 return 0;
1160
1161 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1162 || (aspath->segments->type == AS_CONFED_SET) )
1163 return 1;
1164
1165 return 0;
1166}
1167
paul718e3742002-12-13 20:15:29 +00001168/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001169static struct aspath *
paul718e3742002-12-13 20:15:29 +00001170aspath_merge (struct aspath *as1, struct aspath *as2)
1171{
paulfe69a502005-09-10 16:55:02 +00001172 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001173
1174 if (! as1 || ! as2)
1175 return NULL;
1176
paulfe69a502005-09-10 16:55:02 +00001177 last = new = assegment_dup_all (as1->segments);
1178
1179 /* find the last valid segment */
1180 while (last && last->next)
1181 last = last->next;
1182
1183 last->next = as2->segments;
1184 as2->segments = new;
1185 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001186 return as2;
1187}
1188
1189/* Prepend as1 to as2. as2 should be uninterned aspath. */
1190struct aspath *
1191aspath_prepend (struct aspath *as1, struct aspath *as2)
1192{
paulfe69a502005-09-10 16:55:02 +00001193 struct assegment *seg1;
1194 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001195
1196 if (! as1 || ! as2)
1197 return NULL;
paulfe69a502005-09-10 16:55:02 +00001198
1199 seg1 = as1->segments;
1200 seg2 = as2->segments;
1201
1202 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001203 if (seg2 == NULL)
1204 {
paulfe69a502005-09-10 16:55:02 +00001205 as2->segments = assegment_dup_all (as1->segments);
1206 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001207 return as2;
1208 }
paulfe69a502005-09-10 16:55:02 +00001209
1210 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001211 if (seg1 == NULL)
1212 return as2;
paulfe69a502005-09-10 16:55:02 +00001213
1214 /* find the tail as1's segment chain. */
1215 while (seg1 && seg1->next)
1216 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001217
Vasilis Tsiligiannis736d4402009-07-20 01:59:10 +03001218 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1219 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1220 as2 = aspath_delete_confed_seq (as2);
1221
paul718e3742002-12-13 20:15:29 +00001222 /* Compare last segment type of as1 and first segment type of as2. */
1223 if (seg1->type != seg2->type)
1224 return aspath_merge (as1, as2);
1225
1226 if (seg1->type == AS_SEQUENCE)
1227 {
paulfe69a502005-09-10 16:55:02 +00001228 /* We have two chains of segments, as1->segments and seg2,
1229 * and we have to attach them together, merging the attaching
1230 * segments together into one.
1231 *
1232 * 1. dupe as1->segments onto head of as2
1233 * 2. merge seg2's asns onto last segment of this new chain
1234 * 3. attach chain after seg2
1235 */
paul718e3742002-12-13 20:15:29 +00001236
paulfe69a502005-09-10 16:55:02 +00001237 /* dupe as1 onto as2's head */
1238 seg1 = as2->segments = assegment_dup_all (as1->segments);
1239
1240 /* refind the tail of as2, reusing seg1 */
1241 while (seg1 && seg1->next)
1242 seg1 = seg1->next;
1243
1244 /* merge the old head, seg2, into tail, seg1 */
1245 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1246
1247 /* bypass the merged seg2, and attach any chain after it to
1248 * chain descending from as2's head
1249 */
1250 seg1->next = seg2->next;
1251
1252 /* seg2 is now referenceless and useless*/
1253 assegment_free (seg2);
1254
1255 /* we've now prepended as1's segment chain to as2, merging
1256 * the inbetween AS_SEQUENCE of seg2 in the process
1257 */
1258 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001259 return as2;
1260 }
1261 else
1262 {
1263 /* AS_SET merge code is needed at here. */
1264 return aspath_merge (as1, as2);
1265 }
paulfe69a502005-09-10 16:55:02 +00001266 /* XXX: Ermmm, what if as1 has multiple segments?? */
1267
paul718e3742002-12-13 20:15:29 +00001268 /* Not reached */
1269}
1270
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001271/* Iterate over AS_PATH segments and wipe all occurences of the
1272 * listed AS numbers. Hence some segments may lose some or even
1273 * all data on the way, the operation is implemented as a smarter
1274 * version of aspath_dup(), which allocates memory to hold the new
1275 * data, not the original. The new AS path is returned.
1276 */
1277struct aspath *
1278aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1279{
1280 struct assegment * srcseg, * exclseg, * lastseg;
1281 struct aspath * newpath;
1282
1283 newpath = aspath_new();
1284 lastseg = NULL;
1285
1286 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1287 {
1288 unsigned i, y, newlen = 0, done = 0, skip_as;
1289 struct assegment * newseg;
1290
1291 /* Find out, how much ASns are we going to pick from this segment.
1292 * We can't perform filtering right inline, because the size of
1293 * the new segment isn't known at the moment yet.
1294 */
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 // There's no sense in testing the rest of exclusion list, bail out.
1304 break;
1305 }
1306 if (!skip_as)
1307 newlen++;
1308 }
1309 /* newlen is now the number of ASns to copy */
1310 if (!newlen)
1311 continue;
1312
1313 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1314 newseg = assegment_new (srcseg->type, newlen);
1315 for (i = 0; i < srcseg->length; i++)
1316 {
1317 skip_as = 0;
1318 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1319 for (y = 0; y < exclseg->length; y++)
1320 if (srcseg->as[i] == exclseg->as[y])
1321 {
1322 skip_as = 1;
1323 break;
1324 }
1325 if (skip_as)
1326 continue;
1327 newseg->as[done++] = srcseg->as[i];
1328 }
1329 /* At his point newlen must be equal to done, and both must be positive. Append
1330 * the filtered segment to the gross result. */
1331 if (!lastseg)
1332 newpath->segments = newseg;
1333 else
1334 lastseg->next = newseg;
1335 lastseg = newseg;
1336 }
1337 aspath_str_update (newpath);
1338 /* We are happy returning even an empty AS_PATH, because the administrator
1339 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1340 * by having a match rule against certain AS_PATH regexps in the route-map index.
1341 */
1342 aspath_free (source);
1343 return newpath;
1344}
1345
paul718e3742002-12-13 20:15:29 +00001346/* Add specified AS to the leftmost of aspath. */
1347static struct aspath *
1348aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1349{
paulfe69a502005-09-10 16:55:02 +00001350 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001351
1352 /* In case of empty aspath. */
1353 if (assegment == NULL || assegment->length == 0)
1354 {
paulfe69a502005-09-10 16:55:02 +00001355 aspath->segments = assegment_new (type, 1);
1356 aspath->segments->as[0] = asno;
1357
paul718e3742002-12-13 20:15:29 +00001358 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001359 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001360
1361 return aspath;
1362 }
1363
1364 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001365 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1366 else
paul718e3742002-12-13 20:15:29 +00001367 {
paulfe69a502005-09-10 16:55:02 +00001368 /* create new segment
1369 * push it onto head of aspath's segment chain
1370 */
paul718e3742002-12-13 20:15:29 +00001371 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001372
1373 newsegment = assegment_new (type, 1);
1374 newsegment->as[0] = asno;
1375
1376 newsegment->next = assegment;
1377 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001378 }
1379
1380 return aspath;
1381}
1382
1383/* Add specified AS to the leftmost of aspath. */
1384struct aspath *
1385aspath_add_seq (struct aspath *aspath, as_t asno)
1386{
1387 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1388}
1389
1390/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1391 as2's leftmost AS is same return 1. */
1392int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001393aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001394{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001395 const struct assegment *seg1 = NULL;
1396 const struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001397
paulfe69a502005-09-10 16:55:02 +00001398 if (!(aspath1 && aspath2))
1399 return 0;
paul718e3742002-12-13 20:15:29 +00001400
paulfe69a502005-09-10 16:55:02 +00001401 seg1 = aspath1->segments;
1402 seg2 = aspath2->segments;
1403
1404 /* find first non-confed segments for each */
1405 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1406 || (seg1->type == AS_CONFED_SET)))
1407 seg1 = seg1->next;
1408
1409 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1410 || (seg2->type == AS_CONFED_SET)))
1411 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001412
1413 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001414 if (!(seg1 && seg2
1415 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001416 return 0;
paulfe69a502005-09-10 16:55:02 +00001417
1418 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001419 return 1;
1420
1421 return 0;
1422}
1423
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001424/* Truncate an aspath after a number of hops, and put the hops remaining
1425 * at the front of another aspath. Needed for AS4 compat.
1426 *
1427 * Returned aspath is a /new/ aspath, which should either by free'd or
1428 * interned by the caller, as desired.
1429 */
1430struct aspath *
1431aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1432{
1433 struct assegment *seg, *newseg, *prevseg = NULL;
1434 struct aspath *newpath = NULL, *mergedpath;
1435 int hops, cpasns = 0;
1436
1437 if (!aspath)
1438 return NULL;
1439
1440 seg = aspath->segments;
1441
1442 /* CONFEDs should get reconciled too.. */
1443 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1444 - aspath_count_hops (as4path);
1445
1446 if (hops < 0)
1447 {
1448 if (BGP_DEBUG (as4, AS4))
1449 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1450 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1451 * which is daft behaviour - it contains vital loop-detection
1452 * information which must have been removed from AS_PATH.
1453 */
1454 hops = aspath_count_hops (aspath);
1455 }
1456
1457 if (!hops)
1458 return aspath_dup (as4path);
1459
1460 if ( BGP_DEBUG(as4, AS4))
1461 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1462 aspath->str, as4path->str);
1463
1464 while (seg && hops > 0)
1465 {
1466 switch (seg->type)
1467 {
1468 case AS_SET:
1469 case AS_CONFED_SET:
1470 hops--;
1471 cpasns = seg->length;
1472 break;
1473 case AS_CONFED_SEQUENCE:
1474 /* Should never split a confed-sequence, if hop-count
1475 * suggests we must then something's gone wrong somewhere.
1476 *
1477 * Most important goal is to preserve AS_PATHs prime function
1478 * as loop-detector, so we fudge the numbers so that the entire
1479 * confed-sequence is merged in.
1480 */
1481 if (hops < seg->length)
1482 {
1483 if (BGP_DEBUG (as4, AS4))
1484 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1485 " across 2/4 ASN boundary somewhere, broken..");
1486 hops = seg->length;
1487 }
1488 case AS_SEQUENCE:
1489 cpasns = MIN(seg->length, hops);
1490 hops -= seg->length;
1491 }
1492
1493 assert (cpasns <= seg->length);
1494
1495 newseg = assegment_new (seg->type, 0);
1496 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1497
1498 if (!newpath)
1499 {
1500 newpath = aspath_new ();
1501 newpath->segments = newseg;
1502 }
1503 else
1504 prevseg->next = newseg;
1505
1506 prevseg = newseg;
1507 seg = seg->next;
1508 }
1509
1510 /* We may be able to join some segments here, and we must
1511 * do this because... we want normalised aspaths in out hash
1512 * and we do not want to stumble in aspath_put.
1513 */
1514 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1515 aspath_free (newpath);
1516 mergedpath->segments = assegment_normalise (mergedpath->segments);
1517 aspath_str_update (mergedpath);
1518
1519 if ( BGP_DEBUG(as4, AS4))
1520 zlog_debug ("[AS4] result of synthesizing is %s",
1521 mergedpath->str);
1522
1523 return mergedpath;
1524}
1525
paul718e3742002-12-13 20:15:29 +00001526/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1527 as2's leftmost AS is same return 1. (confederation as-path
1528 only). */
1529int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001530aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001531{
paulfe69a502005-09-10 16:55:02 +00001532 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001533 return 0;
paulfe69a502005-09-10 16:55:02 +00001534
paulad727402005-11-23 02:47:02 +00001535 if ( !(aspath1->segments && aspath2->segments) )
1536 return 0;
1537
paulfe69a502005-09-10 16:55:02 +00001538 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1539 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001540 return 0;
paulfe69a502005-09-10 16:55:02 +00001541
1542 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001543 return 1;
1544
1545 return 0;
1546}
1547
paulfe69a502005-09-10 16:55:02 +00001548/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1549 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001550struct aspath *
1551aspath_delete_confed_seq (struct aspath *aspath)
1552{
paulfe69a502005-09-10 16:55:02 +00001553 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001554
paulfe69a502005-09-10 16:55:02 +00001555 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001556 return aspath;
1557
paulfe69a502005-09-10 16:55:02 +00001558 seg = aspath->segments;
1559
1560 /* "if the first path segment of the AS_PATH is
1561 * of type AS_CONFED_SEQUENCE,"
1562 */
1563 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1564 return aspath;
paul718e3742002-12-13 20:15:29 +00001565
paulfe69a502005-09-10 16:55:02 +00001566 /* "... that segment and any immediately following segments
1567 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1568 * from the AS_PATH attribute,"
1569 */
1570 while (seg &&
1571 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001572 {
paulfe69a502005-09-10 16:55:02 +00001573 aspath->segments = seg->next;
1574 assegment_free (seg);
1575 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001576 }
paulfe69a502005-09-10 16:55:02 +00001577 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001578 return aspath;
1579}
1580
1581/* Add new AS number to the leftmost part of the aspath as
1582 AS_CONFED_SEQUENCE. */
1583struct aspath*
1584aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1585{
1586 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1587}
1588
1589/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001590static void
paul718e3742002-12-13 20:15:29 +00001591aspath_as_add (struct aspath *as, as_t asno)
1592{
paulfe69a502005-09-10 16:55:02 +00001593 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001594
paulfe69a502005-09-10 16:55:02 +00001595 if (!seg)
1596 return;
1597
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001598 /* Last segment search procedure. */
1599 while (seg->next)
1600 seg = seg->next;
1601
paulfe69a502005-09-10 16:55:02 +00001602 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001603}
1604
1605/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001606static void
paul718e3742002-12-13 20:15:29 +00001607aspath_segment_add (struct aspath *as, int type)
1608{
paulfe69a502005-09-10 16:55:02 +00001609 struct assegment *seg = as->segments;
1610 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001611
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001612 if (seg)
1613 {
1614 while (seg->next)
1615 seg = seg->next;
1616 seg->next = new;
1617 }
paul718e3742002-12-13 20:15:29 +00001618 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001619 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001620}
1621
1622struct aspath *
paul94f2b392005-06-28 12:44:16 +00001623aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001624{
Paul Jakmaab005292010-11-27 22:48:34 +00001625 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001626}
1627
1628struct aspath *
paul94f2b392005-06-28 12:44:16 +00001629aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001630{
1631 struct aspath *aspath;
1632
1633 aspath = aspath_new ();
1634 aspath->str = aspath_make_str_count (aspath);
1635 return aspath;
1636}
1637
1638unsigned long
paulfe69a502005-09-10 16:55:02 +00001639aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001640{
1641 return ashash->count;
1642}
1643
1644/*
1645 Theoretically, one as path can have:
1646
1647 One BGP packet size should be less than 4096.
1648 One BGP attribute size should be less than 4096 - BGP header size.
1649 One BGP aspath size should be less than 4096 - BGP header size -
1650 BGP mandantry attribute size.
1651*/
1652
1653/* AS path string lexical token enum. */
1654enum as_token
1655{
1656 as_token_asval,
1657 as_token_set_start,
1658 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001659 as_token_confed_seq_start,
1660 as_token_confed_seq_end,
1661 as_token_confed_set_start,
1662 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001663 as_token_unknown
1664};
1665
1666/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001667static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001668aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001669{
paulfd79ac92004-10-13 05:06:08 +00001670 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001671
paulfe69a502005-09-10 16:55:02 +00001672 /* Skip seperators (space for sequences, ',' for sets). */
1673 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001674 p++;
1675
1676 /* Check the end of the string and type specify characters
1677 (e.g. {}()). */
1678 switch (*p)
1679 {
1680 case '\0':
1681 return NULL;
paul718e3742002-12-13 20:15:29 +00001682 case '{':
1683 *token = as_token_set_start;
1684 p++;
1685 return p;
paul718e3742002-12-13 20:15:29 +00001686 case '}':
1687 *token = as_token_set_end;
1688 p++;
1689 return p;
paul718e3742002-12-13 20:15:29 +00001690 case '(':
paulfe69a502005-09-10 16:55:02 +00001691 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001692 p++;
1693 return p;
paul718e3742002-12-13 20:15:29 +00001694 case ')':
paulfe69a502005-09-10 16:55:02 +00001695 *token = as_token_confed_seq_end;
1696 p++;
1697 return p;
paulfe69a502005-09-10 16:55:02 +00001698 case '[':
1699 *token = as_token_confed_set_start;
1700 p++;
1701 return p;
paulfe69a502005-09-10 16:55:02 +00001702 case ']':
1703 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001704 p++;
1705 return p;
paul718e3742002-12-13 20:15:29 +00001706 }
1707
1708 /* Check actual AS value. */
1709 if (isdigit ((int) *p))
1710 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001711 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001712
paul718e3742002-12-13 20:15:29 +00001713 *token = as_token_asval;
1714 asval = (*p - '0');
1715 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001716
paul718e3742002-12-13 20:15:29 +00001717 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001718 {
1719 asval *= 10;
1720 asval += (*p - '0');
1721 p++;
1722 }
paul718e3742002-12-13 20:15:29 +00001723 *asno = asval;
1724 return p;
1725 }
1726
1727 /* There is no match then return unknown token. */
1728 *token = as_token_unknown;
1729 return p++;
1730}
1731
1732struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001733aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001734{
paul3fff6ff2006-02-05 17:55:35 +00001735 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001736 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001737 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001738 struct aspath *aspath;
1739 int needtype;
1740
1741 aspath = aspath_new ();
1742
1743 /* We start default type as AS_SEQUENCE. */
1744 as_type = AS_SEQUENCE;
1745 needtype = 1;
1746
1747 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1748 {
1749 switch (token)
1750 {
1751 case as_token_asval:
1752 if (needtype)
1753 {
1754 aspath_segment_add (aspath, as_type);
1755 needtype = 0;
1756 }
1757 aspath_as_add (aspath, asno);
1758 break;
1759 case as_token_set_start:
1760 as_type = AS_SET;
1761 aspath_segment_add (aspath, as_type);
1762 needtype = 0;
1763 break;
1764 case as_token_set_end:
1765 as_type = AS_SEQUENCE;
1766 needtype = 1;
1767 break;
paulfe69a502005-09-10 16:55:02 +00001768 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001769 as_type = AS_CONFED_SEQUENCE;
1770 aspath_segment_add (aspath, as_type);
1771 needtype = 0;
1772 break;
paulfe69a502005-09-10 16:55:02 +00001773 case as_token_confed_seq_end:
1774 as_type = AS_SEQUENCE;
1775 needtype = 1;
1776 break;
1777 case as_token_confed_set_start:
1778 as_type = AS_CONFED_SET;
1779 aspath_segment_add (aspath, as_type);
1780 needtype = 0;
1781 break;
1782 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001783 as_type = AS_SEQUENCE;
1784 needtype = 1;
1785 break;
1786 case as_token_unknown:
1787 default:
paulfe69a502005-09-10 16:55:02 +00001788 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001789 return NULL;
paul718e3742002-12-13 20:15:29 +00001790 }
1791 }
1792
1793 aspath->str = aspath_make_str_count (aspath);
1794
1795 return aspath;
1796}
1797
1798/* Make hash value by raw aspath data. */
1799unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001800aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001801{
Paul Jakma923de652007-04-29 18:25:17 +00001802 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001803 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001804
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001805 if (!aspath->str)
1806 aspath_str_update (aspath);
1807
1808 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001809
1810 return key;
1811}
1812
1813/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001814static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001815aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001816{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001817 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1818 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001819
1820 while (seg1 || seg2)
1821 {
1822 int i;
1823 if ((!seg1 && seg2) || (seg1 && !seg2))
1824 return 0;
1825 if (seg1->type != seg2->type)
1826 return 0;
1827 if (seg1->length != seg2->length)
1828 return 0;
1829 for (i = 0; i < seg1->length; i++)
1830 if (seg1->as[i] != seg2->as[i])
1831 return 0;
1832 seg1 = seg1->next;
1833 seg2 = seg2->next;
1834 }
1835 return 1;
paul718e3742002-12-13 20:15:29 +00001836}
1837
1838/* AS path hash initialize. */
1839void
paul94f2b392005-06-28 12:44:16 +00001840aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001841{
1842 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1843}
paul8fdc32a2006-01-16 12:01:29 +00001844
1845void
1846aspath_finish (void)
1847{
1848 hash_free (ashash);
Chris Caputo228da422009-07-18 05:44:03 +00001849 ashash = NULL;
paul8fdc32a2006-01-16 12:01:29 +00001850
1851 if (snmp_stream)
1852 stream_free (snmp_stream);
1853}
paul718e3742002-12-13 20:15:29 +00001854
1855/* return and as path value */
1856const char *
1857aspath_print (struct aspath *as)
1858{
paulfe69a502005-09-10 16:55:02 +00001859 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001860}
1861
1862/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001863/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1864 * AS_PATH wasn't empty.
1865 */
paul718e3742002-12-13 20:15:29 +00001866void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001867aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001868{
Paul Jakmab2518c12006-05-12 23:48:40 +00001869 assert (format);
1870 vty_out (vty, format, as->str);
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001871 if (strlen (as->str) && strlen (suffix))
1872 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001873}
1874
paul94f2b392005-06-28 12:44:16 +00001875static void
paul718e3742002-12-13 20:15:29 +00001876aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1877{
1878 struct aspath *as;
1879
1880 as = (struct aspath *) backet->data;
1881
paulefa9f832002-12-13 21:47:59 +00001882 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001883 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1884}
1885
1886/* Print all aspath and hash information. This function is used from
1887 `show ip bgp paths' command. */
1888void
1889aspath_print_all_vty (struct vty *vty)
1890{
1891 hash_iterate (ashash,
1892 (void (*) (struct hash_backet *, void *))
1893 aspath_show_all_iterator,
1894 vty);
1895}