Annotation of embedaddon/quagga/bgpd/bgp_aspath.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>