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

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

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