]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_aspath.c
BGP: Correctly display local-as for peer-group member
[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;
1048 int minlen;
1049 int match;
fe69a505 1050 int from;
1051 struct assegment *seg1 = as1->segments;
1052 struct assegment *seg2 = as2->segments;
0b2aa3a0 1053 struct aspath *aspath = NULL;
718e3744 1054 struct assegment *asset;
0b2aa3a0 1055 struct assegment *prevseg = NULL;
718e3744 1056
1057 match = 0;
1058 minlen = 0;
1059 aspath = NULL;
1060 asset = NULL;
718e3744 1061
1062 /* First of all check common leading sequence. */
fe69a505 1063 while (seg1 && seg2)
0b2aa3a0 1064 {
718e3744 1065 /* Check segment type. */
1066 if (seg1->type != seg2->type)
1067 break;
1068
1069 /* Minimum segment length. */
1070 minlen = min (seg1->length, seg2->length);
1071
1072 for (match = 0; match < minlen; match++)
fe69a505 1073 if (seg1->as[match] != seg2->as[match])
718e3744 1074 break;
1075
1076 if (match)
1077 {
0b2aa3a0
PJ
1078 struct assegment *seg = assegment_new (seg1->type, 0);
1079
1080 seg = assegment_append_asns (seg, seg1->as, match);
1081
718e3744 1082 if (! aspath)
0b2aa3a0
PJ
1083 {
1084 aspath = aspath_new ();
1085 aspath->segments = seg;
1086 }
1087 else
1088 prevseg->next = seg;
1089
1090 prevseg = seg;
718e3744 1091 }
1092
1093 if (match != minlen || match != seg1->length
1094 || seg1->length != seg2->length)
1095 break;
b5d58c32
DS
1096 /* We are moving on to the next segment to reset match */
1097 else
1098 match = 0;
fe69a505 1099
1100 seg1 = seg1->next;
1101 seg2 = seg2->next;
718e3744 1102 }
1103
1104 if (! aspath)
1105 aspath = aspath_new();
1106
1107 /* Make as-set using rest of all information. */
fe69a505 1108 from = match;
1109 while (seg1)
718e3744 1110 {
fe69a505 1111 for (i = from; i < seg1->length; i++)
1112 asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1113
1114 from = 0;
1115 seg1 = seg1->next;
718e3744 1116 }
1117
fe69a505 1118 from = match;
1119 while (seg2)
718e3744 1120 {
fe69a505 1121 for (i = from; i < seg2->length; i++)
1122 asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
718e3744 1123
fe69a505 1124 from = 0;
1125 seg2 = seg2->next;
718e3744 1126 }
fe69a505 1127
1128 assegment_normalise (aspath->segments);
1129 aspath_str_update (aspath);
718e3744 1130 return aspath;
1131}
1132
1133/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1134 attribute, check the leftmost AS number in the AS_PATH attribute is
1135 or not the peer's AS number. */
1136int
1137aspath_firstas_check (struct aspath *aspath, as_t asno)
1138{
fe69a505 1139 if ( (aspath == NULL) || (aspath->segments == NULL) )
718e3744 1140 return 0;
fe69a505 1141
1142 if (aspath->segments
1143 && (aspath->segments->type == AS_SEQUENCE)
1144 && (aspath->segments->as[0] == asno ))
718e3744 1145 return 1;
1146
1147 return 0;
1148}
1149
1f742f21 1150/* AS path loop check. If aspath contains asno then return >= 1. */
718e3744 1151int
1152aspath_loop_check (struct aspath *aspath, as_t asno)
1153{
fe69a505 1154 struct assegment *seg;
718e3744 1155 int count = 0;
1156
1f742f21 1157 if ( (aspath == NULL) || (aspath->segments == NULL) )
718e3744 1158 return 0;
fe69a505 1159
1160 seg = aspath->segments;
1161
1162 while (seg)
718e3744 1163 {
1164 int i;
718e3744 1165
fe69a505 1166 for (i = 0; i < seg->length; i++)
1167 if (seg->as[i] == asno)
718e3744 1168 count++;
fe69a505 1169
1170 seg = seg->next;
718e3744 1171 }
1172 return count;
1173}
1174
1175/* When all of AS path is private AS return 1. */
1176int
1177aspath_private_as_check (struct aspath *aspath)
1178{
fe69a505 1179 struct assegment *seg;
5000f21c 1180
fe69a505 1181 if ( !(aspath && aspath->segments) )
718e3744 1182 return 0;
5000f21c 1183
fe69a505 1184 seg = aspath->segments;
718e3744 1185
fe69a505 1186 while (seg)
718e3744 1187 {
1188 int i;
5000f21c 1189
fe69a505 1190 for (i = 0; i < seg->length; i++)
718e3744 1191 {
5000f21c 1192 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
718e3744 1193 return 0;
1194 }
fe69a505 1195 seg = seg->next;
718e3744 1196 }
1197 return 1;
1198}
1199
c7122e14
DS
1200/* Return True if the entire ASPATH consist of the specified ASN */
1201int
1202aspath_single_asn_check (struct aspath *aspath, as_t asn)
1203{
1204 struct assegment *seg;
1205
1206 if ( !(aspath && aspath->segments) )
1207 return 0;
1208
1209 seg = aspath->segments;
1210
1211 while (seg)
1212 {
1213 int i;
1214
1215 for (i = 0; i < seg->length; i++)
1216 {
1217 if (seg->as[i] != asn)
1218 return 0;
1219 }
1220 seg = seg->next;
1221 }
1222 return 1;
1223}
1224
1225/* Replace all instances of the target ASN with our own ASN */
1226struct aspath *
1227aspath_replace_specific_asn (struct aspath *aspath, as_t target_asn,
1228 as_t our_asn)
1229{
1230 struct aspath *new;
1231 struct assegment *seg;
1232
1233 new = aspath_dup(aspath);
1234 seg = new->segments;
1235
1236 while (seg)
1237 {
1238 int i;
1239
1240 for (i = 0; i < seg->length; i++)
1241 {
1242 if (seg->as[i] == target_asn)
1243 seg->as[i] = our_asn;
1244 }
1245 seg = seg->next;
1246 }
1247
1248 aspath_str_update(new);
1249 return new;
1250}
1251
5000f21c
DS
1252/* Replace all private ASNs with our own ASN */
1253struct aspath *
1254aspath_replace_private_asns (struct aspath *aspath, as_t asn)
1255{
1256 struct aspath *new;
1257 struct assegment *seg;
1258
1259 new = aspath_dup(aspath);
1260 seg = new->segments;
1261
1262 while (seg)
1263 {
1264 int i;
1265
1266 for (i = 0; i < seg->length; i++)
1267 {
1268 if (BGP_AS_IS_PRIVATE(seg->as[i]))
1269 seg->as[i] = asn;
1270 }
1271 seg = seg->next;
1272 }
1273
1274 aspath_str_update(new);
1275 return new;
1276}
1277
1278/* Remove all private ASNs */
1279struct aspath *
1280aspath_remove_private_asns (struct aspath *aspath)
1281{
1282 struct aspath *new;
1283 struct assegment *seg;
1284 struct assegment *new_seg;
1285 struct assegment *last_new_seg;
1286 int i;
1287 int j;
1288 int public = 0;
1289
1290 new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
1291
f1aa5d8a 1292 new->json = NULL;
5000f21c
DS
1293 new_seg = NULL;
1294 last_new_seg = NULL;
1295 seg = aspath->segments;
1296 while (seg)
1297 {
1298 public = 0;
1299 for (i = 0; i < seg->length; i++)
1300 {
1301 // ASN is public
1302 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1303 {
1304 public++;
1305 }
1306 }
1307
1308 // The entire segment is private so skip it
1309 if (!public)
1310 {
1311 seg = seg->next;
1312 continue;
1313 }
1314
1315 // The entire segment is public so copy it
1316 else if (public == seg->length)
1317 {
1318 new_seg = assegment_dup (seg);
1319 }
1320
1321 // The segment is a mix of public and private ASNs. Copy as many spots as
1322 // there are public ASNs then come back and fill in only the public ASNs.
1323 else
1324 {
1325 new_seg = assegment_new (seg->type, public);
1326 j = 0;
1327 for (i = 0; i < seg->length; i++)
1328 {
1329 // ASN is public
1330 if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1331 {
1332 new_seg->as[j] = seg->as[i];
1333 j++;
1334 }
1335 }
1336 }
1337
1338 // This is the first segment so set the aspath segments pointer to this one
1339 if (!last_new_seg)
1340 new->segments = new_seg;
1341 else
1342 last_new_seg->next = new_seg;
1343
1344 last_new_seg = new_seg;
1345 seg = seg->next;
1346 }
1347
1348 aspath_str_update(new);
1349 return new;
1350}
1351
ca87e1d3
VT
1352/* AS path confed check. If aspath contains confed set or sequence then return 1. */
1353int
1354aspath_confed_check (struct aspath *aspath)
1355{
1356 struct assegment *seg;
1357
1358 if ( !(aspath && aspath->segments) )
1359 return 0;
1360
1361 seg = aspath->segments;
1362
1363 while (seg)
1364 {
1365 if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1366 return 1;
1367 seg = seg->next;
1368 }
1369 return 0;
1370}
1371
1372/* Leftmost AS path segment confed check. If leftmost AS segment is of type
1373 AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1374int
1375aspath_left_confed_check (struct aspath *aspath)
1376{
1377
1378 if ( !(aspath && aspath->segments) )
1379 return 0;
1380
1381 if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1382 || (aspath->segments->type == AS_CONFED_SET) )
1383 return 1;
1384
1385 return 0;
1386}
1387
718e3744 1388/* Merge as1 to as2. as2 should be uninterned aspath. */
94f2b392 1389static struct aspath *
718e3744 1390aspath_merge (struct aspath *as1, struct aspath *as2)
1391{
fe69a505 1392 struct assegment *last, *new;
718e3744 1393
1394 if (! as1 || ! as2)
1395 return NULL;
1396
fe69a505 1397 last = new = assegment_dup_all (as1->segments);
1398
1399 /* find the last valid segment */
1400 while (last && last->next)
1401 last = last->next;
1402
1403 last->next = as2->segments;
1404 as2->segments = new;
1405 aspath_str_update (as2);
718e3744 1406 return as2;
1407}
1408
1409/* Prepend as1 to as2. as2 should be uninterned aspath. */
1410struct aspath *
1411aspath_prepend (struct aspath *as1, struct aspath *as2)
1412{
fe69a505 1413 struct assegment *seg1;
1414 struct assegment *seg2;
718e3744 1415
1416 if (! as1 || ! as2)
1417 return NULL;
fe69a505 1418
1419 seg1 = as1->segments;
1420 seg2 = as2->segments;
1421
1422 /* If as2 is empty, only need to dupe as1's chain onto as2 */
718e3744 1423 if (seg2 == NULL)
1424 {
fe69a505 1425 as2->segments = assegment_dup_all (as1->segments);
1426 aspath_str_update (as2);
718e3744 1427 return as2;
1428 }
fe69a505 1429
1430 /* If as1 is empty AS, no prepending to do. */
718e3744 1431 if (seg1 == NULL)
1432 return as2;
fe69a505 1433
1434 /* find the tail as1's segment chain. */
1435 while (seg1 && seg1->next)
1436 seg1 = seg1->next;
718e3744 1437
736d4408
VT
1438 /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1439 if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1440 as2 = aspath_delete_confed_seq (as2);
1441
718e3744 1442 /* Compare last segment type of as1 and first segment type of as2. */
1443 if (seg1->type != seg2->type)
1444 return aspath_merge (as1, as2);
1445
1446 if (seg1->type == AS_SEQUENCE)
1447 {
fe69a505 1448 /* We have two chains of segments, as1->segments and seg2,
1449 * and we have to attach them together, merging the attaching
1450 * segments together into one.
1451 *
1452 * 1. dupe as1->segments onto head of as2
1453 * 2. merge seg2's asns onto last segment of this new chain
1454 * 3. attach chain after seg2
1455 */
718e3744 1456
fe69a505 1457 /* dupe as1 onto as2's head */
1458 seg1 = as2->segments = assegment_dup_all (as1->segments);
1459
1460 /* refind the tail of as2, reusing seg1 */
1461 while (seg1 && seg1->next)
1462 seg1 = seg1->next;
1463
1464 /* merge the old head, seg2, into tail, seg1 */
1465 seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1466
1467 /* bypass the merged seg2, and attach any chain after it to
1468 * chain descending from as2's head
1469 */
1470 seg1->next = seg2->next;
1471
1472 /* seg2 is now referenceless and useless*/
1473 assegment_free (seg2);
1474
1475 /* we've now prepended as1's segment chain to as2, merging
1476 * the inbetween AS_SEQUENCE of seg2 in the process
1477 */
1478 aspath_str_update (as2);
718e3744 1479 return as2;
1480 }
1481 else
1482 {
1483 /* AS_SET merge code is needed at here. */
1484 return aspath_merge (as1, as2);
1485 }
fe69a505 1486 /* XXX: Ermmm, what if as1 has multiple segments?? */
1487
718e3744 1488 /* Not reached */
1489}
1490
841f7a57
DO
1491/* Iterate over AS_PATH segments and wipe all occurences of the
1492 * listed AS numbers. Hence some segments may lose some or even
1493 * all data on the way, the operation is implemented as a smarter
1494 * version of aspath_dup(), which allocates memory to hold the new
1495 * data, not the original. The new AS path is returned.
1496 */
1497struct aspath *
1498aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1499{
1500 struct assegment * srcseg, * exclseg, * lastseg;
1501 struct aspath * newpath;
1502
1503 newpath = aspath_new();
1504 lastseg = NULL;
1505
1506 for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1507 {
1508 unsigned i, y, newlen = 0, done = 0, skip_as;
1509 struct assegment * newseg;
1510
1511 /* Find out, how much ASns are we going to pick from this segment.
1512 * We can't perform filtering right inline, because the size of
1513 * the new segment isn't known at the moment yet.
1514 */
1515 for (i = 0; i < srcseg->length; i++)
1516 {
1517 skip_as = 0;
1518 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1519 for (y = 0; y < exclseg->length; y++)
1520 if (srcseg->as[i] == exclseg->as[y])
1521 {
1522 skip_as = 1;
1523 // There's no sense in testing the rest of exclusion list, bail out.
1524 break;
1525 }
1526 if (!skip_as)
1527 newlen++;
1528 }
1529 /* newlen is now the number of ASns to copy */
1530 if (!newlen)
1531 continue;
1532
1533 /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1534 newseg = assegment_new (srcseg->type, newlen);
1535 for (i = 0; i < srcseg->length; i++)
1536 {
1537 skip_as = 0;
1538 for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1539 for (y = 0; y < exclseg->length; y++)
1540 if (srcseg->as[i] == exclseg->as[y])
1541 {
1542 skip_as = 1;
1543 break;
1544 }
1545 if (skip_as)
1546 continue;
1547 newseg->as[done++] = srcseg->as[i];
1548 }
1549 /* At his point newlen must be equal to done, and both must be positive. Append
1550 * the filtered segment to the gross result. */
1551 if (!lastseg)
1552 newpath->segments = newseg;
1553 else
1554 lastseg->next = newseg;
1555 lastseg = newseg;
1556 }
1557 aspath_str_update (newpath);
1558 /* We are happy returning even an empty AS_PATH, because the administrator
1559 * might expect this very behaviour. There's a mean to avoid this, if necessary,
1560 * by having a match rule against certain AS_PATH regexps in the route-map index.
1561 */
1562 aspath_free (source);
1563 return newpath;
1564}
1565
718e3744 1566/* Add specified AS to the leftmost of aspath. */
1567static struct aspath *
1568aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1569{
fe69a505 1570 struct assegment *assegment = aspath->segments;
718e3744 1571
1572 /* In case of empty aspath. */
1573 if (assegment == NULL || assegment->length == 0)
1574 {
fe69a505 1575 aspath->segments = assegment_new (type, 1);
1576 aspath->segments->as[0] = asno;
1577
718e3744 1578 if (assegment)
fe69a505 1579 assegment_free (assegment);
718e3744 1580
1581 return aspath;
1582 }
1583
1584 if (assegment->type == type)
fe69a505 1585 aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1586 else
718e3744 1587 {
fe69a505 1588 /* create new segment
1589 * push it onto head of aspath's segment chain
1590 */
718e3744 1591 struct assegment *newsegment;
fe69a505 1592
1593 newsegment = assegment_new (type, 1);
1594 newsegment->as[0] = asno;
1595
1596 newsegment->next = assegment;
1597 aspath->segments = newsegment;
718e3744 1598 }
1599
1600 return aspath;
1601}
1602
1603/* Add specified AS to the leftmost of aspath. */
1604struct aspath *
1605aspath_add_seq (struct aspath *aspath, as_t asno)
1606{
1607 return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1608}
1609
1610/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1611 as2's leftmost AS is same return 1. */
1612int
ffe11cfb 1613aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
718e3744 1614{
f669f7d2
JBD
1615 const struct assegment *seg1;
1616 const struct assegment *seg2;
718e3744 1617
fe69a505 1618 if (!(aspath1 && aspath2))
1619 return 0;
718e3744 1620
fe69a505 1621 seg1 = aspath1->segments;
1622 seg2 = aspath2->segments;
718e3744 1623
2a3fa5d7
DS
1624 /* If both paths are originated in this AS then we do want to compare MED */
1625 if (!seg1 && !seg2)
1626 return 1;
1627
fe69a505 1628 /* find first non-confed segments for each */
1629 while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1630 || (seg1->type == AS_CONFED_SET)))
1631 seg1 = seg1->next;
718e3744 1632
fe69a505 1633 while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1634 || (seg2->type == AS_CONFED_SET)))
1635 seg2 = seg2->next;
718e3744 1636
fe69a505 1637 /* Check as1's */
1638 if (!(seg1 && seg2
1639 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
1640 return 0;
1641
1642 if (seg1->as[0] == seg2->as[0])
718e3744 1643 return 1;
1644
1645 return 0;
1646}
1647
0b2aa3a0
PJ
1648/* Truncate an aspath after a number of hops, and put the hops remaining
1649 * at the front of another aspath. Needed for AS4 compat.
1650 *
1651 * Returned aspath is a /new/ aspath, which should either by free'd or
1652 * interned by the caller, as desired.
1653 */
1654struct aspath *
1655aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1656{
1657 struct assegment *seg, *newseg, *prevseg = NULL;
1658 struct aspath *newpath = NULL, *mergedpath;
1659 int hops, cpasns = 0;
1660
1661 if (!aspath)
1662 return NULL;
1663
1664 seg = aspath->segments;
1665
1666 /* CONFEDs should get reconciled too.. */
1667 hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1668 - aspath_count_hops (as4path);
1669
1670 if (hops < 0)
1671 {
1672 if (BGP_DEBUG (as4, AS4))
1673 zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1674 /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1675 * which is daft behaviour - it contains vital loop-detection
1676 * information which must have been removed from AS_PATH.
1677 */
1678 hops = aspath_count_hops (aspath);
1679 }
1680
1681 if (!hops)
f1aa5d8a
DS
1682 {
1683 newpath = aspath_dup (as4path);
1684 aspath_str_update(newpath);
1685 return newpath;
1686 }
0b2aa3a0
PJ
1687
1688 if ( BGP_DEBUG(as4, AS4))
1689 zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1690 aspath->str, as4path->str);
1691
1692 while (seg && hops > 0)
1693 {
1694 switch (seg->type)
1695 {
1696 case AS_SET:
1697 case AS_CONFED_SET:
1698 hops--;
1699 cpasns = seg->length;
1700 break;
1701 case AS_CONFED_SEQUENCE:
1702 /* Should never split a confed-sequence, if hop-count
1703 * suggests we must then something's gone wrong somewhere.
1704 *
1705 * Most important goal is to preserve AS_PATHs prime function
1706 * as loop-detector, so we fudge the numbers so that the entire
1707 * confed-sequence is merged in.
1708 */
1709 if (hops < seg->length)
1710 {
1711 if (BGP_DEBUG (as4, AS4))
1712 zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1713 " across 2/4 ASN boundary somewhere, broken..");
1714 hops = seg->length;
1715 }
1716 case AS_SEQUENCE:
1717 cpasns = MIN(seg->length, hops);
1718 hops -= seg->length;
1719 }
1720
1721 assert (cpasns <= seg->length);
1722
1723 newseg = assegment_new (seg->type, 0);
1724 newseg = assegment_append_asns (newseg, seg->as, cpasns);
1725
1726 if (!newpath)
1727 {
1728 newpath = aspath_new ();
1729 newpath->segments = newseg;
1730 }
1731 else
1732 prevseg->next = newseg;
1733
1734 prevseg = newseg;
1735 seg = seg->next;
1736 }
1737
1738 /* We may be able to join some segments here, and we must
1739 * do this because... we want normalised aspaths in out hash
1740 * and we do not want to stumble in aspath_put.
1741 */
1742 mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1743 aspath_free (newpath);
1744 mergedpath->segments = assegment_normalise (mergedpath->segments);
1745 aspath_str_update (mergedpath);
1746
1747 if ( BGP_DEBUG(as4, AS4))
1748 zlog_debug ("[AS4] result of synthesizing is %s",
1749 mergedpath->str);
1750
1751 return mergedpath;
1752}
1753
718e3744 1754/* Compare leftmost AS value for MED check. If as1's leftmost AS and
1755 as2's leftmost AS is same return 1. (confederation as-path
1756 only). */
1757int
ffe11cfb 1758aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
718e3744 1759{
fe69a505 1760 if (! (aspath1 && aspath2) )
718e3744 1761 return 0;
fe69a505 1762
ad72740e 1763 if ( !(aspath1->segments && aspath2->segments) )
1764 return 0;
1765
fe69a505 1766 if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1767 || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
718e3744 1768 return 0;
fe69a505 1769
1770 if (aspath1->segments->as[0] == aspath2->segments->as[0])
718e3744 1771 return 1;
1772
1773 return 0;
1774}
1775
66b199b2
DS
1776/* Delete all AS_CONFED_SEQUENCE/SET segments from aspath.
1777 * RFC 5065 section 4.1.c.1
1778 *
1779 * 1) if any path segments of the AS_PATH are of the type
1780 * AS_CONFED_SEQUENCE or AS_CONFED_SET, those segments MUST be
1781 * removed from the AS_PATH attribute, leaving the sanitized
1782 * AS_PATH attribute to be operated on by steps 2, 3 or 4.
1783 */
718e3744 1784struct aspath *
1785aspath_delete_confed_seq (struct aspath *aspath)
1786{
66b199b2
DS
1787 struct assegment *seg, *prev, *next;
1788 char removed_confed_segment;
718e3744 1789
fe69a505 1790 if (!(aspath && aspath->segments))
718e3744 1791 return aspath;
1792
fe69a505 1793 seg = aspath->segments;
66b199b2
DS
1794 removed_confed_segment = 0;
1795 next = NULL;
1796 prev = NULL;
fe69a505 1797
66b199b2 1798 while (seg)
718e3744 1799 {
66b199b2
DS
1800 next = seg->next;
1801
1802 if (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET)
1803 {
1804 /* This is the first segment in the aspath */
1805 if (aspath->segments == seg)
1806 aspath->segments = seg->next;
1807 else
1808 prev->next = seg->next;
1809
1810 assegment_free (seg);
1811 removed_confed_segment = 1;
1812 }
1813 else
1814 prev = seg;
1815
1816 seg = next;
718e3744 1817 }
66b199b2
DS
1818
1819 if (removed_confed_segment)
1820 aspath_str_update (aspath);
1821
718e3744 1822 return aspath;
1823}
1824
1825/* Add new AS number to the leftmost part of the aspath as
1826 AS_CONFED_SEQUENCE. */
1827struct aspath*
1828aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1829{
1830 return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1831}
1832
1833/* Add new as value to as path structure. */
94f2b392 1834static void
718e3744 1835aspath_as_add (struct aspath *as, as_t asno)
1836{
fe69a505 1837 struct assegment *seg = as->segments;
718e3744 1838
fe69a505 1839 if (!seg)
1840 return;
1841
93c1749c
AS
1842 /* Last segment search procedure. */
1843 while (seg->next)
1844 seg = seg->next;
1845
fe69a505 1846 assegment_append_asns (seg, &asno, 1);
718e3744 1847}
1848
1849/* Add new as segment to the as path. */
94f2b392 1850static void
718e3744 1851aspath_segment_add (struct aspath *as, int type)
1852{
fe69a505 1853 struct assegment *seg = as->segments;
1854 struct assegment *new = assegment_new (type, 0);
718e3744 1855
93c1749c
AS
1856 if (seg)
1857 {
1858 while (seg->next)
1859 seg = seg->next;
1860 seg->next = new;
1861 }
718e3744 1862 else
93c1749c 1863 as->segments = new;
718e3744 1864}
1865
1866struct aspath *
94f2b392 1867aspath_empty (void)
718e3744 1868{
ab005298 1869 return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
718e3744 1870}
1871
1872struct aspath *
94f2b392 1873aspath_empty_get (void)
718e3744 1874{
1875 struct aspath *aspath;
1876
1877 aspath = aspath_new ();
f669f7d2 1878 aspath_make_str_count (aspath);
718e3744 1879 return aspath;
1880}
1881
1882unsigned long
fe69a505 1883aspath_count (void)
718e3744 1884{
1885 return ashash->count;
1886}
6b0655a2 1887
718e3744 1888/*
1889 Theoretically, one as path can have:
1890
1891 One BGP packet size should be less than 4096.
1892 One BGP attribute size should be less than 4096 - BGP header size.
1893 One BGP aspath size should be less than 4096 - BGP header size -
1894 BGP mandantry attribute size.
1895*/
1896
1897/* AS path string lexical token enum. */
1898enum as_token
1899{
1900 as_token_asval,
1901 as_token_set_start,
1902 as_token_set_end,
fe69a505 1903 as_token_confed_seq_start,
1904 as_token_confed_seq_end,
1905 as_token_confed_set_start,
1906 as_token_confed_set_end,
718e3744 1907 as_token_unknown
1908};
1909
1910/* Return next token and point for string parse. */
94f2b392 1911static const char *
0b2aa3a0 1912aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
718e3744 1913{
fd79ac91 1914 const char *p = buf;
718e3744 1915
fe69a505 1916 /* Skip seperators (space for sequences, ',' for sets). */
1917 while (isspace ((int) *p) || *p == ',')
718e3744 1918 p++;
1919
1920 /* Check the end of the string and type specify characters
1921 (e.g. {}()). */
1922 switch (*p)
1923 {
1924 case '\0':
1925 return NULL;
718e3744 1926 case '{':
1927 *token = as_token_set_start;
1928 p++;
1929 return p;
718e3744 1930 case '}':
1931 *token = as_token_set_end;
1932 p++;
1933 return p;
718e3744 1934 case '(':
fe69a505 1935 *token = as_token_confed_seq_start;
718e3744 1936 p++;
1937 return p;
718e3744 1938 case ')':
fe69a505 1939 *token = as_token_confed_seq_end;
1940 p++;
1941 return p;
fe69a505 1942 case '[':
1943 *token = as_token_confed_set_start;
1944 p++;
1945 return p;
fe69a505 1946 case ']':
1947 *token = as_token_confed_set_end;
718e3744 1948 p++;
1949 return p;
718e3744 1950 }
1951
1952 /* Check actual AS value. */
1953 if (isdigit ((int) *p))
1954 {
10819ece 1955 as_t asval;
0b2aa3a0 1956
718e3744 1957 *token = as_token_asval;
1958 asval = (*p - '0');
1959 p++;
0b2aa3a0 1960
718e3744 1961 while (isdigit ((int) *p))
0b2aa3a0
PJ
1962 {
1963 asval *= 10;
1964 asval += (*p - '0');
1965 p++;
1966 }
718e3744 1967 *asno = asval;
1968 return p;
1969 }
1970
1971 /* There is no match then return unknown token. */
1972 *token = as_token_unknown;
1973 return p++;
1974}
1975
1976struct aspath *
fd79ac91 1977aspath_str2aspath (const char *str)
718e3744 1978{
3fff6ffc 1979 enum as_token token = as_token_unknown;
718e3744 1980 u_short as_type;
0b2aa3a0 1981 u_long asno = 0;
718e3744 1982 struct aspath *aspath;
1983 int needtype;
1984
1985 aspath = aspath_new ();
1986
1987 /* We start default type as AS_SEQUENCE. */
1988 as_type = AS_SEQUENCE;
1989 needtype = 1;
1990
1991 while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1992 {
1993 switch (token)
1994 {
1995 case as_token_asval:
1996 if (needtype)
1997 {
1998 aspath_segment_add (aspath, as_type);
1999 needtype = 0;
2000 }
2001 aspath_as_add (aspath, asno);
2002 break;
2003 case as_token_set_start:
2004 as_type = AS_SET;
2005 aspath_segment_add (aspath, as_type);
2006 needtype = 0;
2007 break;
2008 case as_token_set_end:
2009 as_type = AS_SEQUENCE;
2010 needtype = 1;
2011 break;
fe69a505 2012 case as_token_confed_seq_start:
718e3744 2013 as_type = AS_CONFED_SEQUENCE;
2014 aspath_segment_add (aspath, as_type);
2015 needtype = 0;
2016 break;
fe69a505 2017 case as_token_confed_seq_end:
2018 as_type = AS_SEQUENCE;
2019 needtype = 1;
2020 break;
2021 case as_token_confed_set_start:
2022 as_type = AS_CONFED_SET;
2023 aspath_segment_add (aspath, as_type);
2024 needtype = 0;
2025 break;
2026 case as_token_confed_set_end:
718e3744 2027 as_type = AS_SEQUENCE;
2028 needtype = 1;
2029 break;
2030 case as_token_unknown:
2031 default:
fe69a505 2032 aspath_free (aspath);
718e3744 2033 return NULL;
718e3744 2034 }
2035 }
2036
f669f7d2 2037 aspath_make_str_count (aspath);
718e3744 2038
2039 return aspath;
2040}
6b0655a2 2041
718e3744 2042/* Make hash value by raw aspath data. */
2043unsigned int
923de654 2044aspath_key_make (void *p)
718e3744 2045{
f669f7d2 2046 struct aspath *aspath = (struct aspath *) p;
718e3744 2047 unsigned int key = 0;
718e3744 2048
0b2aa3a0
PJ
2049 if (!aspath->str)
2050 aspath_str_update (aspath);
f669f7d2
JBD
2051
2052 key = jhash (aspath->str, aspath->str_len, 2334325);
718e3744 2053
2054 return key;
2055}
2056
2057/* If two aspath have same value then return 1 else return 0 */
96450faf 2058int
ffe11cfb 2059aspath_cmp (const void *arg1, const void *arg2)
718e3744 2060{
aea339f7
DO
2061 const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
2062 const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
fe69a505 2063
2064 while (seg1 || seg2)
2065 {
2066 int i;
2067 if ((!seg1 && seg2) || (seg1 && !seg2))
2068 return 0;
2069 if (seg1->type != seg2->type)
2070 return 0;
2071 if (seg1->length != seg2->length)
2072 return 0;
2073 for (i = 0; i < seg1->length; i++)
2074 if (seg1->as[i] != seg2->as[i])
2075 return 0;
2076 seg1 = seg1->next;
2077 seg2 = seg2->next;
2078 }
2079 return 1;
718e3744 2080}
2081
2082/* AS path hash initialize. */
2083void
94f2b392 2084aspath_init (void)
718e3744 2085{
90645f55 2086 ashash = hash_create_size (32768, aspath_key_make, aspath_cmp);
718e3744 2087}
8fdc32ab 2088
2089void
2090aspath_finish (void)
2091{
2092 hash_free (ashash);
228da428 2093 ashash = NULL;
8fdc32ab 2094
2095 if (snmp_stream)
2096 stream_free (snmp_stream);
2097}
6b0655a2 2098
718e3744 2099/* return and as path value */
2100const char *
2101aspath_print (struct aspath *as)
2102{
fe69a505 2103 return (as ? as->str : NULL);
718e3744 2104}
2105
2106/* Printing functions */
841f7a57
DO
2107/* Feed the AS_PATH to the vty; the suffix string follows it only in case
2108 * AS_PATH wasn't empty.
2109 */
718e3744 2110void
841f7a57 2111aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
718e3744 2112{
b2518c1e
PJ
2113 assert (format);
2114 vty_out (vty, format, as->str);
f669f7d2 2115 if (as->str_len && strlen (suffix))
841f7a57 2116 vty_out (vty, "%s", suffix);
718e3744 2117}
2118
94f2b392 2119static void
718e3744 2120aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
2121{
2122 struct aspath *as;
2123
2124 as = (struct aspath *) backet->data;
2125
efa9f830 2126 vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
718e3744 2127 vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
2128}
2129
2130/* Print all aspath and hash information. This function is used from
2131 `show ip bgp paths' command. */
2132void
2133aspath_print_all_vty (struct vty *vty)
2134{
2135 hash_iterate (ashash,
2136 (void (*) (struct hash_backet *, void *))
2137 aspath_show_all_iterator,
2138 vty);
2139}