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