File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / bgpd / bgp_aspath.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

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

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