File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / bgpd / bgp_aspath.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:37 2013 UTC (10 years, 11 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, HEAD
0.99.22

    1: /* AS path management routines.
    2:    Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
    3:    Copyright (C) 2005 Sun Microsystems, Inc.
    4: 
    5: This file is part of GNU Zebra.
    6: 
    7: GNU Zebra is free software; you can redistribute it and/or modify it
    8: under the terms of the GNU General Public License as published by the
    9: Free Software Foundation; either version 2, or (at your option) any
   10: later version.
   11: 
   12: GNU Zebra is distributed in the hope that it will be useful, but
   13: WITHOUT ANY WARRANTY; without even the implied warranty of
   14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15: General Public License for more details.
   16: 
   17: You should have received a copy of the GNU General Public License
   18: along with GNU Zebra; see the file COPYING.  If not, write to the Free
   19: Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   20: 02111-1307, USA.  */
   21: 
   22: #include <zebra.h>
   23: 
   24: #include "hash.h"
   25: #include "memory.h"
   26: #include "vector.h"
   27: #include "vty.h"
   28: #include "str.h"
   29: #include "log.h"
   30: #include "stream.h"
   31: #include "jhash.h"
   32: 
   33: #include "bgpd/bgpd.h"
   34: #include "bgpd/bgp_aspath.h"
   35: #include "bgpd/bgp_debug.h"
   36: #include "bgpd/bgp_attr.h"
   37: 
   38: /* Attr. Flags and Attr. Type Code. */
   39: #define AS_HEADER_SIZE        2	 
   40: 
   41: /* Now FOUR octets are used for AS value. */
   42: #define AS_VALUE_SIZE         sizeof (as_t)
   43: /* This is the old one */
   44: #define AS16_VALUE_SIZE	      sizeof (as16_t)
   45: 
   46: /* Maximum protocol segment length value */
   47: #define AS_SEGMENT_MAX		255
   48: 
   49: /* The following length and size macros relate specifically to Quagga's
   50:  * internal representation of AS-Segments, not per se to the on-wire
   51:  * sizes and lengths.  At present (200508) they sort of match, however
   52:  * the ONLY functions which should now about the on-wire syntax are
   53:  * aspath_put, assegment_put and assegment_parse.
   54:  *
   55:  * aspath_put returns bytes written, the only definitive record of
   56:  * size of wire-format attribute..
   57:  */
   58: 
   59: /* Calculated size in bytes of ASN segment data to hold N ASN's */
   60: #define ASSEGMENT_DATA_SIZE(N,S) \
   61: 	((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )
   62: 
   63: /* Calculated size of segment struct to hold N ASN's */
   64: #define ASSEGMENT_SIZE(N,S)  (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
   65: 
   66: /* AS segment octet length. */
   67: #define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
   68: 
   69: /* AS_SEQUENCE segments can be packed together */
   70: /* Can the types of X and Y be considered for packing? */
   71: #define ASSEGMENT_TYPES_PACKABLE(X,Y) \
   72:   ( ((X)->type == (Y)->type) \
   73:    && ((X)->type == AS_SEQUENCE))
   74: /* Types and length of X,Y suitable for packing? */
   75: #define ASSEGMENTS_PACKABLE(X,Y) \
   76:   ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \
   77:    && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) )
   78: 
   79: /* As segment header - the on-wire representation 
   80:  * NOT the internal representation!
   81:  */
   82: struct assegment_header
   83: {
   84:   u_char type;
   85:   u_char length;
   86: };
   87: 
   88: /* Hash for aspath.  This is the top level structure of AS path. */
   89: static struct hash *ashash;
   90: 
   91: /* Stream for SNMP. See aspath_snmp_pathseg */
   92: static struct stream *snmp_stream;
   93: 
   94: /* Callers are required to initialize the memory */
   95: static as_t *
   96: assegment_data_new (int num)
   97: {
   98:   return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
   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;
  189:   int i;
  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: 
  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;
  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. */
  497: static void
  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:     {
  508:       as->str = XMALLOC (MTYPE_AS_STR, 1);
  509:       as->str[0] = '\0';
  510:       as->str_len = 0;
  511:       return;
  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);
  548:             as->str = NULL;
  549:             as->str_len = 0;
  550:             return;
  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';
  597:   as->str = str_buf;
  598:   as->str_len = len;
  599: 
  600:   return;
  601: }
  602: 
  603: static void
  604: aspath_str_update (struct aspath *as)
  605: {
  606:   if (as->str)
  607:     XFREE (MTYPE_AS_STR, as->str);
  608:   aspath_make_str_count (as);
  609: }
  610: 
  611: /* Intern allocated AS path. */
  612: struct aspath *
  613: aspath_intern (struct aspath *aspath)
  614: {
  615:   struct aspath *find;
  616: 
  617:   /* Assert this AS path structure is not interned and has the string
  618:      representation built. */
  619:   assert (aspath->refcnt == 0);
  620:   assert (aspath->str);
  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: {
  637:   unsigned short buflen = aspath->str_len + 1;
  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: 
  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';
  656: 
  657:   return new;
  658: }
  659: 
  660: static void *
  661: aspath_hash_alloc (void *arg)
  662: {
  663:   const struct aspath *aspath = arg;
  664:   struct aspath *new;
  665: 
  666:   /* Malformed AS path value. */
  667:   assert (aspath->str);
  668:   if (! aspath->str)
  669:     return NULL;
  670: 
  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;
  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;
  804: 
  805:   /* If already same aspath exist then return it. */
  806:   find = hash_get (ashash, &as, aspath_hash_alloc);
  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: 
  819:   find->refcnt++;
  820: 
  821:   return find;
  822: }
  823: 
  824: static void
  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: 
  842: static size_t
  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: {
 1412:   const struct assegment *seg1;
 1413:   const struct assegment *seg2;
 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 ();
 1651:   aspath_make_str_count (aspath);
 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: 
 1810:   aspath_make_str_count (aspath);
 1811: 
 1812:   return aspath;
 1813: }
 1814: 
 1815: /* Make hash value by raw aspath data. */
 1816: unsigned int
 1817: aspath_key_make (void *p)
 1818: {
 1819:   struct aspath *aspath = (struct aspath *) p;
 1820:   unsigned int key = 0;
 1821: 
 1822:   if (!aspath->str)
 1823:     aspath_str_update (aspath);
 1824: 
 1825:   key = jhash (aspath->str, aspath->str_len, 2334325);
 1826: 
 1827:   return key;
 1828: }
 1829: 
 1830: /* If two aspath have same value then return 1 else return 0 */
 1831: int
 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);
 1888:   if (as->str_len && strlen (suffix))
 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>