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