]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_aspath.c
per-interface ospf enable and area set command.
[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"
6b0655a2 37
718e3744 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;
6b0655a2 93
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}
6b0655a2 311
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;
5000f21c 466
2815e61f
PJ
467 while (seg)
468 {
469 for (i = 0; i < seg->length; i++)
5000f21c 470 if (seg->as[i] > highest && !BGP_AS_IS_PRIVATE(seg->as[i]))
2815e61f
PJ
471 highest = seg->as[i];
472 seg = seg->next;
473 }
474 return highest;
475}
476
0b2aa3a0
PJ
477/* Return 1 if there are any 4-byte ASes in the path */
478unsigned int
479aspath_has_as4 (struct aspath *aspath)
480{
481 struct assegment *seg = aspath->segments;
482 unsigned int i;
483
484 while (seg)
485 {
486 for (i = 0; i < seg->length; i++)
487 if (seg->as[i] > BGP_AS_MAX)
488 return 1;
489 seg = seg->next;
490 }
491 return 0;
492}
493
718e3744 494/* Convert aspath structure to string expression. */
f669f7d2 495static void
718e3744 496aspath_make_str_count (struct aspath *as)
497{
fe69a505 498 struct assegment *seg;
499 int str_size;
500 int len = 0;
c9e52be3 501 char *str_buf;
718e3744 502
503 /* Empty aspath. */
fe69a505 504 if (!as->segments)
718e3744 505 {
f669f7d2
JBD
506 as->str = XMALLOC (MTYPE_AS_STR, 1);
507 as->str[0] = '\0';
508 as->str_len = 0;
509 return;
718e3744 510 }
fe69a505 511
512 seg = as->segments;
513
014b670e
DO
514 /* ASN takes 5 to 10 chars plus seperator, see below.
515 * If there is one differing segment type, we need an additional
516 * 2 chars for segment delimiters, and the final '\0'.
517 * Hopefully this is large enough to avoid hitting the realloc
518 * code below for most common sequences.
519 *
520 * This was changed to 10 after the well-known BGP assertion, which
521 * had hit some parts of the Internet in May of 2009.
522 */
523#define ASN_STR_LEN (10 + 1)
524 str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
525 ASPATH_STR_DEFAULT_LEN);
718e3744 526 str_buf = XMALLOC (MTYPE_AS_STR, str_size);
718e3744 527
fe69a505 528 while (seg)
718e3744 529 {
530 int i;
fe69a505 531 char seperator;
718e3744 532
fe69a505 533 /* Check AS type validity. Set seperator for segment */
534 switch (seg->type)
535 {
536 case AS_SET:
537 case AS_CONFED_SET:
538 seperator = ',';
539 break;
540 case AS_SEQUENCE:
541 case AS_CONFED_SEQUENCE:
542 seperator = ' ';
543 break;
544 default:
545 XFREE (MTYPE_AS_STR, str_buf);
f669f7d2
JBD
546 as->str = NULL;
547 as->str_len = 0;
548 return;
fe69a505 549 }
550
014b670e
DO
551 /* We might need to increase str_buf, particularly if path has
552 * differing segments types, our initial guesstimate above will
553 * have been wrong. Need 10 chars for ASN, a seperator each and
554 * potentially two segment delimiters, plus a space between each
555 * segment and trailing zero.
556 *
557 * This definitely didn't work with the value of 5 bytes and
558 * 32-bit ASNs.
559 */
560#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
561 if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
562 {
563 str_size = len + SEGMENT_STR_LEN(seg);
564 str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
565 }
566#undef ASN_STR_LEN
567#undef SEGMENT_STR_LEN
568
fe69a505 569 if (seg->type != AS_SEQUENCE)
014b670e
DO
570 len += snprintf (str_buf + len, str_size - len,
571 "%c",
572 aspath_delimiter_char (seg->type, AS_SEG_START));
fe69a505 573
574 /* write out the ASNs, with their seperators, bar the last one*/
575 for (i = 0; i < seg->length; i++)
576 {
577 len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
578
579 if (i < (seg->length - 1))
580 len += snprintf (str_buf + len, str_size - len, "%c", seperator);
581 }
582
583 if (seg->type != AS_SEQUENCE)
584 len += snprintf (str_buf + len, str_size - len, "%c",
585 aspath_delimiter_char (seg->type, AS_SEG_END));
586 if (seg->next)
587 len += snprintf (str_buf + len, str_size - len, " ");
588
589 seg = seg->next;
718e3744 590 }
fe69a505 591
592 assert (len < str_size);
593
594 str_buf[len] = '\0';
f669f7d2
JBD
595 as->str = str_buf;
596 as->str_len = len;
718e3744 597
f669f7d2 598 return;
718e3744 599}
600
fe69a505 601static void
602aspath_str_update (struct aspath *as)
603{
604 if (as->str)
605 XFREE (MTYPE_AS_STR, as->str);
f669f7d2 606 aspath_make_str_count (as);
fe69a505 607}
608
718e3744 609/* Intern allocated AS path. */
610struct aspath *
611aspath_intern (struct aspath *aspath)
612{
613 struct aspath *find;
f669f7d2
JBD
614
615 /* Assert this AS path structure is not interned and has the string
616 representation built. */
718e3744 617 assert (aspath->refcnt == 0);
f669f7d2 618 assert (aspath->str);
718e3744 619
620 /* Check AS path hash. */
621 find = hash_get (ashash, aspath, hash_alloc_intern);
718e3744 622 if (find != aspath)
fe69a505 623 aspath_free (aspath);
718e3744 624
625 find->refcnt++;
626
718e3744 627 return find;
628}
629
630/* Duplicate aspath structure. Created same aspath structure but
631 reference count and AS path string is cleared. */
632struct aspath *
633aspath_dup (struct aspath *aspath)
634{
f669f7d2 635 unsigned short buflen = aspath->str_len + 1;
718e3744 636 struct aspath *new;
637
fe69a505 638 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
718e3744 639
fe69a505 640 if (aspath->segments)
641 new->segments = assegment_dup_all (aspath->segments);
718e3744 642
f669f7d2
JBD
643 if (!aspath->str)
644 return new;
645
646 new->str = XMALLOC (MTYPE_AS_STR, buflen);
647 new->str_len = aspath->str_len;
648
649 /* copy the string data */
650 if (aspath->str_len > 0)
651 memcpy (new->str, aspath->str, buflen);
652 else
653 new->str[0] = '\0';
718e3744 654
655 return new;
656}
657
94f2b392 658static void *
fe69a505 659aspath_hash_alloc (void *arg)
718e3744 660{
f669f7d2
JBD
661 const struct aspath *aspath = arg;
662 struct aspath *new;
718e3744 663
718e3744 664 /* Malformed AS path value. */
f669f7d2 665 assert (aspath->str);
718e3744 666 if (! aspath->str)
f669f7d2 667 return NULL;
718e3744 668
f669f7d2
JBD
669 /* New aspath structure is needed. */
670 new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
671
672 /* Reuse segments and string representation */
673 new->refcnt = 0;
674 new->segments = aspath->segments;
675 new->str = aspath->str;
676 new->str_len = aspath->str_len;
677
678 return new;
718e3744 679}
680
ab005298 681/* parse as-segment byte stream in struct assegment */
b881c707
PJ
682static int
683assegments_parse (struct stream *s, size_t length,
684 struct assegment **result, int use32bit)
fe69a505 685{
686 struct assegment_header segh;
687 struct assegment *seg, *prev = NULL, *head = NULL;
ab005298 688 size_t bytes = 0;
fe69a505 689
ab005298
PJ
690 /* empty aspath (ie iBGP or somesuch) */
691 if (length == 0)
b881c707 692 return 0;
fe69a505 693
0b2aa3a0
PJ
694 if (BGP_DEBUG (as4, AS4_SEGMENT))
695 zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
696 (unsigned long) length);
ab005298
PJ
697 /* basic checks */
698 if ((STREAM_READABLE(s) < length)
699 || (STREAM_READABLE(s) < AS_HEADER_SIZE)
700 || (length % AS16_VALUE_SIZE ))
b881c707 701 return -1;
fe69a505 702
ab005298 703 while (bytes < length)
fe69a505 704 {
705 int i;
cddb8112 706 size_t seg_size;
fe69a505 707
ab005298 708 if ((length - bytes) <= AS_HEADER_SIZE)
cddb8112 709 {
ab005298
PJ
710 if (head)
711 assegment_free_all (head);
b881c707 712 return -1;
fdbc8e77
PJ
713 }
714
ab005298 715 /* softly softly, get the header first on its own */
fe69a505 716 segh.type = stream_getc (s);
717 segh.length = stream_getc (s);
718
0b2aa3a0
PJ
719 seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
720
721 if (BGP_DEBUG (as4, AS4_SEGMENT))
722 zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
723 segh.type, segh.length);
724
ab005298
PJ
725 /* check it.. */
726 if ( ((bytes + seg_size) > length)
727 /* 1771bis 4.3b: seg length contains one or more */
728 || (segh.length == 0)
729 /* Paranoia in case someone changes type of segment length.
730 * Shift both values by 0x10 to make the comparison operate
731 * on more, than 8 bits (otherwise it's a warning, bug #564).
2eb445e1 732 */
ab005298
PJ
733 || ((sizeof segh.length > 1)
734 && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
fe69a505 735 {
ab005298 736 if (head)
fe69a505 737 assegment_free_all (head);
b881c707 738 return -1;
fe69a505 739 }
740
fdbc8e77
PJ
741 switch (segh.type)
742 {
743 case AS_SEQUENCE:
744 case AS_SET:
fdbc8e77
PJ
745 case AS_CONFED_SEQUENCE:
746 case AS_CONFED_SET:
ab005298
PJ
747 break;
748 default:
749 if (head)
750 assegment_free_all (head);
b881c707 751 return -1;
fe69a505 752 }
753
754 /* now its safe to trust lengths */
755 seg = assegment_new (segh.type, segh.length);
756
757 if (head)
758 prev->next = seg;
759 else /* it's the first segment */
760 head = prev = seg;
761
762 for (i = 0; i < segh.length; i++)
0b2aa3a0
PJ
763 seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
764
ab005298
PJ
765 bytes += seg_size;
766
0b2aa3a0 767 if (BGP_DEBUG (as4, AS4_SEGMENT))
ab005298
PJ
768 zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
769 (unsigned long) bytes);
fe69a505 770
771 prev = seg;
772 }
773
b881c707
PJ
774 *result = assegment_normalise (head);
775 return 0;
fe69a505 776}
777
ab005298
PJ
778/* AS path parse function. pnt is a pointer to byte stream and length
779 is length of byte stream. If there is same AS path in the the AS
b881c707
PJ
780 path hash then return it else make new AS path structure.
781
782 On error NULL is returned.
cddb8112 783 */
718e3744 784struct aspath *
ab005298 785aspath_parse (struct stream *s, size_t length, int use32bit)
718e3744 786{
787 struct aspath as;
788 struct aspath *find;
789
ab005298
PJ
790 /* If length is odd it's malformed AS path. */
791 /* Nit-picking: if (use32bit == 0) it is malformed if odd,
792 * otherwise its malformed when length is larger than 2 and (length-2)
793 * is not dividable by 4.
794 * But... this time we're lazy
795 */
796 if (length % AS16_VALUE_SIZE )
797 return NULL;
cddb8112 798
ab005298 799 memset (&as, 0, sizeof (struct aspath));
b881c707
PJ
800 if (assegments_parse (s, length, &as.segments, use32bit) < 0)
801 return NULL;
f669f7d2 802
718e3744 803 /* If already same aspath exist then return it. */
804 find = hash_get (ashash, &as, aspath_hash_alloc);
f669f7d2
JBD
805
806 /* bug! should not happen, let the daemon crash below */
807 assert (find);
808
809 /* if the aspath was already hashed free temporary memory. */
810 if (find->refcnt)
811 {
812 assegment_free_all (as.segments);
813 /* aspath_key_make() always updates the string */
814 XFREE (MTYPE_AS_STR, as.str);
815 }
816
718e3744 817 find->refcnt++;
818
819 return find;
820}
821
f63f06da 822static void
0b2aa3a0 823assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
fe69a505 824{
825 int i;
826 assert (num <= AS_SEGMENT_MAX);
827
828 for (i = 0; i < num; i++)
0b2aa3a0
PJ
829 if ( use32bit )
830 stream_putl (s, as[i]);
831 else
832 {
833 if ( as[i] <= BGP_AS_MAX )
834 stream_putw(s, as[i]);
835 else
836 stream_putw(s, BGP_AS_TRANS);
837 }
fe69a505 838}
718e3744 839
f63f06da 840static size_t
fe69a505 841assegment_header_put (struct stream *s, u_char type, int length)
718e3744 842{
fe69a505 843 size_t lenp;
844 assert (length <= AS_SEGMENT_MAX);
845 stream_putc (s, type);
846 lenp = stream_get_endp (s);
847 stream_putc (s, length);
848 return lenp;
849}
718e3744 850
fe69a505 851/* write aspath data to stream */
0b2aa3a0
PJ
852size_t
853aspath_put (struct stream *s, struct aspath *as, int use32bit )
fe69a505 854{
855 struct assegment *seg = as->segments;
0b2aa3a0 856 size_t bytes = 0;
fe69a505 857
858 if (!seg || seg->length == 0)
0b2aa3a0 859 return 0;
fe69a505 860
861 if (seg)
718e3744 862 {
0b2aa3a0
PJ
863 /*
864 * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
865 * At the moment, we would write out a partial aspath, and our peer
866 * will complain and drop the session :-/
867 *
868 * The general assumption here is that many things tested will
869 * never happen. And, in real live, up to now, they have not.
870 */
871 while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
fe69a505 872 {
0b2aa3a0 873 struct assegment *next = seg->next;
fe69a505 874 int written = 0;
0b2aa3a0 875 int asns_packed = 0;
fe69a505 876 size_t lenp;
877
878 /* Overlength segments have to be split up */
879 while ( (seg->length - written) > AS_SEGMENT_MAX)
880 {
881 assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
0b2aa3a0 882 assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
fe69a505 883 written += AS_SEGMENT_MAX;
0b2aa3a0 884 bytes += ASSEGMENT_SIZE (written, use32bit);
fe69a505 885 }
886
887 /* write the final segment, probably is also the first */
888 lenp = assegment_header_put (s, seg->type, seg->length - written);
0b2aa3a0
PJ
889 assegment_data_put (s, (seg->as + written), seg->length - written,
890 use32bit);
fe69a505 891
892 /* Sequence-type segments can be 'packed' together
893 * Case of a segment which was overlength and split up
894 * will be missed here, but that doesn't matter.
895 */
0b2aa3a0 896 while (next && ASSEGMENTS_PACKABLE (seg, next))
fe69a505 897 {
898 /* NB: We should never normally get here given we
899 * normalise aspath data when parse them. However, better
900 * safe than sorry. We potentially could call
901 * assegment_normalise here instead, but it's cheaper and
902 * easier to do it on the fly here rather than go through
903 * the segment list twice every time we write out
904 * aspath's.
905 */
906
907 /* Next segment's data can fit in this one */
0b2aa3a0 908 assegment_data_put (s, next->as, next->length, use32bit);
fe69a505 909
910 /* update the length of the segment header */
0b2aa3a0
PJ
911 stream_putc_at (s, lenp, seg->length - written + next->length);
912 asns_packed += next->length;
913
914 next = next->next;
fe69a505 915 }
0b2aa3a0
PJ
916
917 bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
918 use32bit);
919 seg = next;
fe69a505 920 }
718e3744 921 }
0b2aa3a0 922 return bytes;
fe69a505 923}
924
925/* This is for SNMP BGP4PATHATTRASPATHSEGMENT
926 * We have no way to manage the storage, so we use a static stream
927 * wrapper around aspath_put.
928 */
929u_char *
930aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
931{
932#define SNMP_PATHSEG_MAX 1024
8fdc32ab 933
934 if (!snmp_stream)
935 snmp_stream = stream_new (SNMP_PATHSEG_MAX);
718e3744 936 else
8fdc32ab 937 stream_reset (snmp_stream);
fe69a505 938
939 if (!as)
718e3744 940 {
fe69a505 941 *varlen = 0;
942 return NULL;
718e3744 943 }
0b2aa3a0 944 aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
fe69a505 945
8fdc32ab 946 *varlen = stream_get_endp (snmp_stream);
947 return stream_pnt(snmp_stream);
718e3744 948}
fe69a505 949
950#define min(A,B) ((A) < (B) ? (A) : (B))
718e3744 951
94f2b392 952static struct assegment *
718e3744 953aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
954 as_t as)
955{
956 int i;
957
958 /* If this is first AS set member, create new as-set segment. */
959 if (asset == NULL)
960 {
fe69a505 961 asset = assegment_new (AS_SET, 1);
962 if (! aspath->segments)
963 aspath->segments = asset;
718e3744 964 else
fe69a505 965 {
966 struct assegment *seg = aspath->segments;
967 while (seg->next)
968 seg = seg->next;
969 seg->next = asset;
970 }
718e3744 971 asset->type = AS_SET;
972 asset->length = 1;
fe69a505 973 asset->as[0] = as;
718e3744 974 }
975 else
976 {
718e3744 977 /* Check this AS value already exists or not. */
978 for (i = 0; i < asset->length; i++)
fe69a505 979 if (asset->as[i] == as)
718e3744 980 return asset;
fe69a505 981
718e3744 982 asset->length++;
fe69a505 983 asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
984 asset->length * AS_VALUE_SIZE);
985 asset->as[asset->length - 1] = as;
718e3744 986 }
fe69a505 987
718e3744 988
989 return asset;
990}
991
992/* Modify as1 using as2 for aggregation. */
993struct aspath *
994aspath_aggregate (struct aspath *as1, struct aspath *as2)
995{
996 int i;
997 int minlen;
998 int match;
fe69a505 999 int from;
1000 struct assegment *seg1 = as1->segments;
1001 struct assegment *seg2 = as2->segments;
0b2aa3a0 1002 struct aspath *aspath = NULL;
718e3744 1003 struct assegment *asset;
0b2aa3a0 1004 struct assegment *prevseg = NULL;
718e3744 1005
1006 match = 0;
1007 minlen = 0;
1008 aspath = NULL;
1009 asset = NULL;
718e3744 1010
1011 /* First of all check common leading sequence. */
fe69a505 1012 while (seg1 && seg2)
0b2aa3a0 1013 {
718e3744 1014 /* Check segment type. */
1015 if (seg1->type != seg2->type)
1016 break;
1017
1018 /* Minimum segment length. */
1019 minlen = min (seg1->length, seg2->length);
1020
1021 for (match = 0; match < minlen; match++)
fe69a505 1022 if (seg1->as[match] != seg2->as[match])
718e3744 1023 break;
1024
1025 if (match)
1026 {
0b2aa3a0
PJ
1027 struct assegment *seg = assegment_new (seg1->type, 0);
1028
1029 seg = assegment_append_asns (seg, seg1->as, match);
1030
718e3744 1031 if (! aspath)
0b2aa3a0
PJ
1032 {
1033 aspath = aspath_new ();
1034 aspath->segments = seg;
1035 }
1036 else
1037 prevseg->next = seg;
1038
1039 prevseg = seg;
718e3744 1040 }
1041
1042 if (match != minlen || match != seg1->length
1043 || seg1->length != seg2->length)
1044 break;
b5d58c32
DS
1045 /* We are moving on to the next segment to reset match */
1046 else
1047 match = 0;
fe69a505 1048
1049 seg1 = seg1->next;
1050 seg2 = seg2->next;
718e3744 1051 }
1052
1053 if (! aspath)
1054 aspath = aspath_new();
1055
1056 /* Make as-set using rest of all information. */
fe69a505 1057 from = match;
1058 while (seg1)
718e3744 1059 {
fe69a505 1060 for (i = from; i < seg1->length; i++)
1061 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1062
1063 from = 0;
1064 seg1 = seg1->next;
718e3744 1065 }
1066
fe69a505 1067 from = match;
1068 while (seg2)
718e3744 1069 {
fe69a505 1070 for (i = from; i < seg2->length; i++)
1071 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
718e3744 1072
fe69a505 1073 from = 0;
1074 seg2 = seg2->next;
718e3744 1075 }
fe69a505 1076
1077 assegment_normalise (aspath->segments);
1078 aspath_str_update (aspath);
718e3744 1079 return aspath;
1080}
1081
1082/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1083 attribute, check the leftmost AS number in the AS_PATH attribute is
1084 or not the peer's AS number. */
1085int
1086aspath_firstas_check (struct aspath *aspath, as_t asno)
1087{
fe69a505 1088 if ( (aspath == NULL) || (aspath->segments == NULL) )
718e3744 1089 return 0;
fe69a505 1090
1091 if (aspath->segments
1092 && (aspath->segments->type == AS_SEQUENCE)
1093 && (aspath->segments->as[0] == asno ))
718e3744 1094 return 1;
1095
1096 return 0;
1097}
1098
1f742f21 1099/* AS path loop check. If aspath contains asno then return >= 1. */
718e3744 1100int
1101aspath_loop_check (struct aspath *aspath, as_t asno)
1102{
fe69a505 1103 struct assegment *seg;
718e3744 1104 int count = 0;
1105
1f742f21 1106 if ( (aspath == NULL) || (aspath->segments == NULL) )
718e3744 1107 return 0;
fe69a505 1108
1109 seg = aspath->segments;
1110
1111 while (seg)
718e3744 1112 {
1113 int i;
718e3744 1114
fe69a505 1115 for (i = 0; i < seg->length; i++)
1116 if (seg->as[i] == asno)
718e3744 1117 count++;
fe69a505 1118
1119 seg = seg->next;
718e3744 1120 }
1121 return count;
1122}
1123
1124/* When all of AS path is private AS return 1. */
1125int
1126aspath_private_as_check (struct aspath *aspath)
1127{
fe69a505 1128 struct assegment *seg;
5000f21c 1129
fe69a505 1130 if ( !(aspath && aspath->segments) )
718e3744 1131 return 0;
5000f21c 1132
fe69a505 1133 seg = aspath->segments;
718e3744 1134
fe69a505 1135 while (seg)
718e3744 1136 {
1137 int i;
5000f21c 1138
fe69a505 1139 for (i = 0; i < seg->length; i++)
718e3744 1140 {
5000f21c 1141 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
718e3744 1142 return 0;
1143 }
fe69a505 1144 seg = seg->next;
718e3744 1145 }
1146 return 1;
1147}
1148
5000f21c
DS
1149/* Replace all private ASNs with our own ASN */
1150struct aspath *
1151aspath_replace_private_asns (struct aspath *aspath, as_t asn)
1152{
1153 struct aspath *new;
1154 struct assegment *seg;
1155
1156 new = aspath_dup(aspath);
1157 seg = new->segments;
1158
1159 while (seg)
1160 {
1161 int i;
1162
1163 for (i = 0; i < seg->length; i++)
1164 {
1165 if (BGP_AS_IS_PRIVATE(seg->as[i]))
1166 seg->as[i] = asn;
1167 }
1168 seg = seg->next;
1169 }
1170
1171 aspath_str_update(new);
1172 return new;
1173}
1174
1175/* Remove all private ASNs */
1176struct aspath *
1177aspath_remove_private_asns (struct aspath *aspath)
1178{
1179 struct aspath *new;
1180 struct assegment *seg;
1181 struct assegment *new_seg;
1182 struct assegment *last_new_seg;
1183 int i;
1184 int j;
1185 int public = 0;
1186
1187 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
1188
1189 new_seg = NULL;
1190 last_new_seg = NULL;
1191 seg = aspath->segments;
1192 while (seg)
1193 {
1194 public = 0;
1195 for (i = 0; i < seg->length; i++)
1196 {
1197 // ASN is public
1198 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1199 {
1200 public++;
1201 }
1202 }
1203
1204 // The entire segment is private so skip it
1205 if (!public)
1206 {
1207 seg = seg->next;
1208 continue;
1209 }
1210
1211 // The entire segment is public so copy it
1212 else if (public == seg->length)
1213 {
1214 new_seg = assegment_dup (seg);
1215 }
1216
1217 // The segment is a mix of public and private ASNs. Copy as many spots as
1218 // there are public ASNs then come back and fill in only the public ASNs.
1219 else
1220 {
1221 new_seg = assegment_new (seg->type, public);
1222 j = 0;
1223 for (i = 0; i < seg->length; i++)
1224 {
1225 // ASN is public
1226 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1227 {
1228 new_seg->as[j] = seg->as[i];
1229 j++;
1230 }
1231 }
1232 }
1233
1234 // This is the first segment so set the aspath segments pointer to this one
1235 if (!last_new_seg)
1236 new->segments = new_seg;
1237 else
1238 last_new_seg->next = new_seg;
1239
1240 last_new_seg = new_seg;
1241 seg = seg->next;
1242 }
1243
1244 aspath_str_update(new);
1245 return new;
1246}
1247
ca87e1d3
VT
1248/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1249int
1250aspath_confed_check (struct aspath *aspath)
1251{
1252 struct assegment *seg;
1253
1254 if ( !(aspath && aspath->segments) )
1255 return 0;
1256
1257 seg = aspath->segments;
1258
1259 while (seg)
1260 {
1261 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1262 return 1;
1263 seg = seg->next;
1264 }
1265 return 0;
1266}
1267
1268/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1269 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1270int
1271aspath_left_confed_check (struct aspath *aspath)
1272{
1273
1274 if ( !(aspath && aspath->segments) )
1275 return 0;
1276
1277 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1278 || (aspath->segments->type == AS_CONFED_SET) )
1279 return 1;
1280
1281 return 0;
1282}
1283
718e3744 1284/* Merge as1 to as2. as2 should be uninterned aspath. */
94f2b392 1285static struct aspath *
718e3744 1286aspath_merge (struct aspath *as1, struct aspath *as2)
1287{
fe69a505 1288 struct assegment *last, *new;
718e3744 1289
1290 if (! as1 || ! as2)
1291 return NULL;
1292
fe69a505 1293 last = new = assegment_dup_all (as1->segments);
1294
1295 /* find the last valid segment */
1296 while (last && last->next)
1297 last = last->next;
1298
1299 last->next = as2->segments;
1300 as2->segments = new;
1301 aspath_str_update (as2);
718e3744 1302 return as2;
1303}
1304
1305/* Prepend as1 to as2. as2 should be uninterned aspath. */
1306struct aspath *
1307aspath_prepend (struct aspath *as1, struct aspath *as2)
1308{
fe69a505 1309 struct assegment *seg1;
1310 struct assegment *seg2;
718e3744 1311
1312 if (! as1 || ! as2)
1313 return NULL;
fe69a505 1314
1315 seg1 = as1->segments;
1316 seg2 = as2->segments;
1317
1318 /* If as2 is empty, only need to dupe as1's chain onto as2 */
718e3744 1319 if (seg2 == NULL)
1320 {
fe69a505 1321 as2->segments = assegment_dup_all (as1->segments);
1322 aspath_str_update (as2);
718e3744 1323 return as2;
1324 }
fe69a505 1325
1326 /* If as1 is empty AS, no prepending to do. */
718e3744 1327 if (seg1 == NULL)
1328 return as2;
fe69a505 1329
1330 /* find the tail as1's segment chain. */
1331 while (seg1 && seg1->next)
1332 seg1 = seg1->next;
718e3744 1333
736d4408
VT
1334 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1335 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1336 as2 = aspath_delete_confed_seq (as2);
1337
718e3744 1338 /* Compare last segment type of as1 and first segment type of as2. */
1339 if (seg1->type != seg2->type)
1340 return aspath_merge (as1, as2);
1341
1342 if (seg1->type == AS_SEQUENCE)
1343 {
fe69a505 1344 /* We have two chains of segments, as1->segments and seg2,
1345 * and we have to attach them together, merging the attaching
1346 * segments together into one.
1347 *
1348 * 1. dupe as1->segments onto head of as2
1349 * 2. merge seg2's asns onto last segment of this new chain
1350 * 3. attach chain after seg2
1351 */
718e3744 1352
fe69a505 1353 /* dupe as1 onto as2's head */
1354 seg1 = as2->segments = assegment_dup_all (as1->segments);
1355
1356 /* refind the tail of as2, reusing seg1 */
1357 while (seg1 && seg1->next)
1358 seg1 = seg1->next;
1359
1360 /* merge the old head, seg2, into tail, seg1 */
1361 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1362
1363 /* bypass the merged seg2, and attach any chain after it to
1364 * chain descending from as2's head
1365 */
1366 seg1->next = seg2->next;
1367
1368 /* seg2 is now referenceless and useless*/
1369 assegment_free (seg2);
1370
1371 /* we've now prepended as1's segment chain to as2, merging
1372 * the inbetween AS_SEQUENCE of seg2 in the process
1373 */
1374 aspath_str_update (as2);
718e3744 1375 return as2;
1376 }
1377 else
1378 {
1379 /* AS_SET merge code is needed at here. */
1380 return aspath_merge (as1, as2);
1381 }
fe69a505 1382 /* XXX: Ermmm, what if as1 has multiple segments?? */
1383
718e3744 1384 /* Not reached */
1385}
1386
841f7a57
DO
1387/* Iterate over AS_PATH segments and wipe all occurences of the
1388 * listed AS numbers. Hence some segments may lose some or even
1389 * all data on the way, the operation is implemented as a smarter
1390 * version of aspath_dup(), which allocates memory to hold the new
1391 * data, not the original. The new AS path is returned.
1392 */
1393struct aspath *
1394aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1395{
1396 struct assegment * srcseg, * exclseg, * lastseg;
1397 struct aspath * newpath;
1398
1399 newpath = aspath_new();
1400 lastseg = NULL;
1401
1402 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1403 {
1404 unsigned i, y, newlen = 0, done = 0, skip_as;
1405 struct assegment * newseg;
1406
1407 /* Find out, how much ASns are we going to pick from this segment.
1408 * We can't perform filtering right inline, because the size of
1409 * the new segment isn't known at the moment yet.
1410 */
1411 for (i = 0; i < srcseg->length; i++)
1412 {
1413 skip_as = 0;
1414 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1415 for (y = 0; y < exclseg->length; y++)
1416 if (srcseg->as[i] == exclseg->as[y])
1417 {
1418 skip_as = 1;
1419 // There's no sense in testing the rest of exclusion list, bail out.
1420 break;
1421 }
1422 if (!skip_as)
1423 newlen++;
1424 }
1425 /* newlen is now the number of ASns to copy */
1426 if (!newlen)
1427 continue;
1428
1429 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1430 newseg = assegment_new (srcseg->type, newlen);
1431 for (i = 0; i < srcseg->length; i++)
1432 {
1433 skip_as = 0;
1434 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1435 for (y = 0; y < exclseg->length; y++)
1436 if (srcseg->as[i] == exclseg->as[y])
1437 {
1438 skip_as = 1;
1439 break;
1440 }
1441 if (skip_as)
1442 continue;
1443 newseg->as[done++] = srcseg->as[i];
1444 }
1445 /* At his point newlen must be equal to done, and both must be positive. Append
1446 * the filtered segment to the gross result. */
1447 if (!lastseg)
1448 newpath->segments = newseg;
1449 else
1450 lastseg->next = newseg;
1451 lastseg = newseg;
1452 }
1453 aspath_str_update (newpath);
1454 /* We are happy returning even an empty AS_PATH, because the administrator
1455 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1456 * by having a match rule against certain AS_PATH regexps in the route-map index.
1457 */
1458 aspath_free (source);
1459 return newpath;
1460}
1461
718e3744 1462/* Add specified AS to the leftmost of aspath. */
1463static struct aspath *
1464aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1465{
fe69a505 1466 struct assegment *assegment = aspath->segments;
718e3744 1467
1468 /* In case of empty aspath. */
1469 if (assegment == NULL || assegment->length == 0)
1470 {
fe69a505 1471 aspath->segments = assegment_new (type, 1);
1472 aspath->segments->as[0] = asno;
1473
718e3744 1474 if (assegment)
fe69a505 1475 assegment_free (assegment);
718e3744 1476
1477 return aspath;
1478 }
1479
1480 if (assegment->type == type)
fe69a505 1481 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1482 else
718e3744 1483 {
fe69a505 1484 /* create new segment
1485 * push it onto head of aspath's segment chain
1486 */
718e3744 1487 struct assegment *newsegment;
fe69a505 1488
1489 newsegment = assegment_new (type, 1);
1490 newsegment->as[0] = asno;
1491
1492 newsegment->next = assegment;
1493 aspath->segments = newsegment;
718e3744 1494 }
1495
1496 return aspath;
1497}
1498
1499/* Add specified AS to the leftmost of aspath. */
1500struct aspath *
1501aspath_add_seq (struct aspath *aspath, as_t asno)
1502{
1503 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1504}
1505
1506/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1507 as2's leftmost AS is same return 1. */
1508int
ffe11cfb 1509aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
718e3744 1510{
f669f7d2
JBD
1511 const struct assegment *seg1;
1512 const struct assegment *seg2;
718e3744 1513
fe69a505 1514 if (!(aspath1 && aspath2))
1515 return 0;
718e3744 1516
4468119b
DS
1517 /* If both paths are originated in this AS then we do want to compare MED */
1518 if (!aspath_count_hops(aspath1) && !aspath_count_hops(aspath2))
1519 return 1;
1520
fe69a505 1521 seg1 = aspath1->segments;
1522 seg2 = aspath2->segments;
718e3744 1523
fe69a505 1524 /* find first non-confed segments for each */
1525 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1526 || (seg1->type == AS_CONFED_SET)))
1527 seg1 = seg1->next;
718e3744 1528
fe69a505 1529 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1530 || (seg2->type == AS_CONFED_SET)))
1531 seg2 = seg2->next;
718e3744 1532
fe69a505 1533 /* Check as1's */
1534 if (!(seg1 && seg2
1535 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
1536 return 0;
1537
1538 if (seg1->as[0] == seg2->as[0])
718e3744 1539 return 1;
1540
1541 return 0;
1542}
1543
0b2aa3a0
PJ
1544/* Truncate an aspath after a number of hops, and put the hops remaining
1545 * at the front of another aspath. Needed for AS4 compat.
1546 *
1547 * Returned aspath is a /new/ aspath, which should either by free'd or
1548 * interned by the caller, as desired.
1549 */
1550struct aspath *
1551aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1552{
1553 struct assegment *seg, *newseg, *prevseg = NULL;
1554 struct aspath *newpath = NULL, *mergedpath;
1555 int hops, cpasns = 0;
1556
1557 if (!aspath)
1558 return NULL;
1559
1560 seg = aspath->segments;
1561
1562 /* CONFEDs should get reconciled too.. */
1563 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1564 - aspath_count_hops (as4path);
1565
1566 if (hops < 0)
1567 {
1568 if (BGP_DEBUG (as4, AS4))
1569 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1570 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1571 * which is daft behaviour - it contains vital loop-detection
1572 * information which must have been removed from AS_PATH.
1573 */
1574 hops = aspath_count_hops (aspath);
1575 }
1576
1577 if (!hops)
1578 return aspath_dup (as4path);
1579
1580 if ( BGP_DEBUG(as4, AS4))
1581 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1582 aspath->str, as4path->str);
1583
1584 while (seg && hops > 0)
1585 {
1586 switch (seg->type)
1587 {
1588 case AS_SET:
1589 case AS_CONFED_SET:
1590 hops--;
1591 cpasns = seg->length;
1592 break;
1593 case AS_CONFED_SEQUENCE:
1594 /* Should never split a confed-sequence, if hop-count
1595 * suggests we must then something's gone wrong somewhere.
1596 *
1597 * Most important goal is to preserve AS_PATHs prime function
1598 * as loop-detector, so we fudge the numbers so that the entire
1599 * confed-sequence is merged in.
1600 */
1601 if (hops < seg->length)
1602 {
1603 if (BGP_DEBUG (as4, AS4))
1604 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1605 " across 2/4 ASN boundary somewhere, broken..");
1606 hops = seg->length;
1607 }
1608 case AS_SEQUENCE:
1609 cpasns = MIN(seg->length, hops);
1610 hops -= seg->length;
1611 }
1612
1613 assert (cpasns <= seg->length);
1614
1615 newseg = assegment_new (seg->type, 0);
1616 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1617
1618 if (!newpath)
1619 {
1620 newpath = aspath_new ();
1621 newpath->segments = newseg;
1622 }
1623 else
1624 prevseg->next = newseg;
1625
1626 prevseg = newseg;
1627 seg = seg->next;
1628 }
1629
1630 /* We may be able to join some segments here, and we must
1631 * do this because... we want normalised aspaths in out hash
1632 * and we do not want to stumble in aspath_put.
1633 */
1634 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1635 aspath_free (newpath);
1636 mergedpath->segments = assegment_normalise (mergedpath->segments);
1637 aspath_str_update (mergedpath);
1638
1639 if ( BGP_DEBUG(as4, AS4))
1640 zlog_debug ("[AS4] result of synthesizing is %s",
1641 mergedpath->str);
1642
1643 return mergedpath;
1644}
1645
718e3744 1646/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1647 as2's leftmost AS is same return 1. (confederation as-path
1648 only). */
1649int
ffe11cfb 1650aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
718e3744 1651{
fe69a505 1652 if (! (aspath1 && aspath2) )
718e3744 1653 return 0;
fe69a505 1654
ad72740e 1655 if ( !(aspath1->segments && aspath2->segments) )
1656 return 0;
1657
fe69a505 1658 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1659 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
718e3744 1660 return 0;
fe69a505 1661
1662 if (aspath1->segments->as[0] == aspath2->segments->as[0])
718e3744 1663 return 1;
1664
1665 return 0;
1666}
1667
fe69a505 1668/* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1669 * See RFC3065, 6.1 c1 */
718e3744 1670struct aspath *
1671aspath_delete_confed_seq (struct aspath *aspath)
1672{
fe69a505 1673 struct assegment *seg;
718e3744 1674
fe69a505 1675 if (!(aspath && aspath->segments))
718e3744 1676 return aspath;
1677
fe69a505 1678 seg = aspath->segments;
1679
1680 /* "if the first path segment of the AS_PATH is
1681 * of type AS_CONFED_SEQUENCE,"
1682 */
1683 if (aspath->segments->type != AS_CONFED_SEQUENCE)
1684 return aspath;
718e3744 1685
fe69a505 1686 /* "... that segment and any immediately following segments
1687 * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1688 * from the AS_PATH attribute,"
1689 */
1690 while (seg &&
1691 (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
718e3744 1692 {
fe69a505 1693 aspath->segments = seg->next;
1694 assegment_free (seg);
1695 seg = aspath->segments;
718e3744 1696 }
fe69a505 1697 aspath_str_update (aspath);
718e3744 1698 return aspath;
1699}
1700
1701/* Add new AS number to the leftmost part of the aspath as
1702 AS_CONFED_SEQUENCE. */
1703struct aspath*
1704aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1705{
1706 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1707}
1708
1709/* Add new as value to as path structure. */
94f2b392 1710static void
718e3744 1711aspath_as_add (struct aspath *as, as_t asno)
1712{
fe69a505 1713 struct assegment *seg = as->segments;
718e3744 1714
fe69a505 1715 if (!seg)
1716 return;
1717
93c1749c
AS
1718 /* Last segment search procedure. */
1719 while (seg->next)
1720 seg = seg->next;
1721
fe69a505 1722 assegment_append_asns (seg, &asno, 1);
718e3744 1723}
1724
1725/* Add new as segment to the as path. */
94f2b392 1726static void
718e3744 1727aspath_segment_add (struct aspath *as, int type)
1728{
fe69a505 1729 struct assegment *seg = as->segments;
1730 struct assegment *new = assegment_new (type, 0);
718e3744 1731
93c1749c
AS
1732 if (seg)
1733 {
1734 while (seg->next)
1735 seg = seg->next;
1736 seg->next = new;
1737 }
718e3744 1738 else
93c1749c 1739 as->segments = new;
718e3744 1740}
1741
1742struct aspath *
94f2b392 1743aspath_empty (void)
718e3744 1744{
ab005298 1745 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
718e3744 1746}
1747
1748struct aspath *
94f2b392 1749aspath_empty_get (void)
718e3744 1750{
1751 struct aspath *aspath;
1752
1753 aspath = aspath_new ();
f669f7d2 1754 aspath_make_str_count (aspath);
718e3744 1755 return aspath;
1756}
1757
1758unsigned long
fe69a505 1759aspath_count (void)
718e3744 1760{
1761 return ashash->count;
1762}
6b0655a2 1763
718e3744 1764/*
1765 Theoretically, one as path can have:
1766
1767 One BGP packet size should be less than 4096.
1768 One BGP attribute size should be less than 4096 - BGP header size.
1769 One BGP aspath size should be less than 4096 - BGP header size -
1770 BGP mandantry attribute size.
1771*/
1772
1773/* AS path string lexical token enum. */
1774enum as_token
1775{
1776 as_token_asval,
1777 as_token_set_start,
1778 as_token_set_end,
fe69a505 1779 as_token_confed_seq_start,
1780 as_token_confed_seq_end,
1781 as_token_confed_set_start,
1782 as_token_confed_set_end,
718e3744 1783 as_token_unknown
1784};
1785
1786/* Return next token and point for string parse. */
94f2b392 1787static const char *
0b2aa3a0 1788aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
718e3744 1789{
fd79ac91 1790 const char *p = buf;
718e3744 1791
fe69a505 1792 /* Skip seperators (space for sequences, ',' for sets). */
1793 while (isspace ((int) *p) || *p == ',')
718e3744 1794 p++;
1795
1796 /* Check the end of the string and type specify characters
1797 (e.g. {}()). */
1798 switch (*p)
1799 {
1800 case '\0':
1801 return NULL;
718e3744 1802 case '{':
1803 *token = as_token_set_start;
1804 p++;
1805 return p;
718e3744 1806 case '}':
1807 *token = as_token_set_end;
1808 p++;
1809 return p;
718e3744 1810 case '(':
fe69a505 1811 *token = as_token_confed_seq_start;
718e3744 1812 p++;
1813 return p;
718e3744 1814 case ')':
fe69a505 1815 *token = as_token_confed_seq_end;
1816 p++;
1817 return p;
fe69a505 1818 case '[':
1819 *token = as_token_confed_set_start;
1820 p++;
1821 return p;
fe69a505 1822 case ']':
1823 *token = as_token_confed_set_end;
718e3744 1824 p++;
1825 return p;
718e3744 1826 }
1827
1828 /* Check actual AS value. */
1829 if (isdigit ((int) *p))
1830 {
10819ece 1831 as_t asval;
0b2aa3a0 1832
718e3744 1833 *token = as_token_asval;
1834 asval = (*p - '0');
1835 p++;
0b2aa3a0 1836
718e3744 1837 while (isdigit ((int) *p))
0b2aa3a0
PJ
1838 {
1839 asval *= 10;
1840 asval += (*p - '0');
1841 p++;
1842 }
718e3744 1843 *asno = asval;
1844 return p;
1845 }
1846
1847 /* There is no match then return unknown token. */
1848 *token = as_token_unknown;
1849 return p++;
1850}
1851
1852struct aspath *
fd79ac91 1853aspath_str2aspath (const char *str)
718e3744 1854{
3fff6ffc 1855 enum as_token token = as_token_unknown;
718e3744 1856 u_short as_type;
0b2aa3a0 1857 u_long asno = 0;
718e3744 1858 struct aspath *aspath;
1859 int needtype;
1860
1861 aspath = aspath_new ();
1862
1863 /* We start default type as AS_SEQUENCE. */
1864 as_type = AS_SEQUENCE;
1865 needtype = 1;
1866
1867 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1868 {
1869 switch (token)
1870 {
1871 case as_token_asval:
1872 if (needtype)
1873 {
1874 aspath_segment_add (aspath, as_type);
1875 needtype = 0;
1876 }
1877 aspath_as_add (aspath, asno);
1878 break;
1879 case as_token_set_start:
1880 as_type = AS_SET;
1881 aspath_segment_add (aspath, as_type);
1882 needtype = 0;
1883 break;
1884 case as_token_set_end:
1885 as_type = AS_SEQUENCE;
1886 needtype = 1;
1887 break;
fe69a505 1888 case as_token_confed_seq_start:
718e3744 1889 as_type = AS_CONFED_SEQUENCE;
1890 aspath_segment_add (aspath, as_type);
1891 needtype = 0;
1892 break;
fe69a505 1893 case as_token_confed_seq_end:
1894 as_type = AS_SEQUENCE;
1895 needtype = 1;
1896 break;
1897 case as_token_confed_set_start:
1898 as_type = AS_CONFED_SET;
1899 aspath_segment_add (aspath, as_type);
1900 needtype = 0;
1901 break;
1902 case as_token_confed_set_end:
718e3744 1903 as_type = AS_SEQUENCE;
1904 needtype = 1;
1905 break;
1906 case as_token_unknown:
1907 default:
fe69a505 1908 aspath_free (aspath);
718e3744 1909 return NULL;
718e3744 1910 }
1911 }
1912
f669f7d2 1913 aspath_make_str_count (aspath);
718e3744 1914
1915 return aspath;
1916}
6b0655a2 1917
718e3744 1918/* Make hash value by raw aspath data. */
1919unsigned int
923de654 1920aspath_key_make (void *p)
718e3744 1921{
f669f7d2 1922 struct aspath *aspath = (struct aspath *) p;
718e3744 1923 unsigned int key = 0;
718e3744 1924
0b2aa3a0
PJ
1925 if (!aspath->str)
1926 aspath_str_update (aspath);
f669f7d2
JBD
1927
1928 key = jhash (aspath->str, aspath->str_len, 2334325);
718e3744 1929
1930 return key;
1931}
1932
1933/* If two aspath have same value then return 1 else return 0 */
96450faf 1934int
ffe11cfb 1935aspath_cmp (const void *arg1, const void *arg2)
718e3744 1936{
aea339f7
DO
1937 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1938 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
fe69a505 1939
1940 while (seg1 || seg2)
1941 {
1942 int i;
1943 if ((!seg1 && seg2) || (seg1 && !seg2))
1944 return 0;
1945 if (seg1->type != seg2->type)
1946 return 0;
1947 if (seg1->length != seg2->length)
1948 return 0;
1949 for (i = 0; i < seg1->length; i++)
1950 if (seg1->as[i] != seg2->as[i])
1951 return 0;
1952 seg1 = seg1->next;
1953 seg2 = seg2->next;
1954 }
1955 return 1;
718e3744 1956}
1957
1958/* AS path hash initialize. */
1959void
94f2b392 1960aspath_init (void)
718e3744 1961{
90645f55 1962 ashash = hash_create_size (32768, aspath_key_make, aspath_cmp);
718e3744 1963}
8fdc32ab 1964
1965void
1966aspath_finish (void)
1967{
1968 hash_free (ashash);
228da428 1969 ashash = NULL;
8fdc32ab 1970
1971 if (snmp_stream)
1972 stream_free (snmp_stream);
1973}
6b0655a2 1974
718e3744 1975/* return and as path value */
1976const char *
1977aspath_print (struct aspath *as)
1978{
fe69a505 1979 return (as ? as->str : NULL);
718e3744 1980}
1981
1982/* Printing functions */
841f7a57
DO
1983/* Feed the AS_PATH to the vty; the suffix string follows it only in case
1984 * AS_PATH wasn't empty.
1985 */
718e3744 1986void
841f7a57 1987aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
718e3744 1988{
b2518c1e
PJ
1989 assert (format);
1990 vty_out (vty, format, as->str);
f669f7d2 1991 if (as->str_len && strlen (suffix))
841f7a57 1992 vty_out (vty, "%s", suffix);
718e3744 1993}
1994
94f2b392 1995static void
718e3744 1996aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1997{
1998 struct aspath *as;
1999
2000 as = (struct aspath *) backet->data;
2001
efa9f830 2002 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
718e3744 2003 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
2004}
2005
2006/* Print all aspath and hash information. This function is used from
2007 `show ip bgp paths' command. */
2008void
2009aspath_print_all_vty (struct vty *vty)
2010{
2011 hash_iterate (ashash,
2012 (void (*) (struct hash_backet *, void *))
2013 aspath_show_all_iterator,
2014 vty);
2015}