blob: d0d621c22be7d1f848ef816052d5cf985f3c5204 [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. */
89struct 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{
325 struct aspath *aspath;
326
327 aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
328 memset (aspath, 0, sizeof (struct aspath));
329 return aspath;
330}
331
332/* Free AS path structure. */
333void
334aspath_free (struct aspath *aspath)
335{
336 if (!aspath)
337 return;
paulfe69a502005-09-10 16:55:02 +0000338 if (aspath->segments)
339 assegment_free_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000340 if (aspath->str)
341 XFREE (MTYPE_AS_STR, aspath->str);
342 XFREE (MTYPE_AS_PATH, aspath);
343}
344
345/* Unintern aspath from AS path bucket. */
346void
347aspath_unintern (struct aspath *aspath)
348{
349 struct aspath *ret;
350
351 if (aspath->refcnt)
352 aspath->refcnt--;
353
354 if (aspath->refcnt == 0)
355 {
356 /* This aspath must exist in aspath hash table. */
357 ret = hash_release (ashash, aspath);
358 assert (ret != NULL);
359 aspath_free (aspath);
360 }
361}
362
363/* Return the start or end delimiters for a particular Segment type */
364#define AS_SEG_START 0
365#define AS_SEG_END 1
366static char
367aspath_delimiter_char (u_char type, u_char which)
368{
369 int i;
370 struct
371 {
372 int type;
373 char start;
374 char end;
375 } aspath_delim_char [] =
376 {
377 { AS_SET, '{', '}' },
paul718e3742002-12-13 20:15:29 +0000378 { AS_CONFED_SET, '[', ']' },
379 { AS_CONFED_SEQUENCE, '(', ')' },
380 { 0 }
381 };
382
383 for (i = 0; aspath_delim_char[i].type != 0; i++)
384 {
385 if (aspath_delim_char[i].type == type)
386 {
387 if (which == AS_SEG_START)
388 return aspath_delim_char[i].start;
389 else if (which == AS_SEG_END)
390 return aspath_delim_char[i].end;
391 }
392 }
393 return ' ';
394}
395
paulfe69a502005-09-10 16:55:02 +0000396unsigned int
397aspath_count_confeds (struct aspath *aspath)
398{
399 int count = 0;
400 struct assegment *seg = aspath->segments;
401
402 while (seg)
403 {
404 if (seg->type == AS_CONFED_SEQUENCE)
405 count += seg->length;
406 else if (seg->type == AS_CONFED_SET)
407 count++;
408
409 seg = seg->next;
410 }
411 return count;
412}
413
414unsigned int
415aspath_count_hops (struct aspath *aspath)
416{
417 int count = 0;
418 struct assegment *seg = aspath->segments;
419
420 while (seg)
421 {
422 if (seg->type == AS_SEQUENCE)
423 count += seg->length;
424 else if (seg->type == AS_SET)
425 count++;
426
427 seg = seg->next;
428 }
429 return count;
430}
431
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000432/* Estimate size aspath /might/ take if encoded into an
433 * ASPATH attribute.
434 *
435 * This is a quick estimate, not definitive! aspath_put()
436 * may return a different number!!
437 */
paulfe69a502005-09-10 16:55:02 +0000438unsigned int
439aspath_size (struct aspath *aspath)
440{
441 int size = 0;
442 struct assegment *seg = aspath->segments;
443
444 while (seg)
445 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000446 size += ASSEGMENT_SIZE(seg->length, 1);
paulfe69a502005-09-10 16:55:02 +0000447 seg = seg->next;
448 }
449 return size;
450}
451
Paul Jakma2815e612006-09-14 02:56:07 +0000452/* Return highest public ASN in path */
453as_t
454aspath_highest (struct aspath *aspath)
455{
456 struct assegment *seg = aspath->segments;
457 as_t highest = 0;
458 unsigned int i;
459
460 while (seg)
461 {
462 for (i = 0; i < seg->length; i++)
463 if (seg->as[i] > highest
464 && (seg->as[i] < BGP_PRIVATE_AS_MIN
465 || seg->as[i] > BGP_PRIVATE_AS_MAX))
466 highest = seg->as[i];
467 seg = seg->next;
468 }
469 return highest;
470}
471
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000472/* Return 1 if there are any 4-byte ASes in the path */
473unsigned int
474aspath_has_as4 (struct aspath *aspath)
475{
476 struct assegment *seg = aspath->segments;
477 unsigned int i;
478
479 while (seg)
480 {
481 for (i = 0; i < seg->length; i++)
482 if (seg->as[i] > BGP_AS_MAX)
483 return 1;
484 seg = seg->next;
485 }
486 return 0;
487}
488
489/* Return number of as numbers in in path */
490unsigned int
491aspath_count_numas (struct aspath *aspath)
492{
493 struct assegment *seg = aspath->segments;
494 unsigned int num;
495
496 num=0;
497 while (seg)
498 {
499 num += seg->length;
500 seg = seg->next;
501 }
502 return num;
503}
504
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400505static void
506aspath_make_str_big_enough (int len,
507 char **str_buf,
508 int *str_size,
509 int count_to_be_added)
510{
511#define TERMINATOR 1
512 while (len + count_to_be_added + TERMINATOR > *str_size)
513 {
514 *str_size *= 2;
515 *str_buf = XREALLOC (MTYPE_AS_STR, *str_buf, *str_size);
516 }
517#undef TERMINATOR
518}
519
paul718e3742002-12-13 20:15:29 +0000520/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000521static char *
paul718e3742002-12-13 20:15:29 +0000522aspath_make_str_count (struct aspath *as)
523{
paulfe69a502005-09-10 16:55:02 +0000524 struct assegment *seg;
525 int str_size;
526 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000527 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000528
529 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000530 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000531 {
532 str_buf = XMALLOC (MTYPE_AS_STR, 1);
533 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000534 return str_buf;
535 }
paulfe69a502005-09-10 16:55:02 +0000536
537 seg = as->segments;
538
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400539 str_size = ASPATH_STR_DEFAULT_LEN;
paul718e3742002-12-13 20:15:29 +0000540 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000541
paulfe69a502005-09-10 16:55:02 +0000542 while (seg)
paul718e3742002-12-13 20:15:29 +0000543 {
544 int i;
paulfe69a502005-09-10 16:55:02 +0000545 char seperator;
paul718e3742002-12-13 20:15:29 +0000546
paulfe69a502005-09-10 16:55:02 +0000547 /* Check AS type validity. Set seperator for segment */
548 switch (seg->type)
549 {
550 case AS_SET:
551 case AS_CONFED_SET:
552 seperator = ',';
553 break;
554 case AS_SEQUENCE:
555 case AS_CONFED_SEQUENCE:
556 seperator = ' ';
557 break;
558 default:
559 XFREE (MTYPE_AS_STR, str_buf);
560 return NULL;
561 }
562
paulfe69a502005-09-10 16:55:02 +0000563 if (seg->type != AS_SEQUENCE)
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400564 {
565 aspath_make_str_big_enough (len, &str_buf, &str_size, 1); /* %c */
566 len += snprintf (str_buf + len, str_size - len,
567 "%c",
568 aspath_delimiter_char (seg->type, AS_SEG_START));
569 }
paulfe69a502005-09-10 16:55:02 +0000570
571 /* write out the ASNs, with their seperators, bar the last one*/
572 for (i = 0; i < seg->length; i++)
573 {
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400574#define APPROX_DIG_CNT(x) (x < 100000U ? 5 : 10)
575 /* %u + %c + %c + " " (last two are below loop) */
576 aspath_make_str_big_enough (len,
577 &str_buf,
578 &str_size,
579 APPROX_DIG_CNT(seg->as[i]) + 1 + 1 + 1);
580
paulfe69a502005-09-10 16:55:02 +0000581 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
582
583 if (i < (seg->length - 1))
584 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
585 }
586
587 if (seg->type != AS_SEQUENCE)
588 len += snprintf (str_buf + len, str_size - len, "%c",
589 aspath_delimiter_char (seg->type, AS_SEG_END));
590 if (seg->next)
591 len += snprintf (str_buf + len, str_size - len, " ");
592
593 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000594 }
paulfe69a502005-09-10 16:55:02 +0000595
596 assert (len < str_size);
597
598 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000599
600 return str_buf;
601}
602
paulfe69a502005-09-10 16:55:02 +0000603static void
604aspath_str_update (struct aspath *as)
605{
606 if (as->str)
607 XFREE (MTYPE_AS_STR, as->str);
608 as->str = aspath_make_str_count (as);
609}
610
paul718e3742002-12-13 20:15:29 +0000611/* Intern allocated AS path. */
612struct aspath *
613aspath_intern (struct aspath *aspath)
614{
615 struct aspath *find;
616
617 /* Assert this AS path structure is not interned. */
618 assert (aspath->refcnt == 0);
619
620 /* Check AS path hash. */
621 find = hash_get (ashash, aspath, hash_alloc_intern);
622
623 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000624 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000625
626 find->refcnt++;
627
628 if (! find->str)
629 find->str = aspath_make_str_count (find);
630
631 return find;
632}
633
634/* Duplicate aspath structure. Created same aspath structure but
635 reference count and AS path string is cleared. */
636struct aspath *
637aspath_dup (struct aspath *aspath)
638{
639 struct aspath *new;
640
paulfe69a502005-09-10 16:55:02 +0000641 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000642
paulfe69a502005-09-10 16:55:02 +0000643 if (aspath->segments)
644 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000645 else
paulfe69a502005-09-10 16:55:02 +0000646 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000647
paulfe69a502005-09-10 16:55:02 +0000648 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000649
650 return new;
651}
652
paul94f2b392005-06-28 12:44:16 +0000653static void *
paulfe69a502005-09-10 16:55:02 +0000654aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000655{
656 struct aspath *aspath;
657
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000658 /* New aspath structure is needed. */
paulfe69a502005-09-10 16:55:02 +0000659 aspath = aspath_dup (arg);
660
paul718e3742002-12-13 20:15:29 +0000661 /* Malformed AS path value. */
662 if (! aspath->str)
663 {
664 aspath_free (aspath);
665 return NULL;
666 }
667
668 return aspath;
669}
670
paulfe69a502005-09-10 16:55:02 +0000671/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000672static struct assegment *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000673assegments_parse (struct stream *s, size_t length, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000674{
675 struct assegment_header segh;
676 struct assegment *seg, *prev = NULL, *head = NULL;
677 size_t bytes = 0;
678
679 /* empty aspath (ie iBGP or somesuch) */
680 if (length == 0)
681 return NULL;
682
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000683 if (BGP_DEBUG (as4, AS4_SEGMENT))
684 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
685 (unsigned long) length);
paulfe69a502005-09-10 16:55:02 +0000686 /* basic checks */
687 if ( (STREAM_READABLE(s) < length)
688 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000689 || (length % AS16_VALUE_SIZE ))
paulfe69a502005-09-10 16:55:02 +0000690 return NULL;
691
692 while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
693 && (bytes < length))
694 {
695 int i;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000696 int seg_size;
paulfe69a502005-09-10 16:55:02 +0000697
698 /* softly softly, get the header first on its own */
699 segh.type = stream_getc (s);
700 segh.length = stream_getc (s);
701
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000702 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
703
704 if (BGP_DEBUG (as4, AS4_SEGMENT))
705 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
706 segh.type, segh.length);
707
paulfe69a502005-09-10 16:55:02 +0000708 /* check it.. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000709 if ( ((bytes + seg_size) > length)
paulfe69a502005-09-10 16:55:02 +0000710 /* 1771bis 4.3b: seg length contains one or more */
711 || (segh.length == 0)
712 /* Paranoia in case someone changes type of segment length */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000713 || ((sizeof segh.length > 1) && (segh.length > AS_SEGMENT_MAX)) )
paulfe69a502005-09-10 16:55:02 +0000714 {
715 if (head)
716 assegment_free_all (head);
717 return NULL;
718 }
719
720 /* now its safe to trust lengths */
721 seg = assegment_new (segh.type, segh.length);
722
723 if (head)
724 prev->next = seg;
725 else /* it's the first segment */
726 head = prev = seg;
727
728 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000729 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
730
731 bytes += seg_size;
paulfe69a502005-09-10 16:55:02 +0000732
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000733 if (BGP_DEBUG (as4, AS4_SEGMENT))
734 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
735 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000736
737 prev = seg;
738 }
739
740 return assegment_normalise (head);
741}
742
paul718e3742002-12-13 20:15:29 +0000743/* AS path parse function. pnt is a pointer to byte stream and length
744 is length of byte stream. If there is same AS path in the the AS
745 path hash then return it else make new AS path structure. */
746struct aspath *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000747aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000748{
749 struct aspath as;
750 struct aspath *find;
751
752 /* If length is odd it's malformed AS path. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000753 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
754 * otherwise its malformed when length is larger than 2 and (length-2)
755 * is not dividable by 4.
756 * But... this time we're lazy
757 */
758 if (length % AS16_VALUE_SIZE )
paul718e3742002-12-13 20:15:29 +0000759 return NULL;
760
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000761 memset (&as, 0, sizeof (struct aspath));
762 as.segments = assegments_parse (s, length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000763
paul718e3742002-12-13 20:15:29 +0000764 /* If already same aspath exist then return it. */
765 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000766
767 /* aspath_hash_alloc dupes segments too. that probably could be
768 * optimised out.
769 */
770 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000771 if (as.str)
772 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000773
paul718e3742002-12-13 20:15:29 +0000774 if (! find)
775 return NULL;
776 find->refcnt++;
777
778 return find;
779}
780
paulfe69a502005-09-10 16:55:02 +0000781static inline void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000782assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000783{
paulfe69a502005-09-10 16:55:02 +0000784 int i;
785 assert (num <= AS_SEGMENT_MAX);
786
787 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000788 if ( use32bit )
789 stream_putl (s, as[i]);
790 else
791 {
792 if ( as[i] <= BGP_AS_MAX )
793 stream_putw(s, as[i]);
794 else
795 stream_putw(s, BGP_AS_TRANS);
796 }
paul718e3742002-12-13 20:15:29 +0000797}
798
paulfe69a502005-09-10 16:55:02 +0000799static inline size_t
800assegment_header_put (struct stream *s, u_char type, int length)
801{
802 size_t lenp;
803 assert (length <= AS_SEGMENT_MAX);
804 stream_putc (s, type);
805 lenp = stream_get_endp (s);
806 stream_putc (s, length);
807 return lenp;
808}
809
810/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000811size_t
812aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000813{
814 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000815 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000816
817 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000818 return 0;
paulfe69a502005-09-10 16:55:02 +0000819
820 if (seg)
821 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000822 /*
823 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
824 * At the moment, we would write out a partial aspath, and our peer
825 * will complain and drop the session :-/
826 *
827 * The general assumption here is that many things tested will
828 * never happen. And, in real live, up to now, they have not.
829 */
830 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000831 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000832 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000833 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000834 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000835 size_t lenp;
836
837 /* Overlength segments have to be split up */
838 while ( (seg->length - written) > AS_SEGMENT_MAX)
839 {
840 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000841 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000842 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000843 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000844 }
845
846 /* write the final segment, probably is also the first */
847 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000848 assegment_data_put (s, (seg->as + written), seg->length - written,
849 use32bit);
paulfe69a502005-09-10 16:55:02 +0000850
851 /* Sequence-type segments can be 'packed' together
852 * Case of a segment which was overlength and split up
853 * will be missed here, but that doesn't matter.
854 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000855 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000856 {
857 /* NB: We should never normally get here given we
858 * normalise aspath data when parse them. However, better
859 * safe than sorry. We potentially could call
860 * assegment_normalise here instead, but it's cheaper and
861 * easier to do it on the fly here rather than go through
862 * the segment list twice every time we write out
863 * aspath's.
864 */
865
866 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000867 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000868
869 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000870 stream_putc_at (s, lenp, seg->length - written + next->length);
871 asns_packed += next->length;
872
873 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000874 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000875
876 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
877 use32bit);
878 seg = next;
paulfe69a502005-09-10 16:55:02 +0000879 }
880 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000881 return bytes;
paulfe69a502005-09-10 16:55:02 +0000882}
883
884/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
885 * We have no way to manage the storage, so we use a static stream
886 * wrapper around aspath_put.
887 */
888u_char *
889aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
890{
891#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000892
893 if (!snmp_stream)
894 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000895 else
paul8fdc32a2006-01-16 12:01:29 +0000896 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000897
898 if (!as)
899 {
900 *varlen = 0;
901 return NULL;
902 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000903 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000904
paul8fdc32a2006-01-16 12:01:29 +0000905 *varlen = stream_get_endp (snmp_stream);
906 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000907}
908
909#define min(A,B) ((A) < (B) ? (A) : (B))
910
paul94f2b392005-06-28 12:44:16 +0000911static struct assegment *
paul718e3742002-12-13 20:15:29 +0000912aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
913 as_t as)
914{
915 int i;
916
917 /* If this is first AS set member, create new as-set segment. */
918 if (asset == NULL)
919 {
paulfe69a502005-09-10 16:55:02 +0000920 asset = assegment_new (AS_SET, 1);
921 if (! aspath->segments)
922 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000923 else
paulfe69a502005-09-10 16:55:02 +0000924 {
925 struct assegment *seg = aspath->segments;
926 while (seg->next)
927 seg = seg->next;
928 seg->next = asset;
929 }
paul718e3742002-12-13 20:15:29 +0000930 asset->type = AS_SET;
931 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000932 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000933 }
934 else
935 {
paul718e3742002-12-13 20:15:29 +0000936 /* Check this AS value already exists or not. */
937 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000938 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000939 return asset;
paulfe69a502005-09-10 16:55:02 +0000940
paul718e3742002-12-13 20:15:29 +0000941 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000942 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
943 asset->length * AS_VALUE_SIZE);
944 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000945 }
paulfe69a502005-09-10 16:55:02 +0000946
paul718e3742002-12-13 20:15:29 +0000947
948 return asset;
949}
950
951/* Modify as1 using as2 for aggregation. */
952struct aspath *
953aspath_aggregate (struct aspath *as1, struct aspath *as2)
954{
955 int i;
956 int minlen;
957 int match;
paulfe69a502005-09-10 16:55:02 +0000958 int from;
959 struct assegment *seg1 = as1->segments;
960 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000961 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000962 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000963 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +0000964
965 match = 0;
966 minlen = 0;
967 aspath = NULL;
968 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000969
970 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000971 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000972 {
paul718e3742002-12-13 20:15:29 +0000973 /* Check segment type. */
974 if (seg1->type != seg2->type)
975 break;
976
977 /* Minimum segment length. */
978 minlen = min (seg1->length, seg2->length);
979
980 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +0000981 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +0000982 break;
983
984 if (match)
985 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000986 struct assegment *seg = assegment_new (seg1->type, 0);
987
988 seg = assegment_append_asns (seg, seg1->as, match);
989
paul718e3742002-12-13 20:15:29 +0000990 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000991 {
992 aspath = aspath_new ();
993 aspath->segments = seg;
994 }
995 else
996 prevseg->next = seg;
997
998 prevseg = seg;
paul718e3742002-12-13 20:15:29 +0000999 }
1000
1001 if (match != minlen || match != seg1->length
1002 || seg1->length != seg2->length)
1003 break;
paulfe69a502005-09-10 16:55:02 +00001004
1005 seg1 = seg1->next;
1006 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001007 }
1008
1009 if (! aspath)
1010 aspath = aspath_new();
1011
1012 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001013 from = match;
1014 while (seg1)
paul718e3742002-12-13 20:15:29 +00001015 {
paulfe69a502005-09-10 16:55:02 +00001016 for (i = from; i < seg1->length; i++)
1017 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1018
1019 from = 0;
1020 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001021 }
1022
paulfe69a502005-09-10 16:55:02 +00001023 from = match;
1024 while (seg2)
paul718e3742002-12-13 20:15:29 +00001025 {
paulfe69a502005-09-10 16:55:02 +00001026 for (i = from; i < seg2->length; i++)
1027 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001028
paulfe69a502005-09-10 16:55:02 +00001029 from = 0;
1030 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001031 }
paulfe69a502005-09-10 16:55:02 +00001032
1033 assegment_normalise (aspath->segments);
1034 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001035 return aspath;
1036}
1037
1038/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1039 attribute, check the leftmost AS number in the AS_PATH attribute is
1040 or not the peer's AS number. */
1041int
1042aspath_firstas_check (struct aspath *aspath, as_t asno)
1043{
paulfe69a502005-09-10 16:55:02 +00001044 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001045 return 0;
paulfe69a502005-09-10 16:55:02 +00001046
1047 if (aspath->segments
1048 && (aspath->segments->type == AS_SEQUENCE)
1049 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001050 return 1;
1051
1052 return 0;
1053}
1054
Paul Jakma1f742f22006-08-06 15:52:11 +00001055/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001056int
1057aspath_loop_check (struct aspath *aspath, as_t asno)
1058{
paulfe69a502005-09-10 16:55:02 +00001059 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001060 int count = 0;
1061
Paul Jakma1f742f22006-08-06 15:52:11 +00001062 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001063 return 0;
paulfe69a502005-09-10 16:55:02 +00001064
1065 seg = aspath->segments;
1066
1067 while (seg)
paul718e3742002-12-13 20:15:29 +00001068 {
1069 int i;
paul718e3742002-12-13 20:15:29 +00001070
paulfe69a502005-09-10 16:55:02 +00001071 for (i = 0; i < seg->length; i++)
1072 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001073 count++;
paulfe69a502005-09-10 16:55:02 +00001074
1075 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001076 }
1077 return count;
1078}
1079
1080/* When all of AS path is private AS return 1. */
1081int
1082aspath_private_as_check (struct aspath *aspath)
1083{
paulfe69a502005-09-10 16:55:02 +00001084 struct assegment *seg;
1085
1086 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001087 return 0;
paulfe69a502005-09-10 16:55:02 +00001088
1089 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001090
paulfe69a502005-09-10 16:55:02 +00001091 while (seg)
paul718e3742002-12-13 20:15:29 +00001092 {
1093 int i;
paul718e3742002-12-13 20:15:29 +00001094
paulfe69a502005-09-10 16:55:02 +00001095 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001096 {
paulfe69a502005-09-10 16:55:02 +00001097 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1098 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001099 return 0;
1100 }
paulfe69a502005-09-10 16:55:02 +00001101 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001102 }
1103 return 1;
1104}
1105
1106/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001107static struct aspath *
paul718e3742002-12-13 20:15:29 +00001108aspath_merge (struct aspath *as1, struct aspath *as2)
1109{
paulfe69a502005-09-10 16:55:02 +00001110 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001111
1112 if (! as1 || ! as2)
1113 return NULL;
1114
paulfe69a502005-09-10 16:55:02 +00001115 last = new = assegment_dup_all (as1->segments);
1116
1117 /* find the last valid segment */
1118 while (last && last->next)
1119 last = last->next;
1120
1121 last->next = as2->segments;
1122 as2->segments = new;
1123 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001124 return as2;
1125}
1126
1127/* Prepend as1 to as2. as2 should be uninterned aspath. */
1128struct aspath *
1129aspath_prepend (struct aspath *as1, struct aspath *as2)
1130{
paulfe69a502005-09-10 16:55:02 +00001131 struct assegment *seg1;
1132 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001133
1134 if (! as1 || ! as2)
1135 return NULL;
paulfe69a502005-09-10 16:55:02 +00001136
1137 seg1 = as1->segments;
1138 seg2 = as2->segments;
1139
1140 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001141 if (seg2 == NULL)
1142 {
paulfe69a502005-09-10 16:55:02 +00001143 as2->segments = assegment_dup_all (as1->segments);
1144 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001145 return as2;
1146 }
paulfe69a502005-09-10 16:55:02 +00001147
1148 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001149 if (seg1 == NULL)
1150 return as2;
paulfe69a502005-09-10 16:55:02 +00001151
1152 /* find the tail as1's segment chain. */
1153 while (seg1 && seg1->next)
1154 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001155
1156 /* Compare last segment type of as1 and first segment type of as2. */
1157 if (seg1->type != seg2->type)
1158 return aspath_merge (as1, as2);
1159
1160 if (seg1->type == AS_SEQUENCE)
1161 {
paulfe69a502005-09-10 16:55:02 +00001162 /* We have two chains of segments, as1->segments and seg2,
1163 * and we have to attach them together, merging the attaching
1164 * segments together into one.
1165 *
1166 * 1. dupe as1->segments onto head of as2
1167 * 2. merge seg2's asns onto last segment of this new chain
1168 * 3. attach chain after seg2
1169 */
paul718e3742002-12-13 20:15:29 +00001170
paulfe69a502005-09-10 16:55:02 +00001171 /* dupe as1 onto as2's head */
1172 seg1 = as2->segments = assegment_dup_all (as1->segments);
1173
1174 /* refind the tail of as2, reusing seg1 */
1175 while (seg1 && seg1->next)
1176 seg1 = seg1->next;
1177
1178 /* merge the old head, seg2, into tail, seg1 */
1179 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1180
1181 /* bypass the merged seg2, and attach any chain after it to
1182 * chain descending from as2's head
1183 */
1184 seg1->next = seg2->next;
1185
1186 /* seg2 is now referenceless and useless*/
1187 assegment_free (seg2);
1188
1189 /* we've now prepended as1's segment chain to as2, merging
1190 * the inbetween AS_SEQUENCE of seg2 in the process
1191 */
1192 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001193 return as2;
1194 }
1195 else
1196 {
1197 /* AS_SET merge code is needed at here. */
1198 return aspath_merge (as1, as2);
1199 }
paulfe69a502005-09-10 16:55:02 +00001200 /* XXX: Ermmm, what if as1 has multiple segments?? */
1201
paul718e3742002-12-13 20:15:29 +00001202 /* Not reached */
1203}
1204
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001205/* Iterate over AS_PATH segments and wipe all occurences of the
1206 * listed AS numbers. Hence some segments may lose some or even
1207 * all data on the way, the operation is implemented as a smarter
1208 * version of aspath_dup(), which allocates memory to hold the new
1209 * data, not the original. The new AS path is returned.
1210 */
1211struct aspath *
1212aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1213{
1214 struct assegment * srcseg, * exclseg, * lastseg;
1215 struct aspath * newpath;
1216
1217 newpath = aspath_new();
1218 lastseg = NULL;
1219
1220 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1221 {
1222 unsigned i, y, newlen = 0, done = 0, skip_as;
1223 struct assegment * newseg;
1224
1225 /* Find out, how much ASns are we going to pick from this segment.
1226 * We can't perform filtering right inline, because the size of
1227 * the new segment isn't known at the moment yet.
1228 */
1229 for (i = 0; i < srcseg->length; i++)
1230 {
1231 skip_as = 0;
1232 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1233 for (y = 0; y < exclseg->length; y++)
1234 if (srcseg->as[i] == exclseg->as[y])
1235 {
1236 skip_as = 1;
1237 // There's no sense in testing the rest of exclusion list, bail out.
1238 break;
1239 }
1240 if (!skip_as)
1241 newlen++;
1242 }
1243 /* newlen is now the number of ASns to copy */
1244 if (!newlen)
1245 continue;
1246
1247 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1248 newseg = assegment_new (srcseg->type, newlen);
1249 for (i = 0; i < srcseg->length; i++)
1250 {
1251 skip_as = 0;
1252 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1253 for (y = 0; y < exclseg->length; y++)
1254 if (srcseg->as[i] == exclseg->as[y])
1255 {
1256 skip_as = 1;
1257 break;
1258 }
1259 if (skip_as)
1260 continue;
1261 newseg->as[done++] = srcseg->as[i];
1262 }
1263 /* At his point newlen must be equal to done, and both must be positive. Append
1264 * the filtered segment to the gross result. */
1265 if (!lastseg)
1266 newpath->segments = newseg;
1267 else
1268 lastseg->next = newseg;
1269 lastseg = newseg;
1270 }
1271 aspath_str_update (newpath);
1272 /* We are happy returning even an empty AS_PATH, because the administrator
1273 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1274 * by having a match rule against certain AS_PATH regexps in the route-map index.
1275 */
1276 aspath_free (source);
1277 return newpath;
1278}
1279
paul718e3742002-12-13 20:15:29 +00001280/* Add specified AS to the leftmost of aspath. */
1281static struct aspath *
1282aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1283{
paulfe69a502005-09-10 16:55:02 +00001284 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001285
1286 /* In case of empty aspath. */
1287 if (assegment == NULL || assegment->length == 0)
1288 {
paulfe69a502005-09-10 16:55:02 +00001289 aspath->segments = assegment_new (type, 1);
1290 aspath->segments->as[0] = asno;
1291
paul718e3742002-12-13 20:15:29 +00001292 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001293 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001294
1295 return aspath;
1296 }
1297
1298 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001299 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1300 else
paul718e3742002-12-13 20:15:29 +00001301 {
paulfe69a502005-09-10 16:55:02 +00001302 /* create new segment
1303 * push it onto head of aspath's segment chain
1304 */
paul718e3742002-12-13 20:15:29 +00001305 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001306
1307 newsegment = assegment_new (type, 1);
1308 newsegment->as[0] = asno;
1309
1310 newsegment->next = assegment;
1311 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001312 }
1313
1314 return aspath;
1315}
1316
1317/* Add specified AS to the leftmost of aspath. */
1318struct aspath *
1319aspath_add_seq (struct aspath *aspath, as_t asno)
1320{
1321 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1322}
1323
1324/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1325 as2's leftmost AS is same return 1. */
1326int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001327aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001328{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001329 const struct assegment *seg1 = NULL;
1330 const struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001331
paulfe69a502005-09-10 16:55:02 +00001332 if (!(aspath1 && aspath2))
1333 return 0;
paul718e3742002-12-13 20:15:29 +00001334
paulfe69a502005-09-10 16:55:02 +00001335 seg1 = aspath1->segments;
1336 seg2 = aspath2->segments;
1337
1338 /* find first non-confed segments for each */
1339 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1340 || (seg1->type == AS_CONFED_SET)))
1341 seg1 = seg1->next;
1342
1343 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1344 || (seg2->type == AS_CONFED_SET)))
1345 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001346
1347 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001348 if (!(seg1 && seg2
1349 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001350 return 0;
paulfe69a502005-09-10 16:55:02 +00001351
1352 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001353 return 1;
1354
1355 return 0;
1356}
1357
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001358/* Truncate an aspath after a number of hops, and put the hops remaining
1359 * at the front of another aspath. Needed for AS4 compat.
1360 *
1361 * Returned aspath is a /new/ aspath, which should either by free'd or
1362 * interned by the caller, as desired.
1363 */
1364struct aspath *
1365aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1366{
1367 struct assegment *seg, *newseg, *prevseg = NULL;
1368 struct aspath *newpath = NULL, *mergedpath;
1369 int hops, cpasns = 0;
1370
1371 if (!aspath)
1372 return NULL;
1373
1374 seg = aspath->segments;
1375
1376 /* CONFEDs should get reconciled too.. */
1377 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1378 - aspath_count_hops (as4path);
1379
1380 if (hops < 0)
1381 {
1382 if (BGP_DEBUG (as4, AS4))
1383 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1384 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1385 * which is daft behaviour - it contains vital loop-detection
1386 * information which must have been removed from AS_PATH.
1387 */
1388 hops = aspath_count_hops (aspath);
1389 }
1390
1391 if (!hops)
1392 return aspath_dup (as4path);
1393
1394 if ( BGP_DEBUG(as4, AS4))
1395 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1396 aspath->str, as4path->str);
1397
1398 while (seg && hops > 0)
1399 {
1400 switch (seg->type)
1401 {
1402 case AS_SET:
1403 case AS_CONFED_SET:
1404 hops--;
1405 cpasns = seg->length;
1406 break;
1407 case AS_CONFED_SEQUENCE:
1408 /* Should never split a confed-sequence, if hop-count
1409 * suggests we must then something's gone wrong somewhere.
1410 *
1411 * Most important goal is to preserve AS_PATHs prime function
1412 * as loop-detector, so we fudge the numbers so that the entire
1413 * confed-sequence is merged in.
1414 */
1415 if (hops < seg->length)
1416 {
1417 if (BGP_DEBUG (as4, AS4))
1418 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1419 " across 2/4 ASN boundary somewhere, broken..");
1420 hops = seg->length;
1421 }
1422 case AS_SEQUENCE:
1423 cpasns = MIN(seg->length, hops);
1424 hops -= seg->length;
1425 }
1426
1427 assert (cpasns <= seg->length);
1428
1429 newseg = assegment_new (seg->type, 0);
1430 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1431
1432 if (!newpath)
1433 {
1434 newpath = aspath_new ();
1435 newpath->segments = newseg;
1436 }
1437 else
1438 prevseg->next = newseg;
1439
1440 prevseg = newseg;
1441 seg = seg->next;
1442 }
1443
1444 /* We may be able to join some segments here, and we must
1445 * do this because... we want normalised aspaths in out hash
1446 * and we do not want to stumble in aspath_put.
1447 */
1448 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1449 aspath_free (newpath);
1450 mergedpath->segments = assegment_normalise (mergedpath->segments);
1451 aspath_str_update (mergedpath);
1452
1453 if ( BGP_DEBUG(as4, AS4))
1454 zlog_debug ("[AS4] result of synthesizing is %s",
1455 mergedpath->str);
1456
1457 return mergedpath;
1458}
1459
paul718e3742002-12-13 20:15:29 +00001460/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1461 as2's leftmost AS is same return 1. (confederation as-path
1462 only). */
1463int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001464aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001465{
paulfe69a502005-09-10 16:55:02 +00001466 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001467 return 0;
paulfe69a502005-09-10 16:55:02 +00001468
paulad727402005-11-23 02:47:02 +00001469 if ( !(aspath1->segments && aspath2->segments) )
1470 return 0;
1471
paulfe69a502005-09-10 16:55:02 +00001472 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1473 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001474 return 0;
paulfe69a502005-09-10 16:55:02 +00001475
1476 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001477 return 1;
1478
1479 return 0;
1480}
1481
paulfe69a502005-09-10 16:55:02 +00001482/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1483 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001484struct aspath *
1485aspath_delete_confed_seq (struct aspath *aspath)
1486{
paulfe69a502005-09-10 16:55:02 +00001487 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001488
paulfe69a502005-09-10 16:55:02 +00001489 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001490 return aspath;
1491
paulfe69a502005-09-10 16:55:02 +00001492 seg = aspath->segments;
1493
1494 /* "if the first path segment of the AS_PATH is
1495 * of type AS_CONFED_SEQUENCE,"
1496 */
1497 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1498 return aspath;
paul718e3742002-12-13 20:15:29 +00001499
paulfe69a502005-09-10 16:55:02 +00001500 /* "... that segment and any immediately following segments
1501 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1502 * from the AS_PATH attribute,"
1503 */
1504 while (seg &&
1505 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001506 {
paulfe69a502005-09-10 16:55:02 +00001507 aspath->segments = seg->next;
1508 assegment_free (seg);
1509 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001510 }
paulfe69a502005-09-10 16:55:02 +00001511 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001512 return aspath;
1513}
1514
1515/* Add new AS number to the leftmost part of the aspath as
1516 AS_CONFED_SEQUENCE. */
1517struct aspath*
1518aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1519{
1520 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1521}
1522
1523/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001524static void
paul718e3742002-12-13 20:15:29 +00001525aspath_as_add (struct aspath *as, as_t asno)
1526{
paulfe69a502005-09-10 16:55:02 +00001527 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001528
paulfe69a502005-09-10 16:55:02 +00001529 if (!seg)
1530 return;
1531
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001532 /* Last segment search procedure. */
1533 while (seg->next)
1534 seg = seg->next;
1535
paulfe69a502005-09-10 16:55:02 +00001536 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001537}
1538
1539/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001540static void
paul718e3742002-12-13 20:15:29 +00001541aspath_segment_add (struct aspath *as, int type)
1542{
paulfe69a502005-09-10 16:55:02 +00001543 struct assegment *seg = as->segments;
1544 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001545
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001546 if (seg)
1547 {
1548 while (seg->next)
1549 seg = seg->next;
1550 seg->next = new;
1551 }
paul718e3742002-12-13 20:15:29 +00001552 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001553 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001554}
1555
1556struct aspath *
paul94f2b392005-06-28 12:44:16 +00001557aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001558{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001559 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001560}
1561
1562struct aspath *
paul94f2b392005-06-28 12:44:16 +00001563aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001564{
1565 struct aspath *aspath;
1566
1567 aspath = aspath_new ();
1568 aspath->str = aspath_make_str_count (aspath);
1569 return aspath;
1570}
1571
1572unsigned long
paulfe69a502005-09-10 16:55:02 +00001573aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001574{
1575 return ashash->count;
1576}
1577
1578/*
1579 Theoretically, one as path can have:
1580
1581 One BGP packet size should be less than 4096.
1582 One BGP attribute size should be less than 4096 - BGP header size.
1583 One BGP aspath size should be less than 4096 - BGP header size -
1584 BGP mandantry attribute size.
1585*/
1586
1587/* AS path string lexical token enum. */
1588enum as_token
1589{
1590 as_token_asval,
1591 as_token_set_start,
1592 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001593 as_token_confed_seq_start,
1594 as_token_confed_seq_end,
1595 as_token_confed_set_start,
1596 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001597 as_token_unknown
1598};
1599
1600/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001601static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001602aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001603{
paulfd79ac92004-10-13 05:06:08 +00001604 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001605
paulfe69a502005-09-10 16:55:02 +00001606 /* Skip seperators (space for sequences, ',' for sets). */
1607 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001608 p++;
1609
1610 /* Check the end of the string and type specify characters
1611 (e.g. {}()). */
1612 switch (*p)
1613 {
1614 case '\0':
1615 return NULL;
paul718e3742002-12-13 20:15:29 +00001616 case '{':
1617 *token = as_token_set_start;
1618 p++;
1619 return p;
paul718e3742002-12-13 20:15:29 +00001620 case '}':
1621 *token = as_token_set_end;
1622 p++;
1623 return p;
paul718e3742002-12-13 20:15:29 +00001624 case '(':
paulfe69a502005-09-10 16:55:02 +00001625 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001626 p++;
1627 return p;
paul718e3742002-12-13 20:15:29 +00001628 case ')':
paulfe69a502005-09-10 16:55:02 +00001629 *token = as_token_confed_seq_end;
1630 p++;
1631 return p;
paulfe69a502005-09-10 16:55:02 +00001632 case '[':
1633 *token = as_token_confed_set_start;
1634 p++;
1635 return p;
paulfe69a502005-09-10 16:55:02 +00001636 case ']':
1637 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001638 p++;
1639 return p;
paul718e3742002-12-13 20:15:29 +00001640 }
1641
1642 /* Check actual AS value. */
1643 if (isdigit ((int) *p))
1644 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001645 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001646
paul718e3742002-12-13 20:15:29 +00001647 *token = as_token_asval;
1648 asval = (*p - '0');
1649 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001650
paul718e3742002-12-13 20:15:29 +00001651 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001652 {
1653 asval *= 10;
1654 asval += (*p - '0');
1655 p++;
1656 }
paul718e3742002-12-13 20:15:29 +00001657 *asno = asval;
1658 return p;
1659 }
1660
1661 /* There is no match then return unknown token. */
1662 *token = as_token_unknown;
1663 return p++;
1664}
1665
1666struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001667aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001668{
paul3fff6ff2006-02-05 17:55:35 +00001669 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001670 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001671 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001672 struct aspath *aspath;
1673 int needtype;
1674
1675 aspath = aspath_new ();
1676
1677 /* We start default type as AS_SEQUENCE. */
1678 as_type = AS_SEQUENCE;
1679 needtype = 1;
1680
1681 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1682 {
1683 switch (token)
1684 {
1685 case as_token_asval:
1686 if (needtype)
1687 {
1688 aspath_segment_add (aspath, as_type);
1689 needtype = 0;
1690 }
1691 aspath_as_add (aspath, asno);
1692 break;
1693 case as_token_set_start:
1694 as_type = AS_SET;
1695 aspath_segment_add (aspath, as_type);
1696 needtype = 0;
1697 break;
1698 case as_token_set_end:
1699 as_type = AS_SEQUENCE;
1700 needtype = 1;
1701 break;
paulfe69a502005-09-10 16:55:02 +00001702 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001703 as_type = AS_CONFED_SEQUENCE;
1704 aspath_segment_add (aspath, as_type);
1705 needtype = 0;
1706 break;
paulfe69a502005-09-10 16:55:02 +00001707 case as_token_confed_seq_end:
1708 as_type = AS_SEQUENCE;
1709 needtype = 1;
1710 break;
1711 case as_token_confed_set_start:
1712 as_type = AS_CONFED_SET;
1713 aspath_segment_add (aspath, as_type);
1714 needtype = 0;
1715 break;
1716 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001717 as_type = AS_SEQUENCE;
1718 needtype = 1;
1719 break;
1720 case as_token_unknown:
1721 default:
paulfe69a502005-09-10 16:55:02 +00001722 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001723 return NULL;
paul718e3742002-12-13 20:15:29 +00001724 }
1725 }
1726
1727 aspath->str = aspath_make_str_count (aspath);
1728
1729 return aspath;
1730}
1731
1732/* Make hash value by raw aspath data. */
1733unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001734aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001735{
Paul Jakma923de652007-04-29 18:25:17 +00001736 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001737 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001738
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001739 if (!aspath->str)
1740 aspath_str_update (aspath);
1741
1742 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001743
1744 return key;
1745}
1746
1747/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001748static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001749aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001750{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001751 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1752 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001753
1754 while (seg1 || seg2)
1755 {
1756 int i;
1757 if ((!seg1 && seg2) || (seg1 && !seg2))
1758 return 0;
1759 if (seg1->type != seg2->type)
1760 return 0;
1761 if (seg1->length != seg2->length)
1762 return 0;
1763 for (i = 0; i < seg1->length; i++)
1764 if (seg1->as[i] != seg2->as[i])
1765 return 0;
1766 seg1 = seg1->next;
1767 seg2 = seg2->next;
1768 }
1769 return 1;
paul718e3742002-12-13 20:15:29 +00001770}
1771
1772/* AS path hash initialize. */
1773void
paul94f2b392005-06-28 12:44:16 +00001774aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001775{
1776 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1777}
paul8fdc32a2006-01-16 12:01:29 +00001778
1779void
1780aspath_finish (void)
1781{
1782 hash_free (ashash);
1783
1784 if (snmp_stream)
1785 stream_free (snmp_stream);
1786}
paul718e3742002-12-13 20:15:29 +00001787
1788/* return and as path value */
1789const char *
1790aspath_print (struct aspath *as)
1791{
paulfe69a502005-09-10 16:55:02 +00001792 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001793}
1794
1795/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001796/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1797 * AS_PATH wasn't empty.
1798 */
paul718e3742002-12-13 20:15:29 +00001799void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001800aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001801{
Paul Jakmab2518c12006-05-12 23:48:40 +00001802 assert (format);
1803 vty_out (vty, format, as->str);
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001804 if (strlen (as->str) && strlen (suffix))
1805 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001806}
1807
paul94f2b392005-06-28 12:44:16 +00001808static void
paul718e3742002-12-13 20:15:29 +00001809aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1810{
1811 struct aspath *as;
1812
1813 as = (struct aspath *) backet->data;
1814
paulefa9f832002-12-13 21:47:59 +00001815 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001816 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1817}
1818
1819/* Print all aspath and hash information. This function is used from
1820 `show ip bgp paths' command. */
1821void
1822aspath_print_all_vty (struct vty *vty)
1823{
1824 hash_iterate (ashash,
1825 (void (*) (struct hash_backet *, void *))
1826 aspath_show_all_iterator,
1827 vty);
1828}