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