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