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