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