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

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

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