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

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

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