]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_aspath.c
build: Quagga 0.99.23-rc1
[mirror_frr.git] / bgpd / bgp_aspath.c
CommitLineData
718e3744 1/* AS path management routines.
2 Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
fe69a505 3 Copyright (C) 2005 Sun Microsystems, Inc.
718e3744 4
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"
fe69a505 30#include "stream.h"
0b2aa3a0 31#include "jhash.h"
718e3744 32
33#include "bgpd/bgpd.h"
34#include "bgpd/bgp_aspath.h"
0b2aa3a0
PJ
35#include "bgpd/bgp_debug.h"
36#include "bgpd/bgp_attr.h"
718e3744 37\f
38/* Attr. Flags and Attr. Type Code. */
39#define AS_HEADER_SIZE 2
40
0b2aa3a0 41/* Now FOUR octets are used for AS value. */
718e3744 42#define AS_VALUE_SIZE sizeof (as_t)
0b2aa3a0
PJ
43/* This is the old one */
44#define AS16_VALUE_SIZE sizeof (as16_t)
718e3744 45
fe69a505 46/* Maximum protocol segment length value */
47#define AS_SEGMENT_MAX 255
48
49/* 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.
0b2aa3a0
PJ
54 *
55 * aspath_put returns bytes written, the only definitive record of
56 * size of wire-format attribute..
fe69a505 57 */
58
59/* Calculated size in bytes of ASN segment data to hold N ASN's */
0b2aa3a0
PJ
60#define ASSEGMENT_DATA_SIZE(N,S) \
61 ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )
718e3744 62
fe69a505 63/* Calculated size of segment struct to hold N ASN's */
0b2aa3a0 64#define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
fe69a505 65
66/* AS segment octet length. */
0b2aa3a0 67#define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
fe69a505 68
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
718e3744 83{
84 u_char type;
85 u_char length;
718e3744 86};
87
88/* Hash for aspath. This is the top level structure of AS path. */
da88ea82 89static struct hash *ashash;
8fdc32ab 90
91/* Stream for SNMP. See aspath_snmp_pathseg */
92static struct stream *snmp_stream;
718e3744 93\f
f669f7d2 94/* Callers are required to initialize the memory */
f63f06da 95static as_t *
fe69a505 96assegment_data_new (int num)
97{
f669f7d2 98 return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
fe69a505 99}
100
101/* Get a new segment. Note that 0 is an allowed length,
102 * and will result in a segment with no allocated data segment.
103 * the caller should immediately assign data to the segment, as the segment
104 * otherwise is not generally valid
105 */
106static struct assegment *
107assegment_new (u_char type, u_short length)
108{
109 struct assegment *new;
110
111 new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
112
113 if (length)
114 new->as = assegment_data_new (length);
115
116 new->length = length;
117 new->type = type;
118
119 return new;
120}
121
122static void
123assegment_free (struct assegment *seg)
124{
125 if (!seg)
126 return;
127
128 if (seg->as)
129 XFREE (MTYPE_AS_SEG_DATA, seg->as);
130 memset (seg, 0xfe, sizeof(struct assegment));
131 XFREE (MTYPE_AS_SEG, seg);
132
133 return;
134}
135
136/* free entire chain of segments */
137static void
138assegment_free_all (struct assegment *seg)
139{
140 struct assegment *prev;
141
142 while (seg)
143 {
144 prev = seg;
145 seg = seg->next;
146 assegment_free (prev);
147 }
148}
149
150/* Duplicate just the given assegment and its data */
151static struct assegment *
152assegment_dup (struct assegment *seg)
153{
154 struct assegment *new;
155
156 new = assegment_new (seg->type, seg->length);
0b2aa3a0 157 memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );
fe69a505 158
159 return new;
160}
161
162/* Duplicate entire chain of assegments, return the head */
163static struct assegment *
164assegment_dup_all (struct assegment *seg)
165{
166 struct assegment *new = NULL;
167 struct assegment *head = NULL;
168
169 while (seg)
170 {
171 if (head)
172 {
173 new->next = assegment_dup (seg);
174 new = new->next;
175 }
176 else
177 head = new = assegment_dup (seg);
178
179 seg = seg->next;
180 }
181 return head;
182}
183
184/* prepend the as number to given segment, given num of times */
185static struct assegment *
186assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
187{
188 as_t *newas;
f669f7d2 189 int i;
fe69a505 190
191 if (!num)
192 return seg;
193
194 if (num >= AS_SEGMENT_MAX)
195 return seg; /* we don't do huge prepends */
196
197 newas = assegment_data_new (seg->length + num);
fe69a505 198
f669f7d2
JBD
199 for (i = 0; i < num; i++)
200 newas[i] = asnum;
201
202 memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
203 XFREE (MTYPE_AS_SEG_DATA, seg->as);
204 seg->as = newas;
205 seg->length += num;
206
207 return seg;
fe69a505 208}
209
210/* append given array of as numbers to the segment */
211static struct assegment *
212assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
213{
02335429 214 as_t *newas;
215
216 newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
0b2aa3a0 217 ASSEGMENT_DATA_SIZE (seg->length + num, 1));
fe69a505 218
02335429 219 if (newas)
fe69a505 220 {
02335429 221 seg->as = newas;
0b2aa3a0 222 memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));
fe69a505 223 seg->length += num;
224 return seg;
225 }
226
227 assegment_free_all (seg);
228 return NULL;
229}
230
231static int
232int_cmp (const void *p1, const void *p2)
233{
234 const as_t *as1 = p1;
235 const as_t *as2 = p2;
236
237 return (*as1 == *as2)
238 ? 0 : ( (*as1 > *as2) ? 1 : -1);
239}
240
241/* normalise the segment.
242 * In particular, merge runs of AS_SEQUENCEs into one segment
243 * Internally, we do not care about the wire segment length limit, and
244 * we want each distinct AS_PATHs to have the exact same internal
245 * representation - eg, so that our hashing actually works..
246 */
247static struct assegment *
248assegment_normalise (struct assegment *head)
249{
250 struct assegment *seg = head, *pin;
251 struct assegment *tmp;
252
253 if (!head)
254 return head;
255
256 while (seg)
257 {
258 pin = seg;
259
260 /* Sort values SET segments, for determinism in paths to aid
261 * creation of hash values / path comparisons
262 * and because it helps other lesser implementations ;)
263 */
264 if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
0b2aa3a0
PJ
265 {
266 int tail = 0;
267 int i;
268
269 qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
270
271 /* weed out dupes */
272 for (i=1; i < seg->length; i++)
273 {
274 if (seg->as[tail] == seg->as[i])
275 continue;
276
277 tail++;
278 if (tail < i)
279 seg->as[tail] = seg->as[i];
280 }
281 /* seg->length can be 0.. */
282 if (seg->length)
283 seg->length = tail + 1;
284 }
fe69a505 285
286 /* read ahead from the current, pinned segment while the segments
287 * are packable/mergeable. Append all following packable segments
288 * to the segment we have pinned and remove these appended
289 * segments.
290 */
291 while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
292 {
293 tmp = pin->next;
294 seg = pin->next;
295
296 /* append the next sequence to the pinned sequence */
297 pin = assegment_append_asns (pin, seg->as, seg->length);
298
299 /* bypass the next sequence */
300 pin->next = seg->next;
301
302 /* get rid of the now referenceless segment */
303 assegment_free (tmp);
304
305 }
306
307 seg = pin->next;
308 }
309 return head;
310}
311\f
718e3744 312static struct aspath *
fe69a505 313aspath_new (void)
718e3744 314{
393deb9b 315 return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
718e3744 316}
317
318/* Free AS path structure. */
319void
320aspath_free (struct aspath *aspath)
321{
322 if (!aspath)
323 return;
fe69a505 324 if (aspath->segments)
325 assegment_free_all (aspath->segments);
718e3744 326 if (aspath->str)
327 XFREE (MTYPE_AS_STR, aspath->str);
328 XFREE (MTYPE_AS_PATH, aspath);
329}
330
331/* Unintern aspath from AS path bucket. */
332void
f6f434b2 333aspath_unintern (struct aspath **aspath)
718e3744 334{
335 struct aspath *ret;
f6f434b2
PJ
336 struct aspath *asp = *aspath;
337
338 if (asp->refcnt)
339 asp->refcnt--;
718e3744 340
f6f434b2 341 if (asp->refcnt == 0)
718e3744 342 {
343 /* This aspath must exist in aspath hash table. */
f6f434b2 344 ret = hash_release (ashash, asp);
718e3744 345 assert (ret != NULL);
f6f434b2
PJ
346 aspath_free (asp);
347 *aspath = NULL;
718e3744 348 }
349}
350
351/* Return the start or end delimiters for a particular Segment type */
352#define AS_SEG_START 0
353#define AS_SEG_END 1
354static char
355aspath_delimiter_char (u_char type, u_char which)
356{
357 int i;
358 struct
359 {
360 int type;
361 char start;
362 char end;
363 } aspath_delim_char [] =
364 {
365 { AS_SET, '{', '}' },
718e3744 366 { AS_CONFED_SET, '[', ']' },
367 { AS_CONFED_SEQUENCE, '(', ')' },
368 { 0 }
369 };
370
371 for (i = 0; aspath_delim_char[i].type != 0; i++)
372 {
373 if (aspath_delim_char[i].type == type)
374 {
375 if (which == AS_SEG_START)
376 return aspath_delim_char[i].start;
377 else if (which == AS_SEG_END)
378 return aspath_delim_char[i].end;
379 }
380 }
381 return ' ';
382}
383
014b670e
DO
384/* countup asns from this segment and index onward */
385static int
386assegment_count_asns (struct assegment *seg, int from)
387{
388 int count = 0;
389 while (seg)
390 {
391 if (!from)
392 count += seg->length;
393 else
394 {
395 count += (seg->length - from);
396 from = 0;
397 }
398 seg = seg->next;
399 }
400 return count;
401}
402
fe69a505 403unsigned int
404aspath_count_confeds (struct aspath *aspath)
405{
406 int count = 0;
407 struct assegment *seg = aspath->segments;
408
409 while (seg)
410 {
411 if (seg->type == AS_CONFED_SEQUENCE)
412 count += seg->length;
413 else if (seg->type == AS_CONFED_SET)
414 count++;
415
416 seg = seg->next;
417 }
418 return count;
419}
420
421unsigned int
422aspath_count_hops (struct aspath *aspath)
423{
424 int count = 0;
425 struct assegment *seg = aspath->segments;
426
427 while (seg)
428 {
429 if (seg->type == AS_SEQUENCE)
430 count += seg->length;
431 else if (seg->type == AS_SET)
432 count++;
433
434 seg = seg->next;
435 }
436 return count;
437}
438
0b2aa3a0
PJ
439/* Estimate size aspath /might/ take if encoded into an
440 * ASPATH attribute.
441 *
442 * This is a quick estimate, not definitive! aspath_put()
443 * may return a different number!!
444 */
fe69a505 445unsigned int
446aspath_size (struct aspath *aspath)
447{
448 int size = 0;
449 struct assegment *seg = aspath->segments;
450
451 while (seg)
452 {
0b2aa3a0 453 size += ASSEGMENT_SIZE(seg->length, 1);
fe69a505 454 seg = seg->next;
455 }
456 return size;
457}
458
2815e61f
PJ
459/* Return highest public ASN in path */
460as_t
461aspath_highest (struct aspath *aspath)
462{
463 struct assegment *seg = aspath->segments;
464 as_t highest = 0;
465 unsigned int i;
466
467 while (seg)
468 {
469 for (i = 0; i < seg->length; i++)
470 if (seg->as[i] > highest
471 && (seg->as[i] < BGP_PRIVATE_AS_MIN
472 || seg->as[i] > BGP_PRIVATE_AS_MAX))
473 highest = seg->as[i];
474 seg = seg->next;
475 }
476 return highest;
477}
478
0b2aa3a0
PJ
479/* Return 1 if there are any 4-byte ASes in the path */
480unsigned int
481aspath_has_as4 (struct aspath *aspath)
482{
483 struct assegment *seg = aspath->segments;
484 unsigned int i;
485
486 while (seg)
487 {
488 for (i = 0; i < seg->length; i++)
489 if (seg->as[i] > BGP_AS_MAX)
490 return 1;
491 seg = seg->next;
492 }
493 return 0;
494}
495
718e3744 496/* Convert aspath structure to string expression. */
f669f7d2 497static void
718e3744 498aspath_make_str_count (struct aspath *as)
499{
fe69a505 500 struct assegment *seg;
501 int str_size;
502 int len = 0;
c9e52be3 503 char *str_buf;
718e3744 504
505 /* Empty aspath. */
fe69a505 506 if (!as->segments)
718e3744 507 {
f669f7d2
JBD
508 as->str = XMALLOC (MTYPE_AS_STR, 1);
509 as->str[0] = '\0';
510 as->str_len = 0;
511 return;
718e3744 512 }
fe69a505 513
514 seg = as->segments;
515
014b670e
DO
516 /* ASN takes 5 to 10 chars plus seperator, see below.
517 * If there is one differing segment type, we need an additional
518 * 2 chars for segment delimiters, and the final '\0'.
519 * Hopefully this is large enough to avoid hitting the realloc
520 * code below for most common sequences.
521 *
522 * This was changed to 10 after the well-known BGP assertion, which
523 * had hit some parts of the Internet in May of 2009.
524 */
525#define ASN_STR_LEN (10 + 1)
526 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
527 ASPATH_STR_DEFAULT_LEN);
718e3744 528 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
718e3744 529
fe69a505 530 while (seg)
718e3744 531 {
532 int i;
fe69a505 533 char seperator;
718e3744 534
fe69a505 535 /* Check AS type validity. Set seperator for segment */
536 switch (seg->type)
537 {
538 case AS_SET:
539 case AS_CONFED_SET:
540 seperator = ',';
541 break;
542 case AS_SEQUENCE:
543 case AS_CONFED_SEQUENCE:
544 seperator = ' ';
545 break;
546 default:
547 XFREE (MTYPE_AS_STR, str_buf);
f669f7d2
JBD
548 as->str = NULL;
549 as->str_len = 0;
550 return;
fe69a505 551 }
552
014b670e
DO
553 /* We might need to increase str_buf, particularly if path has
554 * differing segments types, our initial guesstimate above will
555 * have been wrong. Need 10 chars for ASN, a seperator each and
556 * potentially two segment delimiters, plus a space between each
557 * segment and trailing zero.
558 *
559 * This definitely didn't work with the value of 5 bytes and
560 * 32-bit ASNs.
561 */
562#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
563 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
564 {
565 str_size = len + SEGMENT_STR_LEN(seg);
566 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
567 }
568#undef ASN_STR_LEN
569#undef SEGMENT_STR_LEN
570
fe69a505 571 if (seg->type != AS_SEQUENCE)
014b670e
DO
572 len += snprintf (str_buf + len, str_size - len,
573 "%c",
574 aspath_delimiter_char (seg->type, AS_SEG_START));
fe69a505 575
576 /* write out the ASNs, with their seperators, bar the last one*/
577 for (i = 0; i < seg->length; i++)
578 {
579 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
580
581 if (i < (seg->length - 1))
582 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
583 }
584
585 if (seg->type != AS_SEQUENCE)
586 len += snprintf (str_buf + len, str_size - len, "%c",
587 aspath_delimiter_char (seg->type, AS_SEG_END));
588 if (seg->next)
589 len += snprintf (str_buf + len, str_size - len, " ");
590
591 seg = seg->next;
718e3744 592 }
fe69a505 593
594 assert (len < str_size);
595
596 str_buf[len] = '\0';
f669f7d2
JBD
597 as->str = str_buf;
598 as->str_len = len;
718e3744 599
f669f7d2 600 return;
718e3744 601}
602
fe69a505 603static void
604aspath_str_update (struct aspath *as)
605{
606 if (as->str)
607 XFREE (MTYPE_AS_STR, as->str);
f669f7d2 608 aspath_make_str_count (as);
fe69a505 609}
610
718e3744 611/* Intern allocated AS path. */
612struct aspath *
613aspath_intern (struct aspath *aspath)
614{
615 struct aspath *find;
f669f7d2
JBD
616
617 /* Assert this AS path structure is not interned and has the string
618 representation built. */
718e3744 619 assert (aspath->refcnt == 0);
f669f7d2 620 assert (aspath->str);
718e3744 621
622 /* Check AS path hash. */
623 find = hash_get (ashash, aspath, hash_alloc_intern);
718e3744 624 if (find != aspath)
fe69a505 625 aspath_free (aspath);
718e3744 626
627 find->refcnt++;
628
718e3744 629 return find;
630}
631
632/* Duplicate aspath structure. Created same aspath structure but
633 reference count and AS path string is cleared. */
634struct aspath *
635aspath_dup (struct aspath *aspath)
636{
f669f7d2 637 unsigned short buflen = aspath->str_len + 1;
718e3744 638 struct aspath *new;
639
fe69a505 640 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
718e3744 641
fe69a505 642 if (aspath->segments)
643 new->segments = assegment_dup_all (aspath->segments);
718e3744 644
f669f7d2
JBD
645 if (!aspath->str)
646 return new;
647
648 new->str = XMALLOC (MTYPE_AS_STR, buflen);
649 new->str_len = aspath->str_len;
650
651 /* copy the string data */
652 if (aspath->str_len > 0)
653 memcpy (new->str, aspath->str, buflen);
654 else
655 new->str[0] = '\0';
718e3744 656
657 return new;
658}
659
94f2b392 660static void *
fe69a505 661aspath_hash_alloc (void *arg)
718e3744 662{
f669f7d2
JBD
663 const struct aspath *aspath = arg;
664 struct aspath *new;
718e3744 665
718e3744 666 /* Malformed AS path value. */
f669f7d2 667 assert (aspath->str);
718e3744 668 if (! aspath->str)
f669f7d2 669 return NULL;
718e3744 670
f669f7d2
JBD
671 /* New aspath structure is needed. */
672 new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
673
674 /* Reuse segments and string representation */
675 new->refcnt = 0;
676 new->segments = aspath->segments;
677 new->str = aspath->str;
678 new->str_len = aspath->str_len;
679
680 return new;
718e3744 681}
682
ab005298 683/* parse as-segment byte stream in struct assegment */
b881c707
PJ
684static int
685assegments_parse (struct stream *s, size_t length,
686 struct assegment **result, int use32bit)
fe69a505 687{
688 struct assegment_header segh;
689 struct assegment *seg, *prev = NULL, *head = NULL;
ab005298 690 size_t bytes = 0;
fe69a505 691
ab005298
PJ
692 /* empty aspath (ie iBGP or somesuch) */
693 if (length == 0)
b881c707 694 return 0;
fe69a505 695
0b2aa3a0
PJ
696 if (BGP_DEBUG (as4, AS4_SEGMENT))
697 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
698 (unsigned long) length);
ab005298
PJ
699 /* basic checks */
700 if ((STREAM_READABLE(s) < length)
701 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
702 || (length % AS16_VALUE_SIZE ))
b881c707 703 return -1;
fe69a505 704
ab005298 705 while (bytes < length)
fe69a505 706 {
707 int i;
cddb8112 708 size_t seg_size;
fe69a505 709
ab005298 710 if ((length - bytes) <= AS_HEADER_SIZE)
cddb8112 711 {
ab005298
PJ
712 if (head)
713 assegment_free_all (head);
b881c707 714 return -1;
fdbc8e77
PJ
715 }
716
ab005298 717 /* softly softly, get the header first on its own */
fe69a505 718 segh.type = stream_getc (s);
719 segh.length = stream_getc (s);
720
0b2aa3a0
PJ
721 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
722
723 if (BGP_DEBUG (as4, AS4_SEGMENT))
724 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
725 segh.type, segh.length);
726
ab005298
PJ
727 /* check it.. */
728 if ( ((bytes + seg_size) > length)
729 /* 1771bis 4.3b: seg length contains one or more */
730 || (segh.length == 0)
731 /* Paranoia in case someone changes type of segment length.
732 * Shift both values by 0x10 to make the comparison operate
733 * on more, than 8 bits (otherwise it's a warning, bug #564).
2eb445e1 734 */
ab005298
PJ
735 || ((sizeof segh.length > 1)
736 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
fe69a505 737 {
ab005298 738 if (head)
fe69a505 739 assegment_free_all (head);
b881c707 740 return -1;
fe69a505 741 }
742
fdbc8e77
PJ
743 switch (segh.type)
744 {
745 case AS_SEQUENCE:
746 case AS_SET:
fdbc8e77
PJ
747 case AS_CONFED_SEQUENCE:
748 case AS_CONFED_SET:
ab005298
PJ
749 break;
750 default:
751 if (head)
752 assegment_free_all (head);
b881c707 753 return -1;
fe69a505 754 }
755
756 /* now its safe to trust lengths */
757 seg = assegment_new (segh.type, segh.length);
758
759 if (head)
760 prev->next = seg;
761 else /* it's the first segment */
762 head = prev = seg;
763
764 for (i = 0; i < segh.length; i++)
0b2aa3a0
PJ
765 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
766
ab005298
PJ
767 bytes += seg_size;
768
0b2aa3a0 769 if (BGP_DEBUG (as4, AS4_SEGMENT))
ab005298
PJ
770 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
771 (unsigned long) bytes);
fe69a505 772
773 prev = seg;
774 }
775
b881c707
PJ
776 *result = assegment_normalise (head);
777 return 0;
fe69a505 778}
779
ab005298
PJ
780/* AS path parse function. pnt is a pointer to byte stream and length
781 is length of byte stream. If there is same AS path in the the AS
b881c707
PJ
782 path hash then return it else make new AS path structure.
783
784 On error NULL is returned.
cddb8112 785 */
718e3744 786struct aspath *
ab005298 787aspath_parse (struct stream *s, size_t length, int use32bit)
718e3744 788{
789 struct aspath as;
790 struct aspath *find;
791
ab005298
PJ
792 /* If length is odd it's malformed AS path. */
793 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
794 * otherwise its malformed when length is larger than 2 and (length-2)
795 * is not dividable by 4.
796 * But... this time we're lazy
797 */
798 if (length % AS16_VALUE_SIZE )
799 return NULL;
cddb8112 800
ab005298 801 memset (&as, 0, sizeof (struct aspath));
b881c707
PJ
802 if (assegments_parse (s, length, &as.segments, use32bit) < 0)
803 return NULL;
f669f7d2 804
718e3744 805 /* If already same aspath exist then return it. */
806 find = hash_get (ashash, &as, aspath_hash_alloc);
f669f7d2
JBD
807
808 /* bug! should not happen, let the daemon crash below */
809 assert (find);
810
811 /* if the aspath was already hashed free temporary memory. */
812 if (find->refcnt)
813 {
814 assegment_free_all (as.segments);
815 /* aspath_key_make() always updates the string */
816 XFREE (MTYPE_AS_STR, as.str);
817 }
818
718e3744 819 find->refcnt++;
820
821 return find;
822}
823
f63f06da 824static void
0b2aa3a0 825assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
fe69a505 826{
827 int i;
828 assert (num <= AS_SEGMENT_MAX);
829
830 for (i = 0; i < num; i++)
0b2aa3a0
PJ
831 if ( use32bit )
832 stream_putl (s, as[i]);
833 else
834 {
835 if ( as[i] <= BGP_AS_MAX )
836 stream_putw(s, as[i]);
837 else
838 stream_putw(s, BGP_AS_TRANS);
839 }
fe69a505 840}
718e3744 841
f63f06da 842static size_t
fe69a505 843assegment_header_put (struct stream *s, u_char type, int length)
718e3744 844{
fe69a505 845 size_t lenp;
846 assert (length <= AS_SEGMENT_MAX);
847 stream_putc (s, type);
848 lenp = stream_get_endp (s);
849 stream_putc (s, length);
850 return lenp;
851}
718e3744 852
fe69a505 853/* write aspath data to stream */
0b2aa3a0
PJ
854size_t
855aspath_put (struct stream *s, struct aspath *as, int use32bit )
fe69a505 856{
857 struct assegment *seg = as->segments;
0b2aa3a0 858 size_t bytes = 0;
fe69a505 859
860 if (!seg || seg->length == 0)
0b2aa3a0 861 return 0;
fe69a505 862
863 if (seg)
718e3744 864 {
0b2aa3a0
PJ
865 /*
866 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
867 * At the moment, we would write out a partial aspath, and our peer
868 * will complain and drop the session :-/
869 *
870 * The general assumption here is that many things tested will
871 * never happen. And, in real live, up to now, they have not.
872 */
873 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
fe69a505 874 {
0b2aa3a0 875 struct assegment *next = seg->next;
fe69a505 876 int written = 0;
0b2aa3a0 877 int asns_packed = 0;
fe69a505 878 size_t lenp;
879
880 /* Overlength segments have to be split up */
881 while ( (seg->length - written) > AS_SEGMENT_MAX)
882 {
883 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
0b2aa3a0 884 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
fe69a505 885 written += AS_SEGMENT_MAX;
0b2aa3a0 886 bytes += ASSEGMENT_SIZE (written, use32bit);
fe69a505 887 }
888
889 /* write the final segment, probably is also the first */
890 lenp = assegment_header_put (s, seg->type, seg->length - written);
0b2aa3a0
PJ
891 assegment_data_put (s, (seg->as + written), seg->length - written,
892 use32bit);
fe69a505 893
894 /* Sequence-type segments can be 'packed' together
895 * Case of a segment which was overlength and split up
896 * will be missed here, but that doesn't matter.
897 */
0b2aa3a0 898 while (next && ASSEGMENTS_PACKABLE (seg, next))
fe69a505 899 {
900 /* NB: We should never normally get here given we
901 * normalise aspath data when parse them. However, better
902 * safe than sorry. We potentially could call
903 * assegment_normalise here instead, but it's cheaper and
904 * easier to do it on the fly here rather than go through
905 * the segment list twice every time we write out
906 * aspath's.
907 */
908
909 /* Next segment's data can fit in this one */
0b2aa3a0 910 assegment_data_put (s, next->as, next->length, use32bit);
fe69a505 911
912 /* update the length of the segment header */
0b2aa3a0
PJ
913 stream_putc_at (s, lenp, seg->length - written + next->length);
914 asns_packed += next->length;
915
916 next = next->next;
fe69a505 917 }
0b2aa3a0
PJ
918
919 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
920 use32bit);
921 seg = next;
fe69a505 922 }
718e3744 923 }
0b2aa3a0 924 return bytes;
fe69a505 925}
926
927/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
928 * We have no way to manage the storage, so we use a static stream
929 * wrapper around aspath_put.
930 */
931u_char *
932aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
933{
934#define SNMP_PATHSEG_MAX 1024
8fdc32ab 935
936 if (!snmp_stream)
937 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
718e3744 938 else
8fdc32ab 939 stream_reset (snmp_stream);
fe69a505 940
941 if (!as)
718e3744 942 {
fe69a505 943 *varlen = 0;
944 return NULL;
718e3744 945 }
0b2aa3a0 946 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
fe69a505 947
8fdc32ab 948 *varlen = stream_get_endp (snmp_stream);
949 return stream_pnt(snmp_stream);
718e3744 950}
fe69a505 951
952#define min(A,B) ((A) < (B) ? (A) : (B))
718e3744 953
94f2b392 954static struct assegment *
718e3744 955aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
956 as_t as)
957{
958 int i;
959
960 /* If this is first AS set member, create new as-set segment. */
961 if (asset == NULL)
962 {
fe69a505 963 asset = assegment_new (AS_SET, 1);
964 if (! aspath->segments)
965 aspath->segments = asset;
718e3744 966 else
fe69a505 967 {
968 struct assegment *seg = aspath->segments;
969 while (seg->next)
970 seg = seg->next;
971 seg->next = asset;
972 }
718e3744 973 asset->type = AS_SET;
974 asset->length = 1;
fe69a505 975 asset->as[0] = as;
718e3744 976 }
977 else
978 {
718e3744 979 /* Check this AS value already exists or not. */
980 for (i = 0; i < asset->length; i++)
fe69a505 981 if (asset->as[i] == as)
718e3744 982 return asset;
fe69a505 983
718e3744 984 asset->length++;
fe69a505 985 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
986 asset->length * AS_VALUE_SIZE);
987 asset->as[asset->length - 1] = as;
718e3744 988 }
fe69a505 989
718e3744 990
991 return asset;
992}
993
994/* Modify as1 using as2 for aggregation. */
995struct aspath *
996aspath_aggregate (struct aspath *as1, struct aspath *as2)
997{
998 int i;
999 int minlen;
1000 int match;
fe69a505 1001 int from;
1002 struct assegment *seg1 = as1->segments;
1003 struct assegment *seg2 = as2->segments;
0b2aa3a0 1004 struct aspath *aspath = NULL;
718e3744 1005 struct assegment *asset;
0b2aa3a0 1006 struct assegment *prevseg = NULL;
718e3744 1007
1008 match = 0;
1009 minlen = 0;
1010 aspath = NULL;
1011 asset = NULL;
718e3744 1012
1013 /* First of all check common leading sequence. */
fe69a505 1014 while (seg1 && seg2)
0b2aa3a0 1015 {
718e3744 1016 /* Check segment type. */
1017 if (seg1->type != seg2->type)
1018 break;
1019
1020 /* Minimum segment length. */
1021 minlen = min (seg1->length, seg2->length);
1022
1023 for (match = 0; match < minlen; match++)
fe69a505 1024 if (seg1->as[match] != seg2->as[match])
718e3744 1025 break;
1026
1027 if (match)
1028 {
0b2aa3a0
PJ
1029 struct assegment *seg = assegment_new (seg1->type, 0);
1030
1031 seg = assegment_append_asns (seg, seg1->as, match);
1032
718e3744 1033 if (! aspath)
0b2aa3a0
PJ
1034 {
1035 aspath = aspath_new ();
1036 aspath->segments = seg;
1037 }
1038 else
1039 prevseg->next = seg;
1040
1041 prevseg = seg;
718e3744 1042 }
1043
1044 if (match != minlen || match != seg1->length
1045 || seg1->length != seg2->length)
1046 break;
fe69a505 1047
1048 seg1 = seg1->next;
1049 seg2 = seg2->next;
718e3744 1050 }
1051
1052 if (! aspath)
1053 aspath = aspath_new();
1054
1055 /* Make as-set using rest of all information. */
fe69a505 1056 from = match;
1057 while (seg1)
718e3744 1058 {
fe69a505 1059 for (i = from; i < seg1->length; i++)
1060 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1061
1062 from = 0;
1063 seg1 = seg1->next;
718e3744 1064 }
1065
fe69a505 1066 from = match;
1067 while (seg2)
718e3744 1068 {
fe69a505 1069 for (i = from; i < seg2->length; i++)
1070 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
718e3744 1071
fe69a505 1072 from = 0;
1073 seg2 = seg2->next;
718e3744 1074 }
fe69a505 1075
1076 assegment_normalise (aspath->segments);
1077 aspath_str_update (aspath);
718e3744 1078 return aspath;
1079}
1080
1081/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1082 attribute, check the leftmost AS number in the AS_PATH attribute is
1083 or not the peer's AS number. */
1084int
1085aspath_firstas_check (struct aspath *aspath, as_t asno)
1086{
fe69a505 1087 if ( (aspath == NULL) || (aspath->segments == NULL) )
718e3744 1088 return 0;
fe69a505 1089
1090 if (aspath->segments
1091 && (aspath->segments->type == AS_SEQUENCE)
1092 && (aspath->segments->as[0] == asno ))
718e3744 1093 return 1;
1094
1095 return 0;
1096}
1097
1f742f21 1098/* AS path loop check. If aspath contains asno then return >= 1. */
718e3744 1099int
1100aspath_loop_check (struct aspath *aspath, as_t asno)
1101{
fe69a505 1102 struct assegment *seg;
718e3744 1103 int count = 0;
1104
1f742f21 1105 if ( (aspath == NULL) || (aspath->segments == NULL) )
718e3744 1106 return 0;
fe69a505 1107
1108 seg = aspath->segments;
1109
1110 while (seg)
718e3744 1111 {
1112 int i;
718e3744 1113
fe69a505 1114 for (i = 0; i < seg->length; i++)
1115 if (seg->as[i] == asno)
718e3744 1116 count++;
fe69a505 1117
1118 seg = seg->next;
718e3744 1119 }
1120 return count;
1121}
1122
1123/* When all of AS path is private AS return 1. */
1124int
1125aspath_private_as_check (struct aspath *aspath)
1126{
fe69a505 1127 struct assegment *seg;
1128
1129 if ( !(aspath && aspath->segments) )
718e3744 1130 return 0;
fe69a505 1131
1132 seg = aspath->segments;
718e3744 1133
fe69a505 1134 while (seg)
718e3744 1135 {
1136 int i;
718e3744 1137
fe69a505 1138 for (i = 0; i < seg->length; i++)
718e3744 1139 {
fe69a505 1140 if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1141 || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
718e3744 1142 return 0;
1143 }
fe69a505 1144 seg = seg->next;
718e3744 1145 }
1146 return 1;
1147}
1148
ca87e1d3
VT
1149/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1150int
1151aspath_confed_check (struct aspath *aspath)
1152{
1153 struct assegment *seg;
1154
1155 if ( !(aspath && aspath->segments) )
1156 return 0;
1157
1158 seg = aspath->segments;
1159
1160 while (seg)
1161 {
1162 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1163 return 1;
1164 seg = seg->next;
1165 }
1166 return 0;
1167}
1168
1169/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1170 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1171int
1172aspath_left_confed_check (struct aspath *aspath)
1173{
1174
1175 if ( !(aspath && aspath->segments) )
1176 return 0;
1177
1178 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1179 || (aspath->segments->type == AS_CONFED_SET) )
1180 return 1;
1181
1182 return 0;
1183}
1184
718e3744 1185/* Merge as1 to as2. as2 should be uninterned aspath. */
94f2b392 1186static struct aspath *
718e3744 1187aspath_merge (struct aspath *as1, struct aspath *as2)
1188{
fe69a505 1189 struct assegment *last, *new;
718e3744 1190
1191 if (! as1 || ! as2)
1192 return NULL;
1193
fe69a505 1194 last = new = assegment_dup_all (as1->segments);
1195
1196 /* find the last valid segment */
1197 while (last && last->next)
1198 last = last->next;
1199
1200 last->next = as2->segments;
1201 as2->segments = new;
1202 aspath_str_update (as2);
718e3744 1203 return as2;
1204}
1205
1206/* Prepend as1 to as2. as2 should be uninterned aspath. */
1207struct aspath *
1208aspath_prepend (struct aspath *as1, struct aspath *as2)
1209{
fe69a505 1210 struct assegment *seg1;
1211 struct assegment *seg2;
718e3744 1212
1213 if (! as1 || ! as2)
1214 return NULL;
fe69a505 1215
1216 seg1 = as1->segments;
1217 seg2 = as2->segments;
1218
1219 /* If as2 is empty, only need to dupe as1's chain onto as2 */
718e3744 1220 if (seg2 == NULL)
1221 {
fe69a505 1222 as2->segments = assegment_dup_all (as1->segments);
1223 aspath_str_update (as2);
718e3744 1224 return as2;
1225 }
fe69a505 1226
1227 /* If as1 is empty AS, no prepending to do. */
718e3744 1228 if (seg1 == NULL)
1229 return as2;
fe69a505 1230
1231 /* find the tail as1's segment chain. */
1232 while (seg1 && seg1->next)
1233 seg1 = seg1->next;
718e3744 1234
736d4408
VT
1235 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1236 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1237 as2 = aspath_delete_confed_seq (as2);
1238
718e3744 1239 /* Compare last segment type of as1 and first segment type of as2. */
1240 if (seg1->type != seg2->type)
1241 return aspath_merge (as1, as2);
1242
1243 if (seg1->type == AS_SEQUENCE)
1244 {
fe69a505 1245 /* We have two chains of segments, as1->segments and seg2,
1246 * and we have to attach them together, merging the attaching
1247 * segments together into one.
1248 *
1249 * 1. dupe as1->segments onto head of as2
1250 * 2. merge seg2's asns onto last segment of this new chain
1251 * 3. attach chain after seg2
1252 */
718e3744 1253
fe69a505 1254 /* dupe as1 onto as2's head */
1255 seg1 = as2->segments = assegment_dup_all (as1->segments);
1256
1257 /* refind the tail of as2, reusing seg1 */
1258 while (seg1 && seg1->next)
1259 seg1 = seg1->next;
1260
1261 /* merge the old head, seg2, into tail, seg1 */
1262 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1263
1264 /* bypass the merged seg2, and attach any chain after it to
1265 * chain descending from as2's head
1266 */
1267 seg1->next = seg2->next;
1268
1269 /* seg2 is now referenceless and useless*/
1270 assegment_free (seg2);
1271
1272 /* we've now prepended as1's segment chain to as2, merging
1273 * the inbetween AS_SEQUENCE of seg2 in the process
1274 */
1275 aspath_str_update (as2);
718e3744 1276 return as2;
1277 }
1278 else
1279 {
1280 /* AS_SET merge code is needed at here. */
1281 return aspath_merge (as1, as2);
1282 }
fe69a505 1283 /* XXX: Ermmm, what if as1 has multiple segments?? */
1284
718e3744 1285 /* Not reached */
1286}
1287
841f7a57
DO
1288/* Iterate over AS_PATH segments and wipe all occurences of the
1289 * listed AS numbers. Hence some segments may lose some or even
1290 * all data on the way, the operation is implemented as a smarter
1291 * version of aspath_dup(), which allocates memory to hold the new
1292 * data, not the original. The new AS path is returned.
1293 */
1294struct aspath *
1295aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1296{
1297 struct assegment * srcseg, * exclseg, * lastseg;
1298 struct aspath * newpath;
1299
1300 newpath = aspath_new();
1301 lastseg = NULL;
1302
1303 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1304 {
1305 unsigned i, y, newlen = 0, done = 0, skip_as;
1306 struct assegment * newseg;
1307
1308 /* Find out, how much ASns are we going to pick from this segment.
1309 * We can't perform filtering right inline, because the size of
1310 * the new segment isn't known at the moment yet.
1311 */
1312 for (i = 0; i < srcseg->length; i++)
1313 {
1314 skip_as = 0;
1315 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1316 for (y = 0; y < exclseg->length; y++)
1317 if (srcseg->as[i] == exclseg->as[y])
1318 {
1319 skip_as = 1;
1320 // There's no sense in testing the rest of exclusion list, bail out.
1321 break;
1322 }
1323 if (!skip_as)
1324 newlen++;
1325 }
1326 /* newlen is now the number of ASns to copy */
1327 if (!newlen)
1328 continue;
1329
1330 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1331 newseg = assegment_new (srcseg->type, newlen);
1332 for (i = 0; i < srcseg->length; i++)
1333 {
1334 skip_as = 0;
1335 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1336 for (y = 0; y < exclseg->length; y++)
1337 if (srcseg->as[i] == exclseg->as[y])
1338 {
1339 skip_as = 1;
1340 break;
1341 }
1342 if (skip_as)
1343 continue;
1344 newseg->as[done++] = srcseg->as[i];
1345 }
1346 /* At his point newlen must be equal to done, and both must be positive. Append
1347 * the filtered segment to the gross result. */
1348 if (!lastseg)
1349 newpath->segments = newseg;
1350 else
1351 lastseg->next = newseg;
1352 lastseg = newseg;
1353 }
1354 aspath_str_update (newpath);
1355 /* We are happy returning even an empty AS_PATH, because the administrator
1356 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1357 * by having a match rule against certain AS_PATH regexps in the route-map index.
1358 */
1359 aspath_free (source);
1360 return newpath;
1361}
1362
718e3744 1363/* Add specified AS to the leftmost of aspath. */
1364static struct aspath *
1365aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1366{
fe69a505 1367 struct assegment *assegment = aspath->segments;
718e3744 1368
1369 /* In case of empty aspath. */
1370 if (assegment == NULL || assegment->length == 0)
1371 {
fe69a505 1372 aspath->segments = assegment_new (type, 1);
1373 aspath->segments->as[0] = asno;
1374
718e3744 1375 if (assegment)
fe69a505 1376 assegment_free (assegment);
718e3744 1377
1378 return aspath;
1379 }
1380
1381 if (assegment->type == type)
fe69a505 1382 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1383 else
718e3744 1384 {
fe69a505 1385 /* create new segment
1386 * push it onto head of aspath's segment chain
1387 */
718e3744 1388 struct assegment *newsegment;
fe69a505 1389
1390 newsegment = assegment_new (type, 1);
1391 newsegment->as[0] = asno;
1392
1393 newsegment->next = assegment;
1394 aspath->segments = newsegment;
718e3744 1395 }
1396
1397 return aspath;
1398}
1399
1400/* Add specified AS to the leftmost of aspath. */
1401struct aspath *
1402aspath_add_seq (struct aspath *aspath, as_t asno)
1403{
1404 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1405}
1406
1407/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1408 as2's leftmost AS is same return 1. */
1409int
ffe11cfb 1410aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
718e3744 1411{
f669f7d2
JBD
1412 const struct assegment *seg1;
1413 const struct assegment *seg2;
718e3744 1414
fe69a505 1415 if (!(aspath1 && aspath2))
1416 return 0;
718e3744 1417
fe69a505 1418 seg1 = aspath1->segments;
1419 seg2 = aspath2->segments;
718e3744 1420
fe69a505 1421 /* find first non-confed segments for each */
1422 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1423 || (seg1->type == AS_CONFED_SET)))
1424 seg1 = seg1->next;
718e3744 1425
fe69a505 1426 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1427 || (seg2->type == AS_CONFED_SET)))
1428 seg2 = seg2->next;
718e3744 1429
fe69a505 1430 /* Check as1's */
1431 if (!(seg1 && seg2
1432 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
1433 return 0;
1434
1435 if (seg1->as[0] == seg2->as[0])
718e3744 1436 return 1;
1437
1438 return 0;
1439}
1440
0b2aa3a0
PJ
1441/* Truncate an aspath after a number of hops, and put the hops remaining
1442 * at the front of another aspath. Needed for AS4 compat.
1443 *
1444 * Returned aspath is a /new/ aspath, which should either by free'd or
1445 * interned by the caller, as desired.
1446 */
1447struct aspath *
1448aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1449{
1450 struct assegment *seg, *newseg, *prevseg = NULL;
1451 struct aspath *newpath = NULL, *mergedpath;
1452 int hops, cpasns = 0;
1453
1454 if (!aspath)
1455 return NULL;
1456
1457 seg = aspath->segments;
1458
1459 /* CONFEDs should get reconciled too.. */
1460 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1461 - aspath_count_hops (as4path);
1462
1463 if (hops < 0)
1464 {
1465 if (BGP_DEBUG (as4, AS4))
1466 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1467 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1468 * which is daft behaviour - it contains vital loop-detection
1469 * information which must have been removed from AS_PATH.
1470 */
1471 hops = aspath_count_hops (aspath);
1472 }
1473
1474 if (!hops)
1475 return aspath_dup (as4path);
1476
1477 if ( BGP_DEBUG(as4, AS4))
1478 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1479 aspath->str, as4path->str);
1480
1481 while (seg && hops > 0)
1482 {
1483 switch (seg->type)
1484 {
1485 case AS_SET:
1486 case AS_CONFED_SET:
1487 hops--;
1488 cpasns = seg->length;
1489 break;
1490 case AS_CONFED_SEQUENCE:
1491 /* Should never split a confed-sequence, if hop-count
1492 * suggests we must then something's gone wrong somewhere.
1493 *
1494 * Most important goal is to preserve AS_PATHs prime function
1495 * as loop-detector, so we fudge the numbers so that the entire
1496 * confed-sequence is merged in.
1497 */
1498 if (hops < seg->length)
1499 {
1500 if (BGP_DEBUG (as4, AS4))
1501 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1502 " across 2/4 ASN boundary somewhere, broken..");
1503 hops = seg->length;
1504 }
1505 case AS_SEQUENCE:
1506 cpasns = MIN(seg->length, hops);
1507 hops -= seg->length;
1508 }
1509
1510 assert (cpasns <= seg->length);
1511
1512 newseg = assegment_new (seg->type, 0);
1513 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1514
1515 if (!newpath)
1516 {
1517 newpath = aspath_new ();
1518 newpath->segments = newseg;
1519 }
1520 else
1521 prevseg->next = newseg;
1522
1523 prevseg = newseg;
1524 seg = seg->next;
1525 }
1526
1527 /* We may be able to join some segments here, and we must
1528 * do this because... we want normalised aspaths in out hash
1529 * and we do not want to stumble in aspath_put.
1530 */
1531 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1532 aspath_free (newpath);
1533 mergedpath->segments = assegment_normalise (mergedpath->segments);
1534 aspath_str_update (mergedpath);
1535
1536 if ( BGP_DEBUG(as4, AS4))
1537 zlog_debug ("[AS4] result of synthesizing is %s",
1538 mergedpath->str);
1539
1540 return mergedpath;
1541}
1542
718e3744 1543/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1544 as2's leftmost AS is same return 1. (confederation as-path
1545 only). */
1546int
ffe11cfb 1547aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
718e3744 1548{
fe69a505 1549 if (! (aspath1 && aspath2) )
718e3744 1550 return 0;
fe69a505 1551
ad72740e 1552 if ( !(aspath1->segments && aspath2->segments) )
1553 return 0;
1554
fe69a505 1555 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1556 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
718e3744 1557 return 0;
fe69a505 1558
1559 if (aspath1->segments->as[0] == aspath2->segments->as[0])
718e3744 1560 return 1;
1561
1562 return 0;
1563}
1564
fe69a505 1565/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1566 * See RFC3065, 6.1 c1 */
718e3744 1567struct aspath *
1568aspath_delete_confed_seq (struct aspath *aspath)
1569{
fe69a505 1570 struct assegment *seg;
718e3744 1571
fe69a505 1572 if (!(aspath && aspath->segments))
718e3744 1573 return aspath;
1574
fe69a505 1575 seg = aspath->segments;
1576
1577 /* "if the first path segment of the AS_PATH is
1578 * of type AS_CONFED_SEQUENCE,"
1579 */
1580 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1581 return aspath;
718e3744 1582
fe69a505 1583 /* "... that segment and any immediately following segments
1584 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1585 * from the AS_PATH attribute,"
1586 */
1587 while (seg &&
1588 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
718e3744 1589 {
fe69a505 1590 aspath->segments = seg->next;
1591 assegment_free (seg);
1592 seg = aspath->segments;
718e3744 1593 }
fe69a505 1594 aspath_str_update (aspath);
718e3744 1595 return aspath;
1596}
1597
1598/* Add new AS number to the leftmost part of the aspath as
1599 AS_CONFED_SEQUENCE. */
1600struct aspath*
1601aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1602{
1603 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1604}
1605
1606/* Add new as value to as path structure. */
94f2b392 1607static void
718e3744 1608aspath_as_add (struct aspath *as, as_t asno)
1609{
fe69a505 1610 struct assegment *seg = as->segments;
718e3744 1611
fe69a505 1612 if (!seg)
1613 return;
1614
93c1749c
AS
1615 /* Last segment search procedure. */
1616 while (seg->next)
1617 seg = seg->next;
1618
fe69a505 1619 assegment_append_asns (seg, &asno, 1);
718e3744 1620}
1621
1622/* Add new as segment to the as path. */
94f2b392 1623static void
718e3744 1624aspath_segment_add (struct aspath *as, int type)
1625{
fe69a505 1626 struct assegment *seg = as->segments;
1627 struct assegment *new = assegment_new (type, 0);
718e3744 1628
93c1749c
AS
1629 if (seg)
1630 {
1631 while (seg->next)
1632 seg = seg->next;
1633 seg->next = new;
1634 }
718e3744 1635 else
93c1749c 1636 as->segments = new;
718e3744 1637}
1638
1639struct aspath *
94f2b392 1640aspath_empty (void)
718e3744 1641{
ab005298 1642 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
718e3744 1643}
1644
1645struct aspath *
94f2b392 1646aspath_empty_get (void)
718e3744 1647{
1648 struct aspath *aspath;
1649
1650 aspath = aspath_new ();
f669f7d2 1651 aspath_make_str_count (aspath);
718e3744 1652 return aspath;
1653}
1654
1655unsigned long
fe69a505 1656aspath_count (void)
718e3744 1657{
1658 return ashash->count;
1659}
1660\f
1661/*
1662 Theoretically, one as path can have:
1663
1664 One BGP packet size should be less than 4096.
1665 One BGP attribute size should be less than 4096 - BGP header size.
1666 One BGP aspath size should be less than 4096 - BGP header size -
1667 BGP mandantry attribute size.
1668*/
1669
1670/* AS path string lexical token enum. */
1671enum as_token
1672{
1673 as_token_asval,
1674 as_token_set_start,
1675 as_token_set_end,
fe69a505 1676 as_token_confed_seq_start,
1677 as_token_confed_seq_end,
1678 as_token_confed_set_start,
1679 as_token_confed_set_end,
718e3744 1680 as_token_unknown
1681};
1682
1683/* Return next token and point for string parse. */
94f2b392 1684static const char *
0b2aa3a0 1685aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
718e3744 1686{
fd79ac91 1687 const char *p = buf;
718e3744 1688
fe69a505 1689 /* Skip seperators (space for sequences, ',' for sets). */
1690 while (isspace ((int) *p) || *p == ',')
718e3744 1691 p++;
1692
1693 /* Check the end of the string and type specify characters
1694 (e.g. {}()). */
1695 switch (*p)
1696 {
1697 case '\0':
1698 return NULL;
718e3744 1699 case '{':
1700 *token = as_token_set_start;
1701 p++;
1702 return p;
718e3744 1703 case '}':
1704 *token = as_token_set_end;
1705 p++;
1706 return p;
718e3744 1707 case '(':
fe69a505 1708 *token = as_token_confed_seq_start;
718e3744 1709 p++;
1710 return p;
718e3744 1711 case ')':
fe69a505 1712 *token = as_token_confed_seq_end;
1713 p++;
1714 return p;
fe69a505 1715 case '[':
1716 *token = as_token_confed_set_start;
1717 p++;
1718 return p;
fe69a505 1719 case ']':
1720 *token = as_token_confed_set_end;
718e3744 1721 p++;
1722 return p;
718e3744 1723 }
1724
1725 /* Check actual AS value. */
1726 if (isdigit ((int) *p))
1727 {
10819ece 1728 as_t asval;
0b2aa3a0 1729
718e3744 1730 *token = as_token_asval;
1731 asval = (*p - '0');
1732 p++;
0b2aa3a0 1733
718e3744 1734 while (isdigit ((int) *p))
0b2aa3a0
PJ
1735 {
1736 asval *= 10;
1737 asval += (*p - '0');
1738 p++;
1739 }
718e3744 1740 *asno = asval;
1741 return p;
1742 }
1743
1744 /* There is no match then return unknown token. */
1745 *token = as_token_unknown;
1746 return p++;
1747}
1748
1749struct aspath *
fd79ac91 1750aspath_str2aspath (const char *str)
718e3744 1751{
3fff6ffc 1752 enum as_token token = as_token_unknown;
718e3744 1753 u_short as_type;
0b2aa3a0 1754 u_long asno = 0;
718e3744 1755 struct aspath *aspath;
1756 int needtype;
1757
1758 aspath = aspath_new ();
1759
1760 /* We start default type as AS_SEQUENCE. */
1761 as_type = AS_SEQUENCE;
1762 needtype = 1;
1763
1764 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1765 {
1766 switch (token)
1767 {
1768 case as_token_asval:
1769 if (needtype)
1770 {
1771 aspath_segment_add (aspath, as_type);
1772 needtype = 0;
1773 }
1774 aspath_as_add (aspath, asno);
1775 break;
1776 case as_token_set_start:
1777 as_type = AS_SET;
1778 aspath_segment_add (aspath, as_type);
1779 needtype = 0;
1780 break;
1781 case as_token_set_end:
1782 as_type = AS_SEQUENCE;
1783 needtype = 1;
1784 break;
fe69a505 1785 case as_token_confed_seq_start:
718e3744 1786 as_type = AS_CONFED_SEQUENCE;
1787 aspath_segment_add (aspath, as_type);
1788 needtype = 0;
1789 break;
fe69a505 1790 case as_token_confed_seq_end:
1791 as_type = AS_SEQUENCE;
1792 needtype = 1;
1793 break;
1794 case as_token_confed_set_start:
1795 as_type = AS_CONFED_SET;
1796 aspath_segment_add (aspath, as_type);
1797 needtype = 0;
1798 break;
1799 case as_token_confed_set_end:
718e3744 1800 as_type = AS_SEQUENCE;
1801 needtype = 1;
1802 break;
1803 case as_token_unknown:
1804 default:
fe69a505 1805 aspath_free (aspath);
718e3744 1806 return NULL;
718e3744 1807 }
1808 }
1809
f669f7d2 1810 aspath_make_str_count (aspath);
718e3744 1811
1812 return aspath;
1813}
1814\f
1815/* Make hash value by raw aspath data. */
1816unsigned int
923de654 1817aspath_key_make (void *p)
718e3744 1818{
f669f7d2 1819 struct aspath *aspath = (struct aspath *) p;
718e3744 1820 unsigned int key = 0;
718e3744 1821
0b2aa3a0
PJ
1822 if (!aspath->str)
1823 aspath_str_update (aspath);
f669f7d2
JBD
1824
1825 key = jhash (aspath->str, aspath->str_len, 2334325);
718e3744 1826
1827 return key;
1828}
1829
1830/* If two aspath have same value then return 1 else return 0 */
96450faf 1831int
ffe11cfb 1832aspath_cmp (const void *arg1, const void *arg2)
718e3744 1833{
aea339f7
DO
1834 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1835 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
fe69a505 1836
1837 while (seg1 || seg2)
1838 {
1839 int i;
1840 if ((!seg1 && seg2) || (seg1 && !seg2))
1841 return 0;
1842 if (seg1->type != seg2->type)
1843 return 0;
1844 if (seg1->length != seg2->length)
1845 return 0;
1846 for (i = 0; i < seg1->length; i++)
1847 if (seg1->as[i] != seg2->as[i])
1848 return 0;
1849 seg1 = seg1->next;
1850 seg2 = seg2->next;
1851 }
1852 return 1;
718e3744 1853}
1854
1855/* AS path hash initialize. */
1856void
94f2b392 1857aspath_init (void)
718e3744 1858{
90645f55 1859 ashash = hash_create_size (32768, aspath_key_make, aspath_cmp);
718e3744 1860}
8fdc32ab 1861
1862void
1863aspath_finish (void)
1864{
1865 hash_free (ashash);
228da428 1866 ashash = NULL;
8fdc32ab 1867
1868 if (snmp_stream)
1869 stream_free (snmp_stream);
1870}
718e3744 1871\f
1872/* return and as path value */
1873const char *
1874aspath_print (struct aspath *as)
1875{
fe69a505 1876 return (as ? as->str : NULL);
718e3744 1877}
1878
1879/* Printing functions */
841f7a57
DO
1880/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1881 * AS_PATH wasn't empty.
1882 */
718e3744 1883void
841f7a57 1884aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
718e3744 1885{
b2518c1e
PJ
1886 assert (format);
1887 vty_out (vty, format, as->str);
f669f7d2 1888 if (as->str_len && strlen (suffix))
841f7a57 1889 vty_out (vty, "%s", suffix);
718e3744 1890}
1891
94f2b392 1892static void
718e3744 1893aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1894{
1895 struct aspath *as;
1896
1897 as = (struct aspath *) backet->data;
1898
efa9f830 1899 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
718e3744 1900 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1901}
1902
1903/* Print all aspath and hash information. This function is used from
1904 `show ip bgp paths' command. */
1905void
1906aspath_print_all_vty (struct vty *vty)
1907{
1908 hash_iterate (ashash,
1909 (void (*) (struct hash_backet *, void *))
1910 aspath_show_all_iterator,
1911 vty);
1912}