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