blob: d7e985d4f0b90f3dcef10fe51a77696e852a8d26 [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 +0000396/* countup asns from this segment and index onward */
397static int
398assegment_count_asns (struct assegment *seg, int from)
399{
400 int count = 0;
401 while (seg)
402 {
403 if (!from)
404 count += seg->length;
405 else
406 {
407 count += (seg->length - from);
408 from = 0;
409 }
410 seg = seg->next;
411 }
412 return count;
413}
414
415unsigned int
416aspath_count_confeds (struct aspath *aspath)
417{
418 int count = 0;
419 struct assegment *seg = aspath->segments;
420
421 while (seg)
422 {
423 if (seg->type == AS_CONFED_SEQUENCE)
424 count += seg->length;
425 else if (seg->type == AS_CONFED_SET)
426 count++;
427
428 seg = seg->next;
429 }
430 return count;
431}
432
433unsigned int
434aspath_count_hops (struct aspath *aspath)
435{
436 int count = 0;
437 struct assegment *seg = aspath->segments;
438
439 while (seg)
440 {
441 if (seg->type == AS_SEQUENCE)
442 count += seg->length;
443 else if (seg->type == AS_SET)
444 count++;
445
446 seg = seg->next;
447 }
448 return count;
449}
450
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000451/* Estimate size aspath /might/ take if encoded into an
452 * ASPATH attribute.
453 *
454 * This is a quick estimate, not definitive! aspath_put()
455 * may return a different number!!
456 */
paulfe69a502005-09-10 16:55:02 +0000457unsigned int
458aspath_size (struct aspath *aspath)
459{
460 int size = 0;
461 struct assegment *seg = aspath->segments;
462
463 while (seg)
464 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000465 size += ASSEGMENT_SIZE(seg->length, 1);
paulfe69a502005-09-10 16:55:02 +0000466 seg = seg->next;
467 }
468 return size;
469}
470
Paul Jakma2815e612006-09-14 02:56:07 +0000471/* Return highest public ASN in path */
472as_t
473aspath_highest (struct aspath *aspath)
474{
475 struct assegment *seg = aspath->segments;
476 as_t highest = 0;
477 unsigned int i;
478
479 while (seg)
480 {
481 for (i = 0; i < seg->length; i++)
482 if (seg->as[i] > highest
483 && (seg->as[i] < BGP_PRIVATE_AS_MIN
484 || seg->as[i] > BGP_PRIVATE_AS_MAX))
485 highest = seg->as[i];
486 seg = seg->next;
487 }
488 return highest;
489}
490
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000491/* Return 1 if there are any 4-byte ASes in the path */
492unsigned int
493aspath_has_as4 (struct aspath *aspath)
494{
495 struct assegment *seg = aspath->segments;
496 unsigned int i;
497
498 while (seg)
499 {
500 for (i = 0; i < seg->length; i++)
501 if (seg->as[i] > BGP_AS_MAX)
502 return 1;
503 seg = seg->next;
504 }
505 return 0;
506}
507
508/* Return number of as numbers in in path */
509unsigned int
510aspath_count_numas (struct aspath *aspath)
511{
512 struct assegment *seg = aspath->segments;
513 unsigned int num;
514
515 num=0;
516 while (seg)
517 {
518 num += seg->length;
519 seg = seg->next;
520 }
521 return num;
522}
523
paul718e3742002-12-13 20:15:29 +0000524/* Convert aspath structure to string expression. */
paul94f2b392005-06-28 12:44:16 +0000525static char *
paul718e3742002-12-13 20:15:29 +0000526aspath_make_str_count (struct aspath *as)
527{
paulfe69a502005-09-10 16:55:02 +0000528 struct assegment *seg;
529 int str_size;
530 int len = 0;
hassoc9e52be2004-09-26 16:09:34 +0000531 char *str_buf;
paul718e3742002-12-13 20:15:29 +0000532
533 /* Empty aspath. */
paulfe69a502005-09-10 16:55:02 +0000534 if (!as->segments)
paul718e3742002-12-13 20:15:29 +0000535 {
536 str_buf = XMALLOC (MTYPE_AS_STR, 1);
537 str_buf[0] = '\0';
paul718e3742002-12-13 20:15:29 +0000538 return str_buf;
539 }
paulfe69a502005-09-10 16:55:02 +0000540
541 seg = as->segments;
542
543 /* ASN takes 5 chars at least, plus seperator, see below.
544 * If there is one differing segment type, we need an additional
545 * 2 chars for segment delimiters, and the final '\0'.
546 * Hopefully this is large enough to avoid hitting the realloc
547 * code below for most common sequences.
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000548 *
549 * With 32bit ASNs, this range will increase, but only worth changing
550 * once there are significant numbers of ASN >= 100000
paulfe69a502005-09-10 16:55:02 +0000551 */
552#define ASN_STR_LEN (5 + 1)
553 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
554 ASPATH_STR_DEFAULT_LEN);
paul718e3742002-12-13 20:15:29 +0000555 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
paul718e3742002-12-13 20:15:29 +0000556
paulfe69a502005-09-10 16:55:02 +0000557 while (seg)
paul718e3742002-12-13 20:15:29 +0000558 {
559 int i;
paulfe69a502005-09-10 16:55:02 +0000560 char seperator;
paul718e3742002-12-13 20:15:29 +0000561
paulfe69a502005-09-10 16:55:02 +0000562 /* Check AS type validity. Set seperator for segment */
563 switch (seg->type)
564 {
565 case AS_SET:
566 case AS_CONFED_SET:
567 seperator = ',';
568 break;
569 case AS_SEQUENCE:
570 case AS_CONFED_SEQUENCE:
571 seperator = ' ';
572 break;
573 default:
574 XFREE (MTYPE_AS_STR, str_buf);
575 return NULL;
576 }
577
578 /* We might need to increase str_buf, particularly if path has
579 * differing segments types, our initial guesstimate above will
580 * have been wrong. need 5 chars for ASN, a seperator each and
581 * potentially two segment delimiters, plus a space between each
582 * segment and trailing zero.
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000583 *
584 * This may need to revised if/when significant numbers of
585 * ASNs >= 100000 are assigned and in-use on the internet...
paulfe69a502005-09-10 16:55:02 +0000586 */
587#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
588 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
589 {
590 str_size = len + SEGMENT_STR_LEN(seg);
591 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
592 }
593#undef ASN_STR_LEN
594#undef SEGMENT_STR_LEN
595
596 if (seg->type != AS_SEQUENCE)
597 len += snprintf (str_buf + len, str_size - len,
598 "%c",
599 aspath_delimiter_char (seg->type, AS_SEG_START));
600
601 /* write out the ASNs, with their seperators, bar the last one*/
602 for (i = 0; i < seg->length; i++)
603 {
604 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
605
606 if (i < (seg->length - 1))
607 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
608 }
609
610 if (seg->type != AS_SEQUENCE)
611 len += snprintf (str_buf + len, str_size - len, "%c",
612 aspath_delimiter_char (seg->type, AS_SEG_END));
613 if (seg->next)
614 len += snprintf (str_buf + len, str_size - len, " ");
615
616 seg = seg->next;
paul718e3742002-12-13 20:15:29 +0000617 }
paulfe69a502005-09-10 16:55:02 +0000618
619 assert (len < str_size);
620
621 str_buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000622
623 return str_buf;
624}
625
paulfe69a502005-09-10 16:55:02 +0000626static void
627aspath_str_update (struct aspath *as)
628{
629 if (as->str)
630 XFREE (MTYPE_AS_STR, as->str);
631 as->str = aspath_make_str_count (as);
632}
633
paul718e3742002-12-13 20:15:29 +0000634/* Intern allocated AS path. */
635struct aspath *
636aspath_intern (struct aspath *aspath)
637{
638 struct aspath *find;
639
640 /* Assert this AS path structure is not interned. */
641 assert (aspath->refcnt == 0);
642
643 /* Check AS path hash. */
644 find = hash_get (ashash, aspath, hash_alloc_intern);
645
646 if (find != aspath)
paulfe69a502005-09-10 16:55:02 +0000647 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +0000648
649 find->refcnt++;
650
651 if (! find->str)
652 find->str = aspath_make_str_count (find);
653
654 return find;
655}
656
657/* Duplicate aspath structure. Created same aspath structure but
658 reference count and AS path string is cleared. */
659struct aspath *
660aspath_dup (struct aspath *aspath)
661{
662 struct aspath *new;
663
paulfe69a502005-09-10 16:55:02 +0000664 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
paul718e3742002-12-13 20:15:29 +0000665
paulfe69a502005-09-10 16:55:02 +0000666 if (aspath->segments)
667 new->segments = assegment_dup_all (aspath->segments);
paul718e3742002-12-13 20:15:29 +0000668 else
paulfe69a502005-09-10 16:55:02 +0000669 new->segments = NULL;
paul718e3742002-12-13 20:15:29 +0000670
paulfe69a502005-09-10 16:55:02 +0000671 new->str = aspath_make_str_count (aspath);
paul718e3742002-12-13 20:15:29 +0000672
673 return new;
674}
675
paul94f2b392005-06-28 12:44:16 +0000676static void *
paulfe69a502005-09-10 16:55:02 +0000677aspath_hash_alloc (void *arg)
paul718e3742002-12-13 20:15:29 +0000678{
679 struct aspath *aspath;
680
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000681 /* New aspath structure is needed. */
paulfe69a502005-09-10 16:55:02 +0000682 aspath = aspath_dup (arg);
683
paul718e3742002-12-13 20:15:29 +0000684 /* Malformed AS path value. */
685 if (! aspath->str)
686 {
687 aspath_free (aspath);
688 return NULL;
689 }
690
691 return aspath;
692}
693
paulfe69a502005-09-10 16:55:02 +0000694/* parse as-segment byte stream in struct assegment */
paulad727402005-11-23 02:47:02 +0000695static struct assegment *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000696assegments_parse (struct stream *s, size_t length, int use32bit)
paulfe69a502005-09-10 16:55:02 +0000697{
698 struct assegment_header segh;
699 struct assegment *seg, *prev = NULL, *head = NULL;
700 size_t bytes = 0;
701
702 /* empty aspath (ie iBGP or somesuch) */
703 if (length == 0)
704 return NULL;
705
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000706 if (BGP_DEBUG (as4, AS4_SEGMENT))
707 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
708 (unsigned long) length);
paulfe69a502005-09-10 16:55:02 +0000709 /* basic checks */
710 if ( (STREAM_READABLE(s) < length)
711 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000712 || (length % AS16_VALUE_SIZE ))
paulfe69a502005-09-10 16:55:02 +0000713 return NULL;
714
715 while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
716 && (bytes < length))
717 {
718 int i;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000719 int seg_size;
paulfe69a502005-09-10 16:55:02 +0000720
721 /* softly softly, get the header first on its own */
722 segh.type = stream_getc (s);
723 segh.length = stream_getc (s);
724
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000725 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
726
727 if (BGP_DEBUG (as4, AS4_SEGMENT))
728 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
729 segh.type, segh.length);
730
paulfe69a502005-09-10 16:55:02 +0000731 /* check it.. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000732 if ( ((bytes + seg_size) > length)
paulfe69a502005-09-10 16:55:02 +0000733 /* 1771bis 4.3b: seg length contains one or more */
734 || (segh.length == 0)
735 /* Paranoia in case someone changes type of segment length */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000736 || ((sizeof segh.length > 1) && (segh.length > AS_SEGMENT_MAX)) )
paulfe69a502005-09-10 16:55:02 +0000737 {
738 if (head)
739 assegment_free_all (head);
740 return NULL;
741 }
742
743 /* now its safe to trust lengths */
744 seg = assegment_new (segh.type, segh.length);
745
746 if (head)
747 prev->next = seg;
748 else /* it's the first segment */
749 head = prev = seg;
750
751 for (i = 0; i < segh.length; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000752 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
753
754 bytes += seg_size;
paulfe69a502005-09-10 16:55:02 +0000755
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000756 if (BGP_DEBUG (as4, AS4_SEGMENT))
757 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
758 (unsigned long) bytes);
paulfe69a502005-09-10 16:55:02 +0000759
760 prev = seg;
761 }
762
763 return assegment_normalise (head);
764}
765
paul718e3742002-12-13 20:15:29 +0000766/* AS path parse function. pnt is a pointer to byte stream and length
767 is length of byte stream. If there is same AS path in the the AS
768 path hash then return it else make new AS path structure. */
769struct aspath *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000770aspath_parse (struct stream *s, size_t length, int use32bit)
paul718e3742002-12-13 20:15:29 +0000771{
772 struct aspath as;
773 struct aspath *find;
774
775 /* If length is odd it's malformed AS path. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000776 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
777 * otherwise its malformed when length is larger than 2 and (length-2)
778 * is not dividable by 4.
779 * But... this time we're lazy
780 */
781 if (length % AS16_VALUE_SIZE )
paul718e3742002-12-13 20:15:29 +0000782 return NULL;
783
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000784 memset (&as, 0, sizeof (struct aspath));
785 as.segments = assegments_parse (s, length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000786
paul718e3742002-12-13 20:15:29 +0000787 /* If already same aspath exist then return it. */
788 find = hash_get (ashash, &as, aspath_hash_alloc);
paul02335422006-01-16 11:13:27 +0000789
790 /* aspath_hash_alloc dupes segments too. that probably could be
791 * optimised out.
792 */
793 assegment_free_all (as.segments);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000794 if (as.str)
795 XFREE (MTYPE_AS_STR, as.str);
paul02335422006-01-16 11:13:27 +0000796
paul718e3742002-12-13 20:15:29 +0000797 if (! find)
798 return NULL;
799 find->refcnt++;
800
801 return find;
802}
803
paulfe69a502005-09-10 16:55:02 +0000804static inline void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000805assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
paul718e3742002-12-13 20:15:29 +0000806{
paulfe69a502005-09-10 16:55:02 +0000807 int i;
808 assert (num <= AS_SEGMENT_MAX);
809
810 for (i = 0; i < num; i++)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000811 if ( use32bit )
812 stream_putl (s, as[i]);
813 else
814 {
815 if ( as[i] <= BGP_AS_MAX )
816 stream_putw(s, as[i]);
817 else
818 stream_putw(s, BGP_AS_TRANS);
819 }
paul718e3742002-12-13 20:15:29 +0000820}
821
paulfe69a502005-09-10 16:55:02 +0000822static inline size_t
823assegment_header_put (struct stream *s, u_char type, int length)
824{
825 size_t lenp;
826 assert (length <= AS_SEGMENT_MAX);
827 stream_putc (s, type);
828 lenp = stream_get_endp (s);
829 stream_putc (s, length);
830 return lenp;
831}
832
833/* write aspath data to stream */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000834size_t
835aspath_put (struct stream *s, struct aspath *as, int use32bit )
paulfe69a502005-09-10 16:55:02 +0000836{
837 struct assegment *seg = as->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000838 size_t bytes = 0;
paulfe69a502005-09-10 16:55:02 +0000839
840 if (!seg || seg->length == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000841 return 0;
paulfe69a502005-09-10 16:55:02 +0000842
843 if (seg)
844 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000845 /*
846 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
847 * At the moment, we would write out a partial aspath, and our peer
848 * will complain and drop the session :-/
849 *
850 * The general assumption here is that many things tested will
851 * never happen. And, in real live, up to now, they have not.
852 */
853 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
paulfe69a502005-09-10 16:55:02 +0000854 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000855 struct assegment *next = seg->next;
paulfe69a502005-09-10 16:55:02 +0000856 int written = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000857 int asns_packed = 0;
paulfe69a502005-09-10 16:55:02 +0000858 size_t lenp;
859
860 /* Overlength segments have to be split up */
861 while ( (seg->length - written) > AS_SEGMENT_MAX)
862 {
863 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000864 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
paulfe69a502005-09-10 16:55:02 +0000865 written += AS_SEGMENT_MAX;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000866 bytes += ASSEGMENT_SIZE (written, use32bit);
paulfe69a502005-09-10 16:55:02 +0000867 }
868
869 /* write the final segment, probably is also the first */
870 lenp = assegment_header_put (s, seg->type, seg->length - written);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000871 assegment_data_put (s, (seg->as + written), seg->length - written,
872 use32bit);
paulfe69a502005-09-10 16:55:02 +0000873
874 /* Sequence-type segments can be 'packed' together
875 * Case of a segment which was overlength and split up
876 * will be missed here, but that doesn't matter.
877 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000878 while (next && ASSEGMENTS_PACKABLE (seg, next))
paulfe69a502005-09-10 16:55:02 +0000879 {
880 /* NB: We should never normally get here given we
881 * normalise aspath data when parse them. However, better
882 * safe than sorry. We potentially could call
883 * assegment_normalise here instead, but it's cheaper and
884 * easier to do it on the fly here rather than go through
885 * the segment list twice every time we write out
886 * aspath's.
887 */
888
889 /* Next segment's data can fit in this one */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000890 assegment_data_put (s, next->as, next->length, use32bit);
paulfe69a502005-09-10 16:55:02 +0000891
892 /* update the length of the segment header */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000893 stream_putc_at (s, lenp, seg->length - written + next->length);
894 asns_packed += next->length;
895
896 next = next->next;
paulfe69a502005-09-10 16:55:02 +0000897 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000898
899 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
900 use32bit);
901 seg = next;
paulfe69a502005-09-10 16:55:02 +0000902 }
903 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000904 return bytes;
paulfe69a502005-09-10 16:55:02 +0000905}
906
907/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
908 * We have no way to manage the storage, so we use a static stream
909 * wrapper around aspath_put.
910 */
911u_char *
912aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
913{
914#define SNMP_PATHSEG_MAX 1024
paul8fdc32a2006-01-16 12:01:29 +0000915
916 if (!snmp_stream)
917 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
paulfe69a502005-09-10 16:55:02 +0000918 else
paul8fdc32a2006-01-16 12:01:29 +0000919 stream_reset (snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000920
921 if (!as)
922 {
923 *varlen = 0;
924 return NULL;
925 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000926 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
paulfe69a502005-09-10 16:55:02 +0000927
paul8fdc32a2006-01-16 12:01:29 +0000928 *varlen = stream_get_endp (snmp_stream);
929 return stream_pnt(snmp_stream);
paulfe69a502005-09-10 16:55:02 +0000930}
931
932#define min(A,B) ((A) < (B) ? (A) : (B))
933
paul94f2b392005-06-28 12:44:16 +0000934static struct assegment *
paul718e3742002-12-13 20:15:29 +0000935aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
936 as_t as)
937{
938 int i;
939
940 /* If this is first AS set member, create new as-set segment. */
941 if (asset == NULL)
942 {
paulfe69a502005-09-10 16:55:02 +0000943 asset = assegment_new (AS_SET, 1);
944 if (! aspath->segments)
945 aspath->segments = asset;
paul718e3742002-12-13 20:15:29 +0000946 else
paulfe69a502005-09-10 16:55:02 +0000947 {
948 struct assegment *seg = aspath->segments;
949 while (seg->next)
950 seg = seg->next;
951 seg->next = asset;
952 }
paul718e3742002-12-13 20:15:29 +0000953 asset->type = AS_SET;
954 asset->length = 1;
paulfe69a502005-09-10 16:55:02 +0000955 asset->as[0] = as;
paul718e3742002-12-13 20:15:29 +0000956 }
957 else
958 {
paul718e3742002-12-13 20:15:29 +0000959 /* Check this AS value already exists or not. */
960 for (i = 0; i < asset->length; i++)
paulfe69a502005-09-10 16:55:02 +0000961 if (asset->as[i] == as)
paul718e3742002-12-13 20:15:29 +0000962 return asset;
paulfe69a502005-09-10 16:55:02 +0000963
paul718e3742002-12-13 20:15:29 +0000964 asset->length++;
paulfe69a502005-09-10 16:55:02 +0000965 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
966 asset->length * AS_VALUE_SIZE);
967 asset->as[asset->length - 1] = as;
paul718e3742002-12-13 20:15:29 +0000968 }
paulfe69a502005-09-10 16:55:02 +0000969
paul718e3742002-12-13 20:15:29 +0000970
971 return asset;
972}
973
974/* Modify as1 using as2 for aggregation. */
975struct aspath *
976aspath_aggregate (struct aspath *as1, struct aspath *as2)
977{
978 int i;
979 int minlen;
980 int match;
paulfe69a502005-09-10 16:55:02 +0000981 int from;
982 struct assegment *seg1 = as1->segments;
983 struct assegment *seg2 = as2->segments;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000984 struct aspath *aspath = NULL;
paul718e3742002-12-13 20:15:29 +0000985 struct assegment *asset;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000986 struct assegment *prevseg = NULL;
paul718e3742002-12-13 20:15:29 +0000987
988 match = 0;
989 minlen = 0;
990 aspath = NULL;
991 asset = NULL;
paul718e3742002-12-13 20:15:29 +0000992
993 /* First of all check common leading sequence. */
paulfe69a502005-09-10 16:55:02 +0000994 while (seg1 && seg2)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000995 {
paul718e3742002-12-13 20:15:29 +0000996 /* Check segment type. */
997 if (seg1->type != seg2->type)
998 break;
999
1000 /* Minimum segment length. */
1001 minlen = min (seg1->length, seg2->length);
1002
1003 for (match = 0; match < minlen; match++)
paulfe69a502005-09-10 16:55:02 +00001004 if (seg1->as[match] != seg2->as[match])
paul718e3742002-12-13 20:15:29 +00001005 break;
1006
1007 if (match)
1008 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001009 struct assegment *seg = assegment_new (seg1->type, 0);
1010
1011 seg = assegment_append_asns (seg, seg1->as, match);
1012
paul718e3742002-12-13 20:15:29 +00001013 if (! aspath)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001014 {
1015 aspath = aspath_new ();
1016 aspath->segments = seg;
1017 }
1018 else
1019 prevseg->next = seg;
1020
1021 prevseg = seg;
paul718e3742002-12-13 20:15:29 +00001022 }
1023
1024 if (match != minlen || match != seg1->length
1025 || seg1->length != seg2->length)
1026 break;
paulfe69a502005-09-10 16:55:02 +00001027
1028 seg1 = seg1->next;
1029 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001030 }
1031
1032 if (! aspath)
1033 aspath = aspath_new();
1034
1035 /* Make as-set using rest of all information. */
paulfe69a502005-09-10 16:55:02 +00001036 from = match;
1037 while (seg1)
paul718e3742002-12-13 20:15:29 +00001038 {
paulfe69a502005-09-10 16:55:02 +00001039 for (i = from; i < seg1->length; i++)
1040 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1041
1042 from = 0;
1043 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001044 }
1045
paulfe69a502005-09-10 16:55:02 +00001046 from = match;
1047 while (seg2)
paul718e3742002-12-13 20:15:29 +00001048 {
paulfe69a502005-09-10 16:55:02 +00001049 for (i = from; i < seg2->length; i++)
1050 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
paul718e3742002-12-13 20:15:29 +00001051
paulfe69a502005-09-10 16:55:02 +00001052 from = 0;
1053 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001054 }
paulfe69a502005-09-10 16:55:02 +00001055
1056 assegment_normalise (aspath->segments);
1057 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001058 return aspath;
1059}
1060
1061/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1062 attribute, check the leftmost AS number in the AS_PATH attribute is
1063 or not the peer's AS number. */
1064int
1065aspath_firstas_check (struct aspath *aspath, as_t asno)
1066{
paulfe69a502005-09-10 16:55:02 +00001067 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001068 return 0;
paulfe69a502005-09-10 16:55:02 +00001069
1070 if (aspath->segments
1071 && (aspath->segments->type == AS_SEQUENCE)
1072 && (aspath->segments->as[0] == asno ))
paul718e3742002-12-13 20:15:29 +00001073 return 1;
1074
1075 return 0;
1076}
1077
Paul Jakma1f742f22006-08-06 15:52:11 +00001078/* AS path loop check. If aspath contains asno then return >= 1. */
paul718e3742002-12-13 20:15:29 +00001079int
1080aspath_loop_check (struct aspath *aspath, as_t asno)
1081{
paulfe69a502005-09-10 16:55:02 +00001082 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001083 int count = 0;
1084
Paul Jakma1f742f22006-08-06 15:52:11 +00001085 if ( (aspath == NULL) || (aspath->segments == NULL) )
paul718e3742002-12-13 20:15:29 +00001086 return 0;
paulfe69a502005-09-10 16:55:02 +00001087
1088 seg = aspath->segments;
1089
1090 while (seg)
paul718e3742002-12-13 20:15:29 +00001091 {
1092 int i;
paul718e3742002-12-13 20:15:29 +00001093
paulfe69a502005-09-10 16:55:02 +00001094 for (i = 0; i < seg->length; i++)
1095 if (seg->as[i] == asno)
paul718e3742002-12-13 20:15:29 +00001096 count++;
paulfe69a502005-09-10 16:55:02 +00001097
1098 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001099 }
1100 return count;
1101}
1102
1103/* When all of AS path is private AS return 1. */
1104int
1105aspath_private_as_check (struct aspath *aspath)
1106{
paulfe69a502005-09-10 16:55:02 +00001107 struct assegment *seg;
1108
1109 if ( !(aspath && aspath->segments) )
paul718e3742002-12-13 20:15:29 +00001110 return 0;
paulfe69a502005-09-10 16:55:02 +00001111
1112 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001113
paulfe69a502005-09-10 16:55:02 +00001114 while (seg)
paul718e3742002-12-13 20:15:29 +00001115 {
1116 int i;
paul718e3742002-12-13 20:15:29 +00001117
paulfe69a502005-09-10 16:55:02 +00001118 for (i = 0; i < seg->length; i++)
paul718e3742002-12-13 20:15:29 +00001119 {
paulfe69a502005-09-10 16:55:02 +00001120 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1121 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
paul718e3742002-12-13 20:15:29 +00001122 return 0;
1123 }
paulfe69a502005-09-10 16:55:02 +00001124 seg = seg->next;
paul718e3742002-12-13 20:15:29 +00001125 }
1126 return 1;
1127}
1128
1129/* Merge as1 to as2. as2 should be uninterned aspath. */
paul94f2b392005-06-28 12:44:16 +00001130static struct aspath *
paul718e3742002-12-13 20:15:29 +00001131aspath_merge (struct aspath *as1, struct aspath *as2)
1132{
paulfe69a502005-09-10 16:55:02 +00001133 struct assegment *last, *new;
paul718e3742002-12-13 20:15:29 +00001134
1135 if (! as1 || ! as2)
1136 return NULL;
1137
paulfe69a502005-09-10 16:55:02 +00001138 last = new = assegment_dup_all (as1->segments);
1139
1140 /* find the last valid segment */
1141 while (last && last->next)
1142 last = last->next;
1143
1144 last->next = as2->segments;
1145 as2->segments = new;
1146 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001147 return as2;
1148}
1149
1150/* Prepend as1 to as2. as2 should be uninterned aspath. */
1151struct aspath *
1152aspath_prepend (struct aspath *as1, struct aspath *as2)
1153{
paulfe69a502005-09-10 16:55:02 +00001154 struct assegment *seg1;
1155 struct assegment *seg2;
paul718e3742002-12-13 20:15:29 +00001156
1157 if (! as1 || ! as2)
1158 return NULL;
paulfe69a502005-09-10 16:55:02 +00001159
1160 seg1 = as1->segments;
1161 seg2 = as2->segments;
1162
1163 /* If as2 is empty, only need to dupe as1's chain onto as2 */
paul718e3742002-12-13 20:15:29 +00001164 if (seg2 == NULL)
1165 {
paulfe69a502005-09-10 16:55:02 +00001166 as2->segments = assegment_dup_all (as1->segments);
1167 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001168 return as2;
1169 }
paulfe69a502005-09-10 16:55:02 +00001170
1171 /* If as1 is empty AS, no prepending to do. */
paul718e3742002-12-13 20:15:29 +00001172 if (seg1 == NULL)
1173 return as2;
paulfe69a502005-09-10 16:55:02 +00001174
1175 /* find the tail as1's segment chain. */
1176 while (seg1 && seg1->next)
1177 seg1 = seg1->next;
paul718e3742002-12-13 20:15:29 +00001178
1179 /* Compare last segment type of as1 and first segment type of as2. */
1180 if (seg1->type != seg2->type)
1181 return aspath_merge (as1, as2);
1182
1183 if (seg1->type == AS_SEQUENCE)
1184 {
paulfe69a502005-09-10 16:55:02 +00001185 /* We have two chains of segments, as1->segments and seg2,
1186 * and we have to attach them together, merging the attaching
1187 * segments together into one.
1188 *
1189 * 1. dupe as1->segments onto head of as2
1190 * 2. merge seg2's asns onto last segment of this new chain
1191 * 3. attach chain after seg2
1192 */
paul718e3742002-12-13 20:15:29 +00001193
paulfe69a502005-09-10 16:55:02 +00001194 /* dupe as1 onto as2's head */
1195 seg1 = as2->segments = assegment_dup_all (as1->segments);
1196
1197 /* refind the tail of as2, reusing seg1 */
1198 while (seg1 && seg1->next)
1199 seg1 = seg1->next;
1200
1201 /* merge the old head, seg2, into tail, seg1 */
1202 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1203
1204 /* bypass the merged seg2, and attach any chain after it to
1205 * chain descending from as2's head
1206 */
1207 seg1->next = seg2->next;
1208
1209 /* seg2 is now referenceless and useless*/
1210 assegment_free (seg2);
1211
1212 /* we've now prepended as1's segment chain to as2, merging
1213 * the inbetween AS_SEQUENCE of seg2 in the process
1214 */
1215 aspath_str_update (as2);
paul718e3742002-12-13 20:15:29 +00001216 return as2;
1217 }
1218 else
1219 {
1220 /* AS_SET merge code is needed at here. */
1221 return aspath_merge (as1, as2);
1222 }
paulfe69a502005-09-10 16:55:02 +00001223 /* XXX: Ermmm, what if as1 has multiple segments?? */
1224
paul718e3742002-12-13 20:15:29 +00001225 /* Not reached */
1226}
1227
1228/* Add specified AS to the leftmost of aspath. */
1229static struct aspath *
1230aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1231{
paulfe69a502005-09-10 16:55:02 +00001232 struct assegment *assegment = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001233
1234 /* In case of empty aspath. */
1235 if (assegment == NULL || assegment->length == 0)
1236 {
paulfe69a502005-09-10 16:55:02 +00001237 aspath->segments = assegment_new (type, 1);
1238 aspath->segments->as[0] = asno;
1239
paul718e3742002-12-13 20:15:29 +00001240 if (assegment)
paulfe69a502005-09-10 16:55:02 +00001241 assegment_free (assegment);
paul718e3742002-12-13 20:15:29 +00001242
1243 return aspath;
1244 }
1245
1246 if (assegment->type == type)
paulfe69a502005-09-10 16:55:02 +00001247 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1248 else
paul718e3742002-12-13 20:15:29 +00001249 {
paulfe69a502005-09-10 16:55:02 +00001250 /* create new segment
1251 * push it onto head of aspath's segment chain
1252 */
paul718e3742002-12-13 20:15:29 +00001253 struct assegment *newsegment;
paulfe69a502005-09-10 16:55:02 +00001254
1255 newsegment = assegment_new (type, 1);
1256 newsegment->as[0] = asno;
1257
1258 newsegment->next = assegment;
1259 aspath->segments = newsegment;
paul718e3742002-12-13 20:15:29 +00001260 }
1261
1262 return aspath;
1263}
1264
1265/* Add specified AS to the leftmost of aspath. */
1266struct aspath *
1267aspath_add_seq (struct aspath *aspath, as_t asno)
1268{
1269 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1270}
1271
1272/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1273 as2's leftmost AS is same return 1. */
1274int
1275aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
1276{
paulfe69a502005-09-10 16:55:02 +00001277 struct assegment *seg1 = NULL;
1278 struct assegment *seg2 = NULL;
paul718e3742002-12-13 20:15:29 +00001279
paulfe69a502005-09-10 16:55:02 +00001280 if (!(aspath1 && aspath2))
1281 return 0;
paul718e3742002-12-13 20:15:29 +00001282
paulfe69a502005-09-10 16:55:02 +00001283 seg1 = aspath1->segments;
1284 seg2 = aspath2->segments;
1285
1286 /* find first non-confed segments for each */
1287 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1288 || (seg1->type == AS_CONFED_SET)))
1289 seg1 = seg1->next;
1290
1291 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1292 || (seg2->type == AS_CONFED_SET)))
1293 seg2 = seg2->next;
paul718e3742002-12-13 20:15:29 +00001294
1295 /* Check as1's */
paulfe69a502005-09-10 16:55:02 +00001296 if (!(seg1 && seg2
1297 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
paul718e3742002-12-13 20:15:29 +00001298 return 0;
paulfe69a502005-09-10 16:55:02 +00001299
1300 if (seg1->as[0] == seg2->as[0])
paul718e3742002-12-13 20:15:29 +00001301 return 1;
1302
1303 return 0;
1304}
1305
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001306/* Truncate an aspath after a number of hops, and put the hops remaining
1307 * at the front of another aspath. Needed for AS4 compat.
1308 *
1309 * Returned aspath is a /new/ aspath, which should either by free'd or
1310 * interned by the caller, as desired.
1311 */
1312struct aspath *
1313aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1314{
1315 struct assegment *seg, *newseg, *prevseg = NULL;
1316 struct aspath *newpath = NULL, *mergedpath;
1317 int hops, cpasns = 0;
1318
1319 if (!aspath)
1320 return NULL;
1321
1322 seg = aspath->segments;
1323
1324 /* CONFEDs should get reconciled too.. */
1325 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1326 - aspath_count_hops (as4path);
1327
1328 if (hops < 0)
1329 {
1330 if (BGP_DEBUG (as4, AS4))
1331 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1332 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1333 * which is daft behaviour - it contains vital loop-detection
1334 * information which must have been removed from AS_PATH.
1335 */
1336 hops = aspath_count_hops (aspath);
1337 }
1338
1339 if (!hops)
1340 return aspath_dup (as4path);
1341
1342 if ( BGP_DEBUG(as4, AS4))
1343 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1344 aspath->str, as4path->str);
1345
1346 while (seg && hops > 0)
1347 {
1348 switch (seg->type)
1349 {
1350 case AS_SET:
1351 case AS_CONFED_SET:
1352 hops--;
1353 cpasns = seg->length;
1354 break;
1355 case AS_CONFED_SEQUENCE:
1356 /* Should never split a confed-sequence, if hop-count
1357 * suggests we must then something's gone wrong somewhere.
1358 *
1359 * Most important goal is to preserve AS_PATHs prime function
1360 * as loop-detector, so we fudge the numbers so that the entire
1361 * confed-sequence is merged in.
1362 */
1363 if (hops < seg->length)
1364 {
1365 if (BGP_DEBUG (as4, AS4))
1366 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1367 " across 2/4 ASN boundary somewhere, broken..");
1368 hops = seg->length;
1369 }
1370 case AS_SEQUENCE:
1371 cpasns = MIN(seg->length, hops);
1372 hops -= seg->length;
1373 }
1374
1375 assert (cpasns <= seg->length);
1376
1377 newseg = assegment_new (seg->type, 0);
1378 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1379
1380 if (!newpath)
1381 {
1382 newpath = aspath_new ();
1383 newpath->segments = newseg;
1384 }
1385 else
1386 prevseg->next = newseg;
1387
1388 prevseg = newseg;
1389 seg = seg->next;
1390 }
1391
1392 /* We may be able to join some segments here, and we must
1393 * do this because... we want normalised aspaths in out hash
1394 * and we do not want to stumble in aspath_put.
1395 */
1396 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1397 aspath_free (newpath);
1398 mergedpath->segments = assegment_normalise (mergedpath->segments);
1399 aspath_str_update (mergedpath);
1400
1401 if ( BGP_DEBUG(as4, AS4))
1402 zlog_debug ("[AS4] result of synthesizing is %s",
1403 mergedpath->str);
1404
1405 return mergedpath;
1406}
1407
paul718e3742002-12-13 20:15:29 +00001408/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1409 as2's leftmost AS is same return 1. (confederation as-path
1410 only). */
1411int
1412aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2)
1413{
paulfe69a502005-09-10 16:55:02 +00001414 if (! (aspath1 && aspath2) )
paul718e3742002-12-13 20:15:29 +00001415 return 0;
paulfe69a502005-09-10 16:55:02 +00001416
paulad727402005-11-23 02:47:02 +00001417 if ( !(aspath1->segments && aspath2->segments) )
1418 return 0;
1419
paulfe69a502005-09-10 16:55:02 +00001420 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1421 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
paul718e3742002-12-13 20:15:29 +00001422 return 0;
paulfe69a502005-09-10 16:55:02 +00001423
1424 if (aspath1->segments->as[0] == aspath2->segments->as[0])
paul718e3742002-12-13 20:15:29 +00001425 return 1;
1426
1427 return 0;
1428}
1429
paulfe69a502005-09-10 16:55:02 +00001430/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1431 * See RFC3065, 6.1 c1 */
paul718e3742002-12-13 20:15:29 +00001432struct aspath *
1433aspath_delete_confed_seq (struct aspath *aspath)
1434{
paulfe69a502005-09-10 16:55:02 +00001435 struct assegment *seg;
paul718e3742002-12-13 20:15:29 +00001436
paulfe69a502005-09-10 16:55:02 +00001437 if (!(aspath && aspath->segments))
paul718e3742002-12-13 20:15:29 +00001438 return aspath;
1439
paulfe69a502005-09-10 16:55:02 +00001440 seg = aspath->segments;
1441
1442 /* "if the first path segment of the AS_PATH is
1443 * of type AS_CONFED_SEQUENCE,"
1444 */
1445 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1446 return aspath;
paul718e3742002-12-13 20:15:29 +00001447
paulfe69a502005-09-10 16:55:02 +00001448 /* "... that segment and any immediately following segments
1449 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1450 * from the AS_PATH attribute,"
1451 */
1452 while (seg &&
1453 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
paul718e3742002-12-13 20:15:29 +00001454 {
paulfe69a502005-09-10 16:55:02 +00001455 aspath->segments = seg->next;
1456 assegment_free (seg);
1457 seg = aspath->segments;
paul718e3742002-12-13 20:15:29 +00001458 }
paulfe69a502005-09-10 16:55:02 +00001459 aspath_str_update (aspath);
paul718e3742002-12-13 20:15:29 +00001460 return aspath;
1461}
1462
1463/* Add new AS number to the leftmost part of the aspath as
1464 AS_CONFED_SEQUENCE. */
1465struct aspath*
1466aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1467{
1468 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1469}
1470
1471/* Add new as value to as path structure. */
paul94f2b392005-06-28 12:44:16 +00001472static void
paul718e3742002-12-13 20:15:29 +00001473aspath_as_add (struct aspath *as, as_t asno)
1474{
paulfe69a502005-09-10 16:55:02 +00001475 struct assegment *seg = as->segments;
paul718e3742002-12-13 20:15:29 +00001476
paulfe69a502005-09-10 16:55:02 +00001477 if (!seg)
1478 return;
1479
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001480 /* Last segment search procedure. */
1481 while (seg->next)
1482 seg = seg->next;
1483
paulfe69a502005-09-10 16:55:02 +00001484 assegment_append_asns (seg, &asno, 1);
paul718e3742002-12-13 20:15:29 +00001485}
1486
1487/* Add new as segment to the as path. */
paul94f2b392005-06-28 12:44:16 +00001488static void
paul718e3742002-12-13 20:15:29 +00001489aspath_segment_add (struct aspath *as, int type)
1490{
paulfe69a502005-09-10 16:55:02 +00001491 struct assegment *seg = as->segments;
1492 struct assegment *new = assegment_new (type, 0);
paul718e3742002-12-13 20:15:29 +00001493
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001494 if (seg)
1495 {
1496 while (seg->next)
1497 seg = seg->next;
1498 seg->next = new;
1499 }
paul718e3742002-12-13 20:15:29 +00001500 else
Andrew J. Schorr93c17492007-04-15 19:17:24 +00001501 as->segments = new;
paul718e3742002-12-13 20:15:29 +00001502}
1503
1504struct aspath *
paul94f2b392005-06-28 12:44:16 +00001505aspath_empty (void)
paul718e3742002-12-13 20:15:29 +00001506{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001507 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
paul718e3742002-12-13 20:15:29 +00001508}
1509
1510struct aspath *
paul94f2b392005-06-28 12:44:16 +00001511aspath_empty_get (void)
paul718e3742002-12-13 20:15:29 +00001512{
1513 struct aspath *aspath;
1514
1515 aspath = aspath_new ();
1516 aspath->str = aspath_make_str_count (aspath);
1517 return aspath;
1518}
1519
1520unsigned long
paulfe69a502005-09-10 16:55:02 +00001521aspath_count (void)
paul718e3742002-12-13 20:15:29 +00001522{
1523 return ashash->count;
1524}
1525
1526/*
1527 Theoretically, one as path can have:
1528
1529 One BGP packet size should be less than 4096.
1530 One BGP attribute size should be less than 4096 - BGP header size.
1531 One BGP aspath size should be less than 4096 - BGP header size -
1532 BGP mandantry attribute size.
1533*/
1534
1535/* AS path string lexical token enum. */
1536enum as_token
1537{
1538 as_token_asval,
1539 as_token_set_start,
1540 as_token_set_end,
paulfe69a502005-09-10 16:55:02 +00001541 as_token_confed_seq_start,
1542 as_token_confed_seq_end,
1543 as_token_confed_set_start,
1544 as_token_confed_set_end,
paul718e3742002-12-13 20:15:29 +00001545 as_token_unknown
1546};
1547
1548/* Return next token and point for string parse. */
paul94f2b392005-06-28 12:44:16 +00001549static const char *
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001550aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
paul718e3742002-12-13 20:15:29 +00001551{
paulfd79ac92004-10-13 05:06:08 +00001552 const char *p = buf;
paul718e3742002-12-13 20:15:29 +00001553
paulfe69a502005-09-10 16:55:02 +00001554 /* Skip seperators (space for sequences, ',' for sets). */
1555 while (isspace ((int) *p) || *p == ',')
paul718e3742002-12-13 20:15:29 +00001556 p++;
1557
1558 /* Check the end of the string and type specify characters
1559 (e.g. {}()). */
1560 switch (*p)
1561 {
1562 case '\0':
1563 return NULL;
paul718e3742002-12-13 20:15:29 +00001564 case '{':
1565 *token = as_token_set_start;
1566 p++;
1567 return p;
paul718e3742002-12-13 20:15:29 +00001568 case '}':
1569 *token = as_token_set_end;
1570 p++;
1571 return p;
paul718e3742002-12-13 20:15:29 +00001572 case '(':
paulfe69a502005-09-10 16:55:02 +00001573 *token = as_token_confed_seq_start;
paul718e3742002-12-13 20:15:29 +00001574 p++;
1575 return p;
paul718e3742002-12-13 20:15:29 +00001576 case ')':
paulfe69a502005-09-10 16:55:02 +00001577 *token = as_token_confed_seq_end;
1578 p++;
1579 return p;
paulfe69a502005-09-10 16:55:02 +00001580 case '[':
1581 *token = as_token_confed_set_start;
1582 p++;
1583 return p;
paulfe69a502005-09-10 16:55:02 +00001584 case ']':
1585 *token = as_token_confed_set_end;
paul718e3742002-12-13 20:15:29 +00001586 p++;
1587 return p;
paul718e3742002-12-13 20:15:29 +00001588 }
1589
1590 /* Check actual AS value. */
1591 if (isdigit ((int) *p))
1592 {
1593 u_short asval;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001594
paul718e3742002-12-13 20:15:29 +00001595 *token = as_token_asval;
1596 asval = (*p - '0');
1597 p++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001598
paul718e3742002-12-13 20:15:29 +00001599 while (isdigit ((int) *p))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001600 {
1601 asval *= 10;
1602 asval += (*p - '0');
1603 p++;
1604 }
paul718e3742002-12-13 20:15:29 +00001605 *asno = asval;
1606 return p;
1607 }
1608
1609 /* There is no match then return unknown token. */
1610 *token = as_token_unknown;
1611 return p++;
1612}
1613
1614struct aspath *
paulfd79ac92004-10-13 05:06:08 +00001615aspath_str2aspath (const char *str)
paul718e3742002-12-13 20:15:29 +00001616{
paul3fff6ff2006-02-05 17:55:35 +00001617 enum as_token token = as_token_unknown;
paul718e3742002-12-13 20:15:29 +00001618 u_short as_type;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001619 u_long asno = 0;
paul718e3742002-12-13 20:15:29 +00001620 struct aspath *aspath;
1621 int needtype;
1622
1623 aspath = aspath_new ();
1624
1625 /* We start default type as AS_SEQUENCE. */
1626 as_type = AS_SEQUENCE;
1627 needtype = 1;
1628
1629 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1630 {
1631 switch (token)
1632 {
1633 case as_token_asval:
1634 if (needtype)
1635 {
1636 aspath_segment_add (aspath, as_type);
1637 needtype = 0;
1638 }
1639 aspath_as_add (aspath, asno);
1640 break;
1641 case as_token_set_start:
1642 as_type = AS_SET;
1643 aspath_segment_add (aspath, as_type);
1644 needtype = 0;
1645 break;
1646 case as_token_set_end:
1647 as_type = AS_SEQUENCE;
1648 needtype = 1;
1649 break;
paulfe69a502005-09-10 16:55:02 +00001650 case as_token_confed_seq_start:
paul718e3742002-12-13 20:15:29 +00001651 as_type = AS_CONFED_SEQUENCE;
1652 aspath_segment_add (aspath, as_type);
1653 needtype = 0;
1654 break;
paulfe69a502005-09-10 16:55:02 +00001655 case as_token_confed_seq_end:
1656 as_type = AS_SEQUENCE;
1657 needtype = 1;
1658 break;
1659 case as_token_confed_set_start:
1660 as_type = AS_CONFED_SET;
1661 aspath_segment_add (aspath, as_type);
1662 needtype = 0;
1663 break;
1664 case as_token_confed_set_end:
paul718e3742002-12-13 20:15:29 +00001665 as_type = AS_SEQUENCE;
1666 needtype = 1;
1667 break;
1668 case as_token_unknown:
1669 default:
paulfe69a502005-09-10 16:55:02 +00001670 aspath_free (aspath);
paul718e3742002-12-13 20:15:29 +00001671 return NULL;
paul718e3742002-12-13 20:15:29 +00001672 }
1673 }
1674
1675 aspath->str = aspath_make_str_count (aspath);
1676
1677 return aspath;
1678}
1679
1680/* Make hash value by raw aspath data. */
1681unsigned int
Paul Jakma923de652007-04-29 18:25:17 +00001682aspath_key_make (void *p)
paul718e3742002-12-13 20:15:29 +00001683{
Paul Jakma923de652007-04-29 18:25:17 +00001684 struct aspath * aspath = (struct aspath *) p;
paul718e3742002-12-13 20:15:29 +00001685 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +00001686
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001687 if (!aspath->str)
1688 aspath_str_update (aspath);
1689
1690 key = jhash (aspath->str, strlen(aspath->str), 2334325);
paul718e3742002-12-13 20:15:29 +00001691
1692 return key;
1693}
1694
1695/* If two aspath have same value then return 1 else return 0 */
paul94f2b392005-06-28 12:44:16 +00001696static int
paulfe69a502005-09-10 16:55:02 +00001697aspath_cmp (void *arg1, void *arg2)
paul718e3742002-12-13 20:15:29 +00001698{
paulfe69a502005-09-10 16:55:02 +00001699 struct assegment *seg1 = ((struct aspath *)arg1)->segments;
1700 struct assegment *seg2 = ((struct aspath *)arg2)->segments;
1701
1702 while (seg1 || seg2)
1703 {
1704 int i;
1705 if ((!seg1 && seg2) || (seg1 && !seg2))
1706 return 0;
1707 if (seg1->type != seg2->type)
1708 return 0;
1709 if (seg1->length != seg2->length)
1710 return 0;
1711 for (i = 0; i < seg1->length; i++)
1712 if (seg1->as[i] != seg2->as[i])
1713 return 0;
1714 seg1 = seg1->next;
1715 seg2 = seg2->next;
1716 }
1717 return 1;
paul718e3742002-12-13 20:15:29 +00001718}
1719
1720/* AS path hash initialize. */
1721void
paul94f2b392005-06-28 12:44:16 +00001722aspath_init (void)
paul718e3742002-12-13 20:15:29 +00001723{
1724 ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1725}
paul8fdc32a2006-01-16 12:01:29 +00001726
1727void
1728aspath_finish (void)
1729{
1730 hash_free (ashash);
1731
1732 if (snmp_stream)
1733 stream_free (snmp_stream);
1734}
paul718e3742002-12-13 20:15:29 +00001735
1736/* return and as path value */
1737const char *
1738aspath_print (struct aspath *as)
1739{
paulfe69a502005-09-10 16:55:02 +00001740 return (as ? as->str : NULL);
paul718e3742002-12-13 20:15:29 +00001741}
1742
1743/* Printing functions */
1744void
Paul Jakmab2518c12006-05-12 23:48:40 +00001745aspath_print_vty (struct vty *vty, const char *format, struct aspath *as)
paul718e3742002-12-13 20:15:29 +00001746{
Paul Jakmab2518c12006-05-12 23:48:40 +00001747 assert (format);
1748 vty_out (vty, format, as->str);
paul718e3742002-12-13 20:15:29 +00001749}
1750
paul94f2b392005-06-28 12:44:16 +00001751static void
paul718e3742002-12-13 20:15:29 +00001752aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1753{
1754 struct aspath *as;
1755
1756 as = (struct aspath *) backet->data;
1757
paulefa9f832002-12-13 21:47:59 +00001758 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
paul718e3742002-12-13 20:15:29 +00001759 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1760}
1761
1762/* Print all aspath and hash information. This function is used from
1763 `show ip bgp paths' command. */
1764void
1765aspath_print_all_vty (struct vty *vty)
1766{
1767 hash_iterate (ashash,
1768 (void (*) (struct hash_backet *, void *))
1769 aspath_show_all_iterator,
1770 vty);
1771}