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