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