blob: 5881abe2d6426e8228377af0931ba121d77e4fdd [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{
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
paulfe69a502005-09-10 16:55:02 +0000392unsigned int
393aspath_count_confeds (struct aspath *aspath)
394{
395 int count = 0;
396 struct assegment *seg = aspath->segments;
397
398 while (seg)
399 {
400 if (seg->type == AS_CONFED_SEQUENCE)
401 count += seg->length;
402 else if (seg->type == AS_CONFED_SET)
403 count++;
404
405 seg = seg->next;
406 }
407 return count;
408}
409
410unsigned int
411aspath_count_hops (struct aspath *aspath)
412{
413 int count = 0;
414 struct assegment *seg = aspath->segments;
415
416 while (seg)
417 {
418 if (seg->type == AS_SEQUENCE)
419 count += seg->length;
420 else if (seg->type == AS_SET)
421 count++;
422
423 seg = seg->next;
424 }
425 return count;
426}
427
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000428/* Estimate size aspath /might/ take if encoded into an
429 * ASPATH attribute.
430 *
431 * This is a quick estimate, not definitive! aspath_put()
432 * may return a different number!!
433 */
paulfe69a502005-09-10 16:55:02 +0000434unsigned int
435aspath_size (struct aspath *aspath)
436{
437 int size = 0;
438 struct assegment *seg = aspath->segments;
439
440 while (seg)
441 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000442 size += ASSEGMENT_SIZE(seg->length, 1);
paulfe69a502005-09-10 16:55:02 +0000443 seg = seg->next;
444 }
445 return size;
446}
447
Paul Jakma2815e612006-09-14 02:56:07 +0000448/* Return highest public ASN in path */
449as_t
450aspath_highest (struct aspath *aspath)
451{
452 struct assegment *seg = aspath->segments;
453 as_t highest = 0;
454 unsigned int i;
455
456 while (seg)
457 {
458 for (i = 0; i < seg->length; i++)
459 if (seg->as[i] > highest
460 && (seg->as[i] < BGP_PRIVATE_AS_MIN
461 || seg->as[i] > BGP_PRIVATE_AS_MAX))
462 highest = seg->as[i];
463 seg = seg->next;
464 }
465 return highest;
466}
467
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000468/* Return 1 if there are any 4-byte ASes in the path */
469unsigned int
470aspath_has_as4 (struct aspath *aspath)
471{
472 struct assegment *seg = aspath->segments;
473 unsigned int i;
474
475 while (seg)
476 {
477 for (i = 0; i < seg->length; i++)
478 if (seg->as[i] > BGP_AS_MAX)
479 return 1;
480 seg = seg->next;
481 }
482 return 0;
483}
484
485/* Return number of as numbers in in path */
486unsigned int
487aspath_count_numas (struct aspath *aspath)
488{
489 struct assegment *seg = aspath->segments;
490 unsigned int num;
491
492 num=0;
493 while (seg)
494 {
495 num += seg->length;
496 seg = seg->next;
497 }
498 return num;
499}
500
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400501static void
502aspath_make_str_big_enough (int len,
503 char **str_buf,
504 int *str_size,
505 int count_to_be_added)
506{
507#define TERMINATOR 1
508 while (len + count_to_be_added + TERMINATOR > *str_size)
509 {
510 *str_size *= 2;
511 *str_buf = XREALLOC (MTYPE_AS_STR, *str_buf, *str_size);
512 }
513#undef TERMINATOR
514}
515
paul718e3742002-12-13 20:15:29 +0000516/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000517static char *
paul718e3742002-12-13 20:15:29 +0000518aspath_make_str_count (struct aspath *as)
519{
paulfe69a502005-09-10 16:55:02 +0000520 struct assegment *seg;
521 int str_size;
522 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000523 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000524
525 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000526 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000527 {
528 str_buf = XMALLOC (MTYPE_AS_STR, 1);
529 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000530 return str_buf;
531 }
paulfe69a502005-09-10 16:55:02 +0000532
533 seg = as->segments;
534
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400535 str_size = ASPATH_STR_DEFAULT_LEN;
paul718e3742002-12-13 20:15:29 +0000536 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000537
paulfe69a502005-09-10 16:55:02 +0000538 while (seg)
paul718e3742002-12-13 20:15:29 +0000539 {
540 int i;
paulfe69a502005-09-10 16:55:02 +0000541 char seperator;
paul718e3742002-12-13 20:15:29 +0000542
paulfe69a502005-09-10 16:55:02 +0000543 /* Check AS type validity. Set seperator for segment */
544 switch (seg->type)
545 {
546 case AS_SET:
547 case AS_CONFED_SET:
548 seperator = ',';
549 break;
550 case AS_SEQUENCE:
551 case AS_CONFED_SEQUENCE:
552 seperator = ' ';
553 break;
554 default:
555 XFREE (MTYPE_AS_STR, str_buf);
556 return NULL;
557 }
558
paulfe69a502005-09-10 16:55:02 +0000559 if (seg->type != AS_SEQUENCE)
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400560 {
561 aspath_make_str_big_enough (len, &str_buf, &str_size, 1); /* %c */
562 len += snprintf (str_buf + len, str_size - len,
563 "%c",
564 aspath_delimiter_char (seg->type, AS_SEG_START));
565 }
paulfe69a502005-09-10 16:55:02 +0000566
567 /* write out the ASNs, with their seperators, bar the last one*/
568 for (i = 0; i < seg->length; i++)
569 {
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400570#define APPROX_DIG_CNT(x) (x < 100000U ? 5 : 10)
571 /* %u + %c + %c + " " (last two are below loop) */
572 aspath_make_str_big_enough (len,
573 &str_buf,
574 &str_size,
575 APPROX_DIG_CNT(seg->as[i]) + 1 + 1 + 1);
576
paulfe69a502005-09-10 16:55:02 +0000577 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
578
579 if (i < (seg->length - 1))
580 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
581 }
582
583 if (seg->type != AS_SEQUENCE)
584 len += snprintf (str_buf + len, str_size - len, "%c",
585 aspath_delimiter_char (seg->type, AS_SEG_END));
586 if (seg->next)
587 len += snprintf (str_buf + len, str_size - len, " ");
588
589 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000590 }
paulfe69a502005-09-10 16:55:02 +0000591
592 assert (len < str_size);
593
594 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000595
596 return str_buf;
597}
598
paulfe69a502005-09-10 16:55:02 +0000599static void
600aspath_str_update (struct aspath *as)
601{
602 if (as->str)
603 XFREE (MTYPE_AS_STR, as->str);
604 as->str = aspath_make_str_count (as);
605}
606
paul718e3742002-12-13 20:15:29 +0000607/* Intern allocated AS path. */
608struct aspath *
609aspath_intern (struct aspath *aspath)
610{
611 struct aspath *find;
612
613 /* Assert this AS path structure is not interned. */
614 assert (aspath->refcnt == 0);
615
616 /* Check AS path hash. */
617 find = hash_get (ashash, aspath, hash_alloc_intern);
618
619 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000620 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000621
622 find->refcnt++;
623
624 if (! find->str)
625 find->str = aspath_make_str_count (find);
626
627 return find;
628}
629
630/* Duplicate aspath structure. Created same aspath structure but
631 reference count and AS path string is cleared. */
632struct aspath *
633aspath_dup (struct aspath *aspath)
634{
635 struct aspath *new;
636
paulfe69a502005-09-10 16:55:02 +0000637 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000638
paulfe69a502005-09-10 16:55:02 +0000639 if (aspath->segments)
640 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000641 else
paulfe69a502005-09-10 16:55:02 +0000642 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000643
paulfe69a502005-09-10 16:55:02 +0000644 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000645
646 return new;
647}
648
paul94f2b392005-06-28 12:44:16 +0000649static void *
paulfe69a502005-09-10 16:55:02 +0000650aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000651{
652 struct aspath *aspath;
653
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000654 /* New aspath structure is needed. */
paulfe69a502005-09-10 16:55:02 +0000655 aspath = aspath_dup (arg);
656
paul718e3742002-12-13 20:15:29 +0000657 /* Malformed AS path value. */
658 if (! aspath->str)
659 {
660 aspath_free (aspath);
661 return NULL;
662 }
663
664 return aspath;
665}
666
paulfe69a502005-09-10 16:55:02 +0000667/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000668static struct assegment *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000669assegments_parse (struct stream *s, size_t length, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000670{
671 struct assegment_header segh;
672 struct assegment *seg, *prev = NULL, *head = NULL;
673 size_t bytes = 0;
674
675 /* empty aspath (ie iBGP or somesuch) */
676 if (length == 0)
677 return NULL;
678
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000679 if (BGP_DEBUG (as4, AS4_SEGMENT))
680 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
681 (unsigned long) length);
paulfe69a502005-09-10 16:55:02 +0000682 /* basic checks */
683 if ( (STREAM_READABLE(s) < length)
684 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000685 || (length % AS16_VALUE_SIZE ))
paulfe69a502005-09-10 16:55:02 +0000686 return NULL;
687
688 while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
689 && (bytes < length))
690 {
691 int i;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000692 int seg_size;
paulfe69a502005-09-10 16:55:02 +0000693
694 /* softly softly, get the header first on its own */
695 segh.type = stream_getc (s);
696 segh.length = stream_getc (s);
697
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000698 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
699
700 if (BGP_DEBUG (as4, AS4_SEGMENT))
701 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
702 segh.type, segh.length);
703
paulfe69a502005-09-10 16:55:02 +0000704 /* check it.. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000705 if ( ((bytes + seg_size) > length)
paulfe69a502005-09-10 16:55:02 +0000706 /* 1771bis 4.3b: seg length contains one or more */
707 || (segh.length == 0)
708 /* Paranoia in case someone changes type of segment length */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000709 || ((sizeof segh.length > 1) && (segh.length > AS_SEGMENT_MAX)) )
paulfe69a502005-09-10 16:55:02 +0000710 {
711 if (head)
712 assegment_free_all (head);
713 return NULL;
714 }
715
716 /* now its safe to trust lengths */
717 seg = assegment_new (segh.type, segh.length);
718
719 if (head)
720 prev->next = seg;
721 else /* it's the first segment */
722 head = prev = seg;
723
724 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000725 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
726
727 bytes += seg_size;
paulfe69a502005-09-10 16:55:02 +0000728
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000729 if (BGP_DEBUG (as4, AS4_SEGMENT))
730 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
731 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000732
733 prev = seg;
734 }
735
736 return assegment_normalise (head);
737}
738
paul718e3742002-12-13 20:15:29 +0000739/* AS path parse function. pnt is a pointer to byte stream and length
740 is length of byte stream. If there is same AS path in the the AS
741 path hash then return it else make new AS path structure. */
742struct aspath *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000743aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000744{
745 struct aspath as;
746 struct aspath *find;
747
748 /* If length is odd it's malformed AS path. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000749 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
750 * otherwise its malformed when length is larger than 2 and (length-2)
751 * is not dividable by 4.
752 * But... this time we're lazy
753 */
754 if (length % AS16_VALUE_SIZE )
paul718e3742002-12-13 20:15:29 +0000755 return NULL;
756
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000757 memset (&as, 0, sizeof (struct aspath));
758 as.segments = assegments_parse (s, length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000759
paul718e3742002-12-13 20:15:29 +0000760 /* If already same aspath exist then return it. */
761 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000762
763 /* aspath_hash_alloc dupes segments too. that probably could be
764 * optimised out.
765 */
766 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000767 if (as.str)
768 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000769
paul718e3742002-12-13 20:15:29 +0000770 if (! find)
771 return NULL;
772 find->refcnt++;
773
774 return find;
775}
776
paulfe69a502005-09-10 16:55:02 +0000777static inline void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000778assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000779{
paulfe69a502005-09-10 16:55:02 +0000780 int i;
781 assert (num <= AS_SEGMENT_MAX);
782
783 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000784 if ( use32bit )
785 stream_putl (s, as[i]);
786 else
787 {
788 if ( as[i] <= BGP_AS_MAX )
789 stream_putw(s, as[i]);
790 else
791 stream_putw(s, BGP_AS_TRANS);
792 }
paul718e3742002-12-13 20:15:29 +0000793}
794
paulfe69a502005-09-10 16:55:02 +0000795static inline size_t
796assegment_header_put (struct stream *s, u_char type, int length)
797{
798 size_t lenp;
799 assert (length <= AS_SEGMENT_MAX);
800 stream_putc (s, type);
801 lenp = stream_get_endp (s);
802 stream_putc (s, length);
803 return lenp;
804}
805
806/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000807size_t
808aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000809{
810 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000811 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000812
813 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000814 return 0;
paulfe69a502005-09-10 16:55:02 +0000815
816 if (seg)
817 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000818 /*
819 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
820 * At the moment, we would write out a partial aspath, and our peer
821 * will complain and drop the session :-/
822 *
823 * The general assumption here is that many things tested will
824 * never happen. And, in real live, up to now, they have not.
825 */
826 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000827 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000828 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000829 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000830 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000831 size_t lenp;
832
833 /* Overlength segments have to be split up */
834 while ( (seg->length - written) > AS_SEGMENT_MAX)
835 {
836 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000837 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000838 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000839 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000840 }
841
842 /* write the final segment, probably is also the first */
843 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000844 assegment_data_put (s, (seg->as + written), seg->length - written,
845 use32bit);
paulfe69a502005-09-10 16:55:02 +0000846
847 /* Sequence-type segments can be 'packed' together
848 * Case of a segment which was overlength and split up
849 * will be missed here, but that doesn't matter.
850 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000851 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000852 {
853 /* NB: We should never normally get here given we
854 * normalise aspath data when parse them. However, better
855 * safe than sorry. We potentially could call
856 * assegment_normalise here instead, but it's cheaper and
857 * easier to do it on the fly here rather than go through
858 * the segment list twice every time we write out
859 * aspath's.
860 */
861
862 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000863 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000864
865 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000866 stream_putc_at (s, lenp, seg->length - written + next->length);
867 asns_packed += next->length;
868
869 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000870 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000871
872 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
873 use32bit);
874 seg = next;
paulfe69a502005-09-10 16:55:02 +0000875 }
876 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000877 return bytes;
paulfe69a502005-09-10 16:55:02 +0000878}
879
880/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
881 * We have no way to manage the storage, so we use a static stream
882 * wrapper around aspath_put.
883 */
884u_char *
885aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
886{
887#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000888
889 if (!snmp_stream)
890 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000891 else
paul8fdc32a2006-01-16 12:01:29 +0000892 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000893
894 if (!as)
895 {
896 *varlen = 0;
897 return NULL;
898 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000899 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000900
paul8fdc32a2006-01-16 12:01:29 +0000901 *varlen = stream_get_endp (snmp_stream);
902 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000903}
904
905#define min(A,B) ((A) < (B) ? (A) : (B))
906
paul94f2b392005-06-28 12:44:16 +0000907static struct assegment *
paul718e3742002-12-13 20:15:29 +0000908aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
909 as_t as)
910{
911 int i;
912
913 /* If this is first AS set member, create new as-set segment. */
914 if (asset == NULL)
915 {
paulfe69a502005-09-10 16:55:02 +0000916 asset = assegment_new (AS_SET, 1);
917 if (! aspath->segments)
918 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000919 else
paulfe69a502005-09-10 16:55:02 +0000920 {
921 struct assegment *seg = aspath->segments;
922 while (seg->next)
923 seg = seg->next;
924 seg->next = asset;
925 }
paul718e3742002-12-13 20:15:29 +0000926 asset->type = AS_SET;
927 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000928 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000929 }
930 else
931 {
paul718e3742002-12-13 20:15:29 +0000932 /* Check this AS value already exists or not. */
933 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000934 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000935 return asset;
paulfe69a502005-09-10 16:55:02 +0000936
paul718e3742002-12-13 20:15:29 +0000937 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000938 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
939 asset->length * AS_VALUE_SIZE);
940 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000941 }
paulfe69a502005-09-10 16:55:02 +0000942
paul718e3742002-12-13 20:15:29 +0000943
944 return asset;
945}
946
947/* Modify as1 using as2 for aggregation. */
948struct aspath *
949aspath_aggregate (struct aspath *as1, struct aspath *as2)
950{
951 int i;
952 int minlen;
953 int match;
paulfe69a502005-09-10 16:55:02 +0000954 int from;
955 struct assegment *seg1 = as1->segments;
956 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000957 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000958 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000959 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +0000960
961 match = 0;
962 minlen = 0;
963 aspath = NULL;
964 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000965
966 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000967 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000968 {
paul718e3742002-12-13 20:15:29 +0000969 /* Check segment type. */
970 if (seg1->type != seg2->type)
971 break;
972
973 /* Minimum segment length. */
974 minlen = min (seg1->length, seg2->length);
975
976 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +0000977 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +0000978 break;
979
980 if (match)
981 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000982 struct assegment *seg = assegment_new (seg1->type, 0);
983
984 seg = assegment_append_asns (seg, seg1->as, match);
985
paul718e3742002-12-13 20:15:29 +0000986 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000987 {
988 aspath = aspath_new ();
989 aspath->segments = seg;
990 }
991 else
992 prevseg->next = seg;
993
994 prevseg = seg;
paul718e3742002-12-13 20:15:29 +0000995 }
996
997 if (match != minlen || match != seg1->length
998 || seg1->length != seg2->length)
999 break;
paulfe69a502005-09-10 16:55:02 +00001000
1001 seg1 = seg1->next;
1002 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001003 }
1004
1005 if (! aspath)
1006 aspath = aspath_new();
1007
1008 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001009 from = match;
1010 while (seg1)
paul718e3742002-12-13 20:15:29 +00001011 {
paulfe69a502005-09-10 16:55:02 +00001012 for (i = from; i < seg1->length; i++)
1013 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1014
1015 from = 0;
1016 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001017 }
1018
paulfe69a502005-09-10 16:55:02 +00001019 from = match;
1020 while (seg2)
paul718e3742002-12-13 20:15:29 +00001021 {
paulfe69a502005-09-10 16:55:02 +00001022 for (i = from; i < seg2->length; i++)
1023 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001024
paulfe69a502005-09-10 16:55:02 +00001025 from = 0;
1026 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001027 }
paulfe69a502005-09-10 16:55:02 +00001028
1029 assegment_normalise (aspath->segments);
1030 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001031 return aspath;
1032}
1033
1034/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1035 attribute, check the leftmost AS number in the AS_PATH attribute is
1036 or not the peer's AS number. */
1037int
1038aspath_firstas_check (struct aspath *aspath, as_t asno)
1039{
paulfe69a502005-09-10 16:55:02 +00001040 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001041 return 0;
paulfe69a502005-09-10 16:55:02 +00001042
1043 if (aspath->segments
1044 && (aspath->segments->type == AS_SEQUENCE)
1045 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001046 return 1;
1047
1048 return 0;
1049}
1050
Paul Jakma1f742f22006-08-06 15:52:11 +00001051/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001052int
1053aspath_loop_check (struct aspath *aspath, as_t asno)
1054{
paulfe69a502005-09-10 16:55:02 +00001055 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001056 int count = 0;
1057
Paul Jakma1f742f22006-08-06 15:52:11 +00001058 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001059 return 0;
paulfe69a502005-09-10 16:55:02 +00001060
1061 seg = aspath->segments;
1062
1063 while (seg)
paul718e3742002-12-13 20:15:29 +00001064 {
1065 int i;
paul718e3742002-12-13 20:15:29 +00001066
paulfe69a502005-09-10 16:55:02 +00001067 for (i = 0; i < seg->length; i++)
1068 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001069 count++;
paulfe69a502005-09-10 16:55:02 +00001070
1071 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001072 }
1073 return count;
1074}
1075
1076/* When all of AS path is private AS return 1. */
1077int
1078aspath_private_as_check (struct aspath *aspath)
1079{
paulfe69a502005-09-10 16:55:02 +00001080 struct assegment *seg;
1081
1082 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001083 return 0;
paulfe69a502005-09-10 16:55:02 +00001084
1085 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001086
paulfe69a502005-09-10 16:55:02 +00001087 while (seg)
paul718e3742002-12-13 20:15:29 +00001088 {
1089 int i;
paul718e3742002-12-13 20:15:29 +00001090
paulfe69a502005-09-10 16:55:02 +00001091 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001092 {
paulfe69a502005-09-10 16:55:02 +00001093 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1094 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001095 return 0;
1096 }
paulfe69a502005-09-10 16:55:02 +00001097 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001098 }
1099 return 1;
1100}
1101
1102/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001103static struct aspath *
paul718e3742002-12-13 20:15:29 +00001104aspath_merge (struct aspath *as1, struct aspath *as2)
1105{
paulfe69a502005-09-10 16:55:02 +00001106 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001107
1108 if (! as1 || ! as2)
1109 return NULL;
1110
paulfe69a502005-09-10 16:55:02 +00001111 last = new = assegment_dup_all (as1->segments);
1112
1113 /* find the last valid segment */
1114 while (last && last->next)
1115 last = last->next;
1116
1117 last->next = as2->segments;
1118 as2->segments = new;
1119 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001120 return as2;
1121}
1122
1123/* Prepend as1 to as2. as2 should be uninterned aspath. */
1124struct aspath *
1125aspath_prepend (struct aspath *as1, struct aspath *as2)
1126{
paulfe69a502005-09-10 16:55:02 +00001127 struct assegment *seg1;
1128 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001129
1130 if (! as1 || ! as2)
1131 return NULL;
paulfe69a502005-09-10 16:55:02 +00001132
1133 seg1 = as1->segments;
1134 seg2 = as2->segments;
1135
1136 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001137 if (seg2 == NULL)
1138 {
paulfe69a502005-09-10 16:55:02 +00001139 as2->segments = assegment_dup_all (as1->segments);
1140 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001141 return as2;
1142 }
paulfe69a502005-09-10 16:55:02 +00001143
1144 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001145 if (seg1 == NULL)
1146 return as2;
paulfe69a502005-09-10 16:55:02 +00001147
1148 /* find the tail as1's segment chain. */
1149 while (seg1 && seg1->next)
1150 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001151
1152 /* Compare last segment type of as1 and first segment type of as2. */
1153 if (seg1->type != seg2->type)
1154 return aspath_merge (as1, as2);
1155
1156 if (seg1->type == AS_SEQUENCE)
1157 {
paulfe69a502005-09-10 16:55:02 +00001158 /* We have two chains of segments, as1->segments and seg2,
1159 * and we have to attach them together, merging the attaching
1160 * segments together into one.
1161 *
1162 * 1. dupe as1->segments onto head of as2
1163 * 2. merge seg2's asns onto last segment of this new chain
1164 * 3. attach chain after seg2
1165 */
paul718e3742002-12-13 20:15:29 +00001166
paulfe69a502005-09-10 16:55:02 +00001167 /* dupe as1 onto as2's head */
1168 seg1 = as2->segments = assegment_dup_all (as1->segments);
1169
1170 /* refind the tail of as2, reusing seg1 */
1171 while (seg1 && seg1->next)
1172 seg1 = seg1->next;
1173
1174 /* merge the old head, seg2, into tail, seg1 */
1175 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1176
1177 /* bypass the merged seg2, and attach any chain after it to
1178 * chain descending from as2's head
1179 */
1180 seg1->next = seg2->next;
1181
1182 /* seg2 is now referenceless and useless*/
1183 assegment_free (seg2);
1184
1185 /* we've now prepended as1's segment chain to as2, merging
1186 * the inbetween AS_SEQUENCE of seg2 in the process
1187 */
1188 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001189 return as2;
1190 }
1191 else
1192 {
1193 /* AS_SET merge code is needed at here. */
1194 return aspath_merge (as1, as2);
1195 }
paulfe69a502005-09-10 16:55:02 +00001196 /* XXX: Ermmm, what if as1 has multiple segments?? */
1197
paul718e3742002-12-13 20:15:29 +00001198 /* Not reached */
1199}
1200
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001201/* Iterate over AS_PATH segments and wipe all occurences of the
1202 * listed AS numbers. Hence some segments may lose some or even
1203 * all data on the way, the operation is implemented as a smarter
1204 * version of aspath_dup(), which allocates memory to hold the new
1205 * data, not the original. The new AS path is returned.
1206 */
1207struct aspath *
1208aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1209{
1210 struct assegment * srcseg, * exclseg, * lastseg;
1211 struct aspath * newpath;
1212
1213 newpath = aspath_new();
1214 lastseg = NULL;
1215
1216 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1217 {
1218 unsigned i, y, newlen = 0, done = 0, skip_as;
1219 struct assegment * newseg;
1220
1221 /* Find out, how much ASns are we going to pick from this segment.
1222 * We can't perform filtering right inline, because the size of
1223 * the new segment isn't known at the moment yet.
1224 */
1225 for (i = 0; i < srcseg->length; i++)
1226 {
1227 skip_as = 0;
1228 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1229 for (y = 0; y < exclseg->length; y++)
1230 if (srcseg->as[i] == exclseg->as[y])
1231 {
1232 skip_as = 1;
1233 // There's no sense in testing the rest of exclusion list, bail out.
1234 break;
1235 }
1236 if (!skip_as)
1237 newlen++;
1238 }
1239 /* newlen is now the number of ASns to copy */
1240 if (!newlen)
1241 continue;
1242
1243 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1244 newseg = assegment_new (srcseg->type, newlen);
1245 for (i = 0; i < srcseg->length; i++)
1246 {
1247 skip_as = 0;
1248 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1249 for (y = 0; y < exclseg->length; y++)
1250 if (srcseg->as[i] == exclseg->as[y])
1251 {
1252 skip_as = 1;
1253 break;
1254 }
1255 if (skip_as)
1256 continue;
1257 newseg->as[done++] = srcseg->as[i];
1258 }
1259 /* At his point newlen must be equal to done, and both must be positive. Append
1260 * the filtered segment to the gross result. */
1261 if (!lastseg)
1262 newpath->segments = newseg;
1263 else
1264 lastseg->next = newseg;
1265 lastseg = newseg;
1266 }
1267 aspath_str_update (newpath);
1268 /* We are happy returning even an empty AS_PATH, because the administrator
1269 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1270 * by having a match rule against certain AS_PATH regexps in the route-map index.
1271 */
1272 aspath_free (source);
1273 return newpath;
1274}
1275
paul718e3742002-12-13 20:15:29 +00001276/* Add specified AS to the leftmost of aspath. */
1277static struct aspath *
1278aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1279{
paulfe69a502005-09-10 16:55:02 +00001280 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001281
1282 /* In case of empty aspath. */
1283 if (assegment == NULL || assegment->length == 0)
1284 {
paulfe69a502005-09-10 16:55:02 +00001285 aspath->segments = assegment_new (type, 1);
1286 aspath->segments->as[0] = asno;
1287
paul718e3742002-12-13 20:15:29 +00001288 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001289 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001290
1291 return aspath;
1292 }
1293
1294 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001295 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1296 else
paul718e3742002-12-13 20:15:29 +00001297 {
paulfe69a502005-09-10 16:55:02 +00001298 /* create new segment
1299 * push it onto head of aspath's segment chain
1300 */
paul718e3742002-12-13 20:15:29 +00001301 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001302
1303 newsegment = assegment_new (type, 1);
1304 newsegment->as[0] = asno;
1305
1306 newsegment->next = assegment;
1307 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001308 }
1309
1310 return aspath;
1311}
1312
1313/* Add specified AS to the leftmost of aspath. */
1314struct aspath *
1315aspath_add_seq (struct aspath *aspath, as_t asno)
1316{
1317 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1318}
1319
1320/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1321 as2's leftmost AS is same return 1. */
1322int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001323aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001324{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001325 const struct assegment *seg1 = NULL;
1326 const struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001327
paulfe69a502005-09-10 16:55:02 +00001328 if (!(aspath1 && aspath2))
1329 return 0;
paul718e3742002-12-13 20:15:29 +00001330
paulfe69a502005-09-10 16:55:02 +00001331 seg1 = aspath1->segments;
1332 seg2 = aspath2->segments;
1333
1334 /* find first non-confed segments for each */
1335 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1336 || (seg1->type == AS_CONFED_SET)))
1337 seg1 = seg1->next;
1338
1339 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1340 || (seg2->type == AS_CONFED_SET)))
1341 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001342
1343 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001344 if (!(seg1 && seg2
1345 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001346 return 0;
paulfe69a502005-09-10 16:55:02 +00001347
1348 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001349 return 1;
1350
1351 return 0;
1352}
1353
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001354/* Truncate an aspath after a number of hops, and put the hops remaining
1355 * at the front of another aspath. Needed for AS4 compat.
1356 *
1357 * Returned aspath is a /new/ aspath, which should either by free'd or
1358 * interned by the caller, as desired.
1359 */
1360struct aspath *
1361aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1362{
1363 struct assegment *seg, *newseg, *prevseg = NULL;
1364 struct aspath *newpath = NULL, *mergedpath;
1365 int hops, cpasns = 0;
1366
1367 if (!aspath)
1368 return NULL;
1369
1370 seg = aspath->segments;
1371
1372 /* CONFEDs should get reconciled too.. */
1373 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1374 - aspath_count_hops (as4path);
1375
1376 if (hops < 0)
1377 {
1378 if (BGP_DEBUG (as4, AS4))
1379 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1380 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1381 * which is daft behaviour - it contains vital loop-detection
1382 * information which must have been removed from AS_PATH.
1383 */
1384 hops = aspath_count_hops (aspath);
1385 }
1386
1387 if (!hops)
1388 return aspath_dup (as4path);
1389
1390 if ( BGP_DEBUG(as4, AS4))
1391 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1392 aspath->str, as4path->str);
1393
1394 while (seg && hops > 0)
1395 {
1396 switch (seg->type)
1397 {
1398 case AS_SET:
1399 case AS_CONFED_SET:
1400 hops--;
1401 cpasns = seg->length;
1402 break;
1403 case AS_CONFED_SEQUENCE:
1404 /* Should never split a confed-sequence, if hop-count
1405 * suggests we must then something's gone wrong somewhere.
1406 *
1407 * Most important goal is to preserve AS_PATHs prime function
1408 * as loop-detector, so we fudge the numbers so that the entire
1409 * confed-sequence is merged in.
1410 */
1411 if (hops < seg->length)
1412 {
1413 if (BGP_DEBUG (as4, AS4))
1414 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1415 " across 2/4 ASN boundary somewhere, broken..");
1416 hops = seg->length;
1417 }
1418 case AS_SEQUENCE:
1419 cpasns = MIN(seg->length, hops);
1420 hops -= seg->length;
1421 }
1422
1423 assert (cpasns <= seg->length);
1424
1425 newseg = assegment_new (seg->type, 0);
1426 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1427
1428 if (!newpath)
1429 {
1430 newpath = aspath_new ();
1431 newpath->segments = newseg;
1432 }
1433 else
1434 prevseg->next = newseg;
1435
1436 prevseg = newseg;
1437 seg = seg->next;
1438 }
1439
1440 /* We may be able to join some segments here, and we must
1441 * do this because... we want normalised aspaths in out hash
1442 * and we do not want to stumble in aspath_put.
1443 */
1444 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1445 aspath_free (newpath);
1446 mergedpath->segments = assegment_normalise (mergedpath->segments);
1447 aspath_str_update (mergedpath);
1448
1449 if ( BGP_DEBUG(as4, AS4))
1450 zlog_debug ("[AS4] result of synthesizing is %s",
1451 mergedpath->str);
1452
1453 return mergedpath;
1454}
1455
paul718e3742002-12-13 20:15:29 +00001456/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1457 as2's leftmost AS is same return 1. (confederation as-path
1458 only). */
1459int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001460aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
paul718e3742002-12-13 20:15:29 +00001461{
paulfe69a502005-09-10 16:55:02 +00001462 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001463 return 0;
paulfe69a502005-09-10 16:55:02 +00001464
paulad727402005-11-23 02:47:02 +00001465 if ( !(aspath1->segments && aspath2->segments) )
1466 return 0;
1467
paulfe69a502005-09-10 16:55:02 +00001468 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1469 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001470 return 0;
paulfe69a502005-09-10 16:55:02 +00001471
1472 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001473 return 1;
1474
1475 return 0;
1476}
1477
paulfe69a502005-09-10 16:55:02 +00001478/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1479 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001480struct aspath *
1481aspath_delete_confed_seq (struct aspath *aspath)
1482{
paulfe69a502005-09-10 16:55:02 +00001483 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001484
paulfe69a502005-09-10 16:55:02 +00001485 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001486 return aspath;
1487
paulfe69a502005-09-10 16:55:02 +00001488 seg = aspath->segments;
1489
1490 /* "if the first path segment of the AS_PATH is
1491 * of type AS_CONFED_SEQUENCE,"
1492 */
1493 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1494 return aspath;
paul718e3742002-12-13 20:15:29 +00001495
paulfe69a502005-09-10 16:55:02 +00001496 /* "... that segment and any immediately following segments
1497 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1498 * from the AS_PATH attribute,"
1499 */
1500 while (seg &&
1501 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001502 {
paulfe69a502005-09-10 16:55:02 +00001503 aspath->segments = seg->next;
1504 assegment_free (seg);
1505 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001506 }
paulfe69a502005-09-10 16:55:02 +00001507 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001508 return aspath;
1509}
1510
1511/* Add new AS number to the leftmost part of the aspath as
1512 AS_CONFED_SEQUENCE. */
1513struct aspath*
1514aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1515{
1516 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1517}
1518
1519/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001520static void
paul718e3742002-12-13 20:15:29 +00001521aspath_as_add (struct aspath *as, as_t asno)
1522{
paulfe69a502005-09-10 16:55:02 +00001523 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001524
paulfe69a502005-09-10 16:55:02 +00001525 if (!seg)
1526 return;
1527
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001528 /* Last segment search procedure. */
1529 while (seg->next)
1530 seg = seg->next;
1531
paulfe69a502005-09-10 16:55:02 +00001532 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001533}
1534
1535/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001536static void
paul718e3742002-12-13 20:15:29 +00001537aspath_segment_add (struct aspath *as, int type)
1538{
paulfe69a502005-09-10 16:55:02 +00001539 struct assegment *seg = as->segments;
1540 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001541
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001542 if (seg)
1543 {
1544 while (seg->next)
1545 seg = seg->next;
1546 seg->next = new;
1547 }
paul718e3742002-12-13 20:15:29 +00001548 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001549 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001550}
1551
1552struct aspath *
paul94f2b392005-06-28 12:44:16 +00001553aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001554{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001555 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001556}
1557
1558struct aspath *
paul94f2b392005-06-28 12:44:16 +00001559aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001560{
1561 struct aspath *aspath;
1562
1563 aspath = aspath_new ();
1564 aspath->str = aspath_make_str_count (aspath);
1565 return aspath;
1566}
1567
1568unsigned long
paulfe69a502005-09-10 16:55:02 +00001569aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001570{
1571 return ashash->count;
1572}
1573
1574/*
1575 Theoretically, one as path can have:
1576
1577 One BGP packet size should be less than 4096.
1578 One BGP attribute size should be less than 4096 - BGP header size.
1579 One BGP aspath size should be less than 4096 - BGP header size -
1580 BGP mandantry attribute size.
1581*/
1582
1583/* AS path string lexical token enum. */
1584enum as_token
1585{
1586 as_token_asval,
1587 as_token_set_start,
1588 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001589 as_token_confed_seq_start,
1590 as_token_confed_seq_end,
1591 as_token_confed_set_start,
1592 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001593 as_token_unknown
1594};
1595
1596/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001597static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001598aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001599{
paulfd79ac92004-10-13 05:06:08 +00001600 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001601
paulfe69a502005-09-10 16:55:02 +00001602 /* Skip seperators (space for sequences, ',' for sets). */
1603 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001604 p++;
1605
1606 /* Check the end of the string and type specify characters
1607 (e.g. {}()). */
1608 switch (*p)
1609 {
1610 case '\0':
1611 return NULL;
paul718e3742002-12-13 20:15:29 +00001612 case '{':
1613 *token = as_token_set_start;
1614 p++;
1615 return p;
paul718e3742002-12-13 20:15:29 +00001616 case '}':
1617 *token = as_token_set_end;
1618 p++;
1619 return p;
paul718e3742002-12-13 20:15:29 +00001620 case '(':
paulfe69a502005-09-10 16:55:02 +00001621 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001622 p++;
1623 return p;
paul718e3742002-12-13 20:15:29 +00001624 case ')':
paulfe69a502005-09-10 16:55:02 +00001625 *token = as_token_confed_seq_end;
1626 p++;
1627 return p;
paulfe69a502005-09-10 16:55:02 +00001628 case '[':
1629 *token = as_token_confed_set_start;
1630 p++;
1631 return p;
paulfe69a502005-09-10 16:55:02 +00001632 case ']':
1633 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001634 p++;
1635 return p;
paul718e3742002-12-13 20:15:29 +00001636 }
1637
1638 /* Check actual AS value. */
1639 if (isdigit ((int) *p))
1640 {
Denis Ovsienko10819ec2009-06-09 15:15:33 +04001641 as_t asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001642
paul718e3742002-12-13 20:15:29 +00001643 *token = as_token_asval;
1644 asval = (*p - '0');
1645 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001646
paul718e3742002-12-13 20:15:29 +00001647 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001648 {
1649 asval *= 10;
1650 asval += (*p - '0');
1651 p++;
1652 }
paul718e3742002-12-13 20:15:29 +00001653 *asno = asval;
1654 return p;
1655 }
1656
1657 /* There is no match then return unknown token. */
1658 *token = as_token_unknown;
1659 return p++;
1660}
1661
1662struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001663aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001664{
paul3fff6ff2006-02-05 17:55:35 +00001665 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001666 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001667 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001668 struct aspath *aspath;
1669 int needtype;
1670
1671 aspath = aspath_new ();
1672
1673 /* We start default type as AS_SEQUENCE. */
1674 as_type = AS_SEQUENCE;
1675 needtype = 1;
1676
1677 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1678 {
1679 switch (token)
1680 {
1681 case as_token_asval:
1682 if (needtype)
1683 {
1684 aspath_segment_add (aspath, as_type);
1685 needtype = 0;
1686 }
1687 aspath_as_add (aspath, asno);
1688 break;
1689 case as_token_set_start:
1690 as_type = AS_SET;
1691 aspath_segment_add (aspath, as_type);
1692 needtype = 0;
1693 break;
1694 case as_token_set_end:
1695 as_type = AS_SEQUENCE;
1696 needtype = 1;
1697 break;
paulfe69a502005-09-10 16:55:02 +00001698 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001699 as_type = AS_CONFED_SEQUENCE;
1700 aspath_segment_add (aspath, as_type);
1701 needtype = 0;
1702 break;
paulfe69a502005-09-10 16:55:02 +00001703 case as_token_confed_seq_end:
1704 as_type = AS_SEQUENCE;
1705 needtype = 1;
1706 break;
1707 case as_token_confed_set_start:
1708 as_type = AS_CONFED_SET;
1709 aspath_segment_add (aspath, as_type);
1710 needtype = 0;
1711 break;
1712 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001713 as_type = AS_SEQUENCE;
1714 needtype = 1;
1715 break;
1716 case as_token_unknown:
1717 default:
paulfe69a502005-09-10 16:55:02 +00001718 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001719 return NULL;
paul718e3742002-12-13 20:15:29 +00001720 }
1721 }
1722
1723 aspath->str = aspath_make_str_count (aspath);
1724
1725 return aspath;
1726}
1727
1728/* Make hash value by raw aspath data. */
1729unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001730aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001731{
Paul Jakma923de652007-04-29 18:25:17 +00001732 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001733 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001734
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001735 if (!aspath->str)
1736 aspath_str_update (aspath);
1737
1738 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001739
1740 return key;
1741}
1742
1743/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001744static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +01001745aspath_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +00001746{
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001747 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1748 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
paulfe69a502005-09-10 16:55:02 +00001749
1750 while (seg1 || seg2)
1751 {
1752 int i;
1753 if ((!seg1 && seg2) || (seg1 && !seg2))
1754 return 0;
1755 if (seg1->type != seg2->type)
1756 return 0;
1757 if (seg1->length != seg2->length)
1758 return 0;
1759 for (i = 0; i < seg1->length; i++)
1760 if (seg1->as[i] != seg2->as[i])
1761 return 0;
1762 seg1 = seg1->next;
1763 seg2 = seg2->next;
1764 }
1765 return 1;
paul718e3742002-12-13 20:15:29 +00001766}
1767
1768/* AS path hash initialize. */
1769void
paul94f2b392005-06-28 12:44:16 +00001770aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001771{
1772 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1773}
paul8fdc32a2006-01-16 12:01:29 +00001774
1775void
1776aspath_finish (void)
1777{
1778 hash_free (ashash);
1779
1780 if (snmp_stream)
1781 stream_free (snmp_stream);
1782}
paul718e3742002-12-13 20:15:29 +00001783
1784/* return and as path value */
1785const char *
1786aspath_print (struct aspath *as)
1787{
paulfe69a502005-09-10 16:55:02 +00001788 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001789}
1790
1791/* Printing functions */
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001792/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1793 * AS_PATH wasn't empty.
1794 */
paul718e3742002-12-13 20:15:29 +00001795void
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001796aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
paul718e3742002-12-13 20:15:29 +00001797{
Paul Jakmab2518c12006-05-12 23:48:40 +00001798 assert (format);
1799 vty_out (vty, format, as->str);
Denis Ovsienko841f7a52008-04-10 11:47:45 +00001800 if (strlen (as->str) && strlen (suffix))
1801 vty_out (vty, "%s", suffix);
paul718e3742002-12-13 20:15:29 +00001802}
1803
paul94f2b392005-06-28 12:44:16 +00001804static void
paul718e3742002-12-13 20:15:29 +00001805aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1806{
1807 struct aspath *as;
1808
1809 as = (struct aspath *) backet->data;
1810
paulefa9f832002-12-13 21:47:59 +00001811 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001812 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1813}
1814
1815/* Print all aspath and hash information. This function is used from
1816 `show ip bgp paths' command. */
1817void
1818aspath_print_all_vty (struct vty *vty)
1819{
1820 hash_iterate (ashash,
1821 (void (*) (struct hash_backet *, void *))
1822 aspath_show_all_iterator,
1823 vty);
1824}