LCOV - code coverage report
Current view: top level - bgpd - bgp_aspath.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 602 790 76.2 %
Date: 2015-11-19 Functions: 49 63 77.8 %

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

Generated by: LCOV version 1.10