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