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