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