bgp_aspath.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:26k
源码类别:

网络

开发平台:

Unix_Linux

  1. /* AS path management routines.
  2.    Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
  3.    This file is part of GNU Zebra.
  4.    GNU Zebra is free software; you can redistribute it and/or modify it
  5.    under the terms of the GNU General Public License as published by the
  6.    Free Software Foundation; either version 2, or (at your option) any
  7.    later version.
  8.    GNU Zebra is distributed in the hope that it will be useful, but
  9.    WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.    General Public License for more details.
  12.    You should have received a copy of the GNU General Public License
  13.    along with GNU Zebra; see the file COPYING.  If not, write to the Free
  14.    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  15.    02111-1307, USA.  */
  16. #include <zebra.h>
  17. #include "hash.h"
  18. #include "memory.h"
  19. #include "vector.h"
  20. #include "vty.h"
  21. #include "str.h"
  22. #include "log.h"
  23. #include "bgpd/bgpd.h"
  24. #include "bgpd/bgp_aspath.h"
  25. /* Attr. Flags and Attr. Type Code. */
  26. #define AS_HEADER_SIZE        2  
  27. /* Two octet is used for AS value. */
  28. #define AS_VALUE_SIZE         sizeof (as_t)
  29. /* AS segment octet length. */
  30. #define ASSEGMENT_LEN(X)  ((X)->length * AS_VALUE_SIZE + AS_HEADER_SIZE)
  31. /* To fetch and store as segment value. */
  32. struct assegment
  33. {
  34.   u_char type;
  35.   u_char length;
  36.   as_t asval[1];
  37. };
  38. /* Hash for aspath.  This is the top level structure of AS path. */
  39. struct hash *ashash;
  40. static struct aspath *
  41. aspath_new ()
  42. {
  43.   struct aspath *aspath;
  44.   aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
  45.   memset (aspath, 0, sizeof (struct aspath));
  46.   return aspath;
  47. }
  48. /* Free AS path structure. */
  49. void
  50. aspath_free (struct aspath *aspath)
  51. {
  52.   if (!aspath)
  53.     return;
  54.   if (aspath->data)
  55.     XFREE (MTYPE_AS_SEG, aspath->data);
  56.   if (aspath->str)
  57.     XFREE (MTYPE_AS_STR, aspath->str);
  58.   XFREE (MTYPE_AS_PATH, aspath);
  59. }
  60. /* Unintern aspath from AS path bucket. */
  61. void
  62. aspath_unintern (struct aspath *aspath)
  63. {
  64.   struct aspath *ret;
  65.   if (aspath->refcnt)
  66.     aspath->refcnt--;
  67.   if (aspath->refcnt == 0)
  68.     {
  69.       /* This aspath must exist in aspath hash table. */
  70.       ret = hash_release (ashash, aspath);
  71.       assert (ret != NULL);
  72.       aspath_free (aspath);
  73.     }
  74. }
  75. /* Return the start or end delimiters for a particular Segment type */
  76. #define AS_SEG_START 0
  77. #define AS_SEG_END 1
  78. static char
  79. aspath_delimiter_char (u_char type, u_char which)
  80. {
  81.   int i;
  82.   struct
  83.   {
  84.     int type;
  85.     char start;
  86.     char end;
  87.   } aspath_delim_char [] =
  88.     {
  89.       { AS_SET,             '{', '}' },
  90.       { AS_SEQUENCE,        ' ', ' ' },
  91.       { AS_CONFED_SET,      '[', ']' },
  92.       { AS_CONFED_SEQUENCE, '(', ')' },
  93.       { 0 }
  94.     };
  95.   for (i = 0; aspath_delim_char[i].type != 0; i++)
  96.     {
  97.       if (aspath_delim_char[i].type == type)
  98. {
  99.   if (which == AS_SEG_START)
  100.     return aspath_delim_char[i].start;
  101.   else if (which == AS_SEG_END)
  102.     return aspath_delim_char[i].end;
  103. }
  104.     }
  105.   return ' ';
  106. }
  107. /* Convert aspath structure to string expression. */
  108. char *
  109. aspath_make_str_count (struct aspath *as)
  110. {
  111.   int space;
  112.   u_char type;
  113.   caddr_t pnt;
  114.   caddr_t end;
  115.   struct assegment *assegment;
  116.   int str_size = ASPATH_STR_DEFAULT_LEN;
  117.   int str_pnt;
  118.   u_char *str_buf;
  119.   int count = 0;
  120.   /* Empty aspath. */
  121.   if (as->length == 0)
  122.     {
  123.       str_buf = XMALLOC (MTYPE_AS_STR, 1);
  124.       str_buf[0] = '';
  125.       as->count = count;
  126.       return str_buf;
  127.     }
  128.   /* Set default value. */
  129.   space = 0;
  130.   type = AS_SEQUENCE;
  131.   /* Set initial pointer. */
  132.   pnt = as->data;
  133.   end = pnt + as->length;
  134.   str_buf = XMALLOC (MTYPE_AS_STR, str_size);
  135.   str_pnt = 0;
  136.   assegment = (struct assegment *) pnt;
  137.   while (pnt < end)
  138.     {
  139.       int i;
  140.       int estimate_len;
  141.       /* For fetch value. */
  142.       assegment = (struct assegment *) pnt;
  143.       /* Check AS type validity. */
  144.       if ((assegment->type != AS_SET) && 
  145.   (assegment->type != AS_SEQUENCE) &&
  146.   (assegment->type != AS_CONFED_SET) && 
  147.   (assegment->type != AS_CONFED_SEQUENCE))
  148. {
  149.   XFREE (MTYPE_AS_STR, str_buf);
  150.   return NULL;
  151. }
  152.       /* Check AS length. */
  153.       if ((pnt + (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE) > end)
  154. {
  155.   XFREE (MTYPE_AS_STR, str_buf);
  156.   return NULL;
  157. }
  158.       /* Buffer length check. */
  159.       estimate_len = ((assegment->length * 6) + 4);
  160.       
  161.       /* String length check. */
  162.       while (str_pnt + estimate_len >= str_size)
  163. {
  164.   str_size *= 2;
  165.   str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
  166. }
  167.       /* If assegment type is changed, print previous type's end
  168.          character. */
  169.       if (type != AS_SEQUENCE)
  170. str_buf[str_pnt++] = aspath_delimiter_char (type, AS_SEG_END);
  171.       if (space)
  172. str_buf[str_pnt++] = ' ';
  173.       if (assegment->type != AS_SEQUENCE)
  174. str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_START);
  175.       space = 0;
  176.       /* Increment count - ignoring CONFED SETS/SEQUENCES */
  177.       if (assegment->type != AS_CONFED_SEQUENCE
  178.   && assegment->type != AS_CONFED_SET)
  179. {
  180.   if (assegment->type == AS_SEQUENCE)
  181.     count += assegment->length;
  182.   else if (assegment->type == AS_SET)
  183.     count++;
  184. }
  185.       for (i = 0; i < assegment->length; i++)
  186. {
  187.   int len;
  188.   if (space)
  189.     {
  190.       if (assegment->type == AS_SET
  191.   || assegment->type == AS_CONFED_SET)
  192. str_buf[str_pnt++] = ',';
  193.       else
  194. str_buf[str_pnt++] = ' ';
  195.     }
  196.   else
  197.     space = 1;
  198.   len = sprintf (str_buf + str_pnt, "%d", ntohs (assegment->asval[i]));
  199.   str_pnt += len;
  200. }
  201.       type = assegment->type;
  202.       pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE;
  203.     }
  204.   if (assegment->type != AS_SEQUENCE)
  205.     str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_END);
  206.   str_buf[str_pnt] = '';
  207.   as->count = count;
  208.   return str_buf;
  209. }
  210. /* Intern allocated AS path. */
  211. struct aspath *
  212. aspath_intern (struct aspath *aspath)
  213. {
  214.   struct aspath *find;
  215.   
  216.   /* Assert this AS path structure is not interned. */
  217.   assert (aspath->refcnt == 0);
  218.   /* Check AS path hash. */
  219.   find = hash_get (ashash, aspath, hash_alloc_intern);
  220.   if (find != aspath)
  221.     aspath_free (aspath);
  222.   find->refcnt++;
  223.   if (! find->str)
  224.     find->str = aspath_make_str_count (find);
  225.   return find;
  226. }
  227. /* Duplicate aspath structure.  Created same aspath structure but
  228.    reference count and AS path string is cleared. */
  229. struct aspath *
  230. aspath_dup (struct aspath *aspath)
  231. {
  232.   struct aspath *new;
  233.   new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
  234.   memset (new, 0, sizeof (struct aspath));
  235.   new->length = aspath->length;
  236.   if (new->length)
  237.     {
  238.       new->data = XMALLOC (MTYPE_AS_SEG, aspath->length);
  239.       memcpy (new->data, aspath->data, aspath->length);
  240.     }
  241.   else
  242.     new->data = NULL;
  243.   /* new->str = aspath_make_str_count (aspath); */
  244.   return new;
  245. }
  246. void *
  247. aspath_hash_alloc (struct aspath *arg)
  248. {
  249.   struct aspath *aspath;
  250.   /* New aspath strucutre is needed. */
  251.   aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
  252.   memset ((void *) aspath, 0, sizeof (struct aspath));
  253.   aspath->length = arg->length;
  254.   /* In case of IBGP connection aspath's length can be zero. */
  255.   if (arg->length)
  256.     {
  257.       aspath->data = XMALLOC (MTYPE_AS_SEG, arg->length);
  258.       memcpy (aspath->data, arg->data, arg->length);
  259.     }
  260.   else
  261.     aspath->data = NULL;
  262.   /* Make AS path string. */
  263.   aspath->str = aspath_make_str_count (aspath);
  264.   /* Malformed AS path value. */
  265.   if (! aspath->str)
  266.     {
  267.       aspath_free (aspath);
  268.       return NULL;
  269.     }
  270.   return aspath;
  271. }
  272. /* AS path parse function.  pnt is a pointer to byte stream and length
  273.    is length of byte stream.  If there is same AS path in the the AS
  274.    path hash then return it else make new AS path structure. */
  275. struct aspath *
  276. aspath_parse (caddr_t pnt, int length)
  277. {
  278.   struct aspath as;
  279.   struct aspath *find;
  280.   /* If length is odd it's malformed AS path. */
  281.   if (length % 2)
  282.     return NULL;
  283.   /* Looking up aspath hash entry. */
  284.   as.data = pnt;
  285.   as.length = length;
  286.   /* If already same aspath exist then return it. */
  287.   find = hash_get (ashash, &as, aspath_hash_alloc);
  288.   if (! find)
  289.     return NULL;
  290.   find->refcnt++;
  291.   return find;
  292. }
  293. #define min(A,B) ((A) < (B) ? (A) : (B))
  294. #define ASSEGMENT_SIZE(N)  (AS_HEADER_SIZE + ((N) * AS_VALUE_SIZE))
  295. struct aspath *
  296. aspath_aggregate_segment_copy (struct aspath *aspath, struct assegment *seg,
  297.        int i)
  298. {
  299.   struct assegment *newseg;
  300.   if (! aspath->data)
  301.     {
  302.       aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (i));
  303.       newseg = (struct assegment *) aspath->data;
  304.       aspath->length = ASSEGMENT_SIZE (i);
  305.     }
  306.   else
  307.     {
  308.       aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data,
  309.        aspath->length + ASSEGMENT_SIZE (i));
  310.       newseg = (struct assegment *) (aspath->data + aspath->length);
  311.       aspath->length += ASSEGMENT_SIZE (i);
  312.     }
  313.   newseg->type = seg->type;
  314.   newseg->length = i;
  315.   memcpy (newseg->asval, seg->asval, (i * AS_VALUE_SIZE));
  316.   return aspath;
  317. }
  318. struct assegment *
  319. aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
  320.      as_t as)
  321. {
  322.   int i;
  323.   /* If this is first AS set member, create new as-set segment. */
  324.   if (asset == NULL)
  325.     {
  326.       if (! aspath->data)
  327. {
  328.   aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (1));
  329.   asset = (struct assegment *) aspath->data;
  330.   aspath->length = ASSEGMENT_SIZE (1);
  331. }
  332.       else
  333. {
  334.   aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data,
  335.    aspath->length + ASSEGMENT_SIZE (1));
  336.   asset = (struct assegment *) (aspath->data + aspath->length);
  337.   aspath->length += ASSEGMENT_SIZE (1);
  338. }
  339.       asset->type = AS_SET;
  340.       asset->length = 1;
  341.       asset->asval[0] = as;
  342.     }
  343.   else
  344.     {
  345.       size_t offset;
  346.       /* Check this AS value already exists or not. */
  347.       for (i = 0; i < asset->length; i++)
  348. if (asset->asval[i] == as)
  349.   return asset;
  350.       offset = (caddr_t) asset - (caddr_t) aspath->data;
  351.       aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data,
  352.        aspath->length + AS_VALUE_SIZE);
  353.       asset = (struct assegment *) (aspath->data + offset);
  354.       aspath->length += AS_VALUE_SIZE;
  355.       asset->asval[asset->length] = as;
  356.       asset->length++;
  357.     }
  358.   return asset;
  359. }
  360. /* Modify as1 using as2 for aggregation. */
  361. struct aspath *
  362. aspath_aggregate (struct aspath *as1, struct aspath *as2)
  363. {
  364.   int i;
  365.   int minlen;
  366.   int match;
  367.   int match1;
  368.   int match2;
  369.   caddr_t cp1;
  370.   caddr_t cp2;
  371.   caddr_t end1;
  372.   caddr_t end2;
  373.   struct assegment *seg1;
  374.   struct assegment *seg2;
  375.   struct aspath *aspath;
  376.   struct assegment *asset;
  377.   match = 0;
  378.   minlen = 0;
  379.   aspath = NULL;
  380.   asset = NULL;
  381.   cp1 = as1->data;
  382.   end1 = as1->data + as1->length;
  383.   cp2 = as2->data;
  384.   end2 = as2->data + as2->length;
  385.   seg1 = (struct assegment *) cp1;
  386.   seg2 = (struct assegment *) cp2;
  387.   /* First of all check common leading sequence. */
  388.   while ((cp1 < end1) && (cp2 < end2))
  389.     {
  390.       /* Check segment type. */
  391.       if (seg1->type != seg2->type)
  392. break;
  393.       /* Minimum segment length. */
  394.       minlen = min (seg1->length, seg2->length);
  395.       for (match = 0; match < minlen; match++)
  396. if (seg1->asval[match] != seg2->asval[match])
  397.   break;
  398.       if (match)
  399. {
  400.   if (! aspath)
  401.     aspath = aspath_new();
  402.   aspath = aspath_aggregate_segment_copy (aspath, seg1, match);
  403. }
  404.       if (match != minlen || match != seg1->length 
  405.   || seg1->length != seg2->length)
  406. break;
  407.       cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE);
  408.       cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE);
  409.       seg1 = (struct assegment *) cp1;
  410.       seg2 = (struct assegment *) cp2;
  411.     }
  412.   if (! aspath)
  413.     aspath = aspath_new();
  414.   /* Make as-set using rest of all information. */
  415.   match1 = match;
  416.   while (cp1 < end1)
  417.     {
  418.       seg1 = (struct assegment *) cp1;
  419.       for (i = match1; i < seg1->length; i++)
  420. asset = aspath_aggregate_as_set_add (aspath, asset, seg1->asval[i]);
  421.       match1 = 0;
  422.       cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE);
  423.     }
  424.   match2 = match;
  425.   while (cp2 < end2)
  426.     {
  427.       seg2 = (struct assegment *) cp2;
  428.       for (i = match2; i < seg2->length; i++)
  429. asset = aspath_aggregate_as_set_add (aspath, asset, seg2->asval[i]);
  430.       match2 = 0;
  431.       cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE);
  432.     }
  433.   return aspath;
  434. }
  435. /* When a BGP router receives an UPDATE with an MP_REACH_NLRI
  436.    attribute, check the leftmost AS number in the AS_PATH attribute is
  437.    or not the peer's AS number. */ 
  438. int
  439. aspath_firstas_check (struct aspath *aspath, as_t asno)
  440. {
  441.   caddr_t pnt;
  442.   struct assegment *assegment;
  443.   if (aspath == NULL)
  444.     return 0;
  445.   pnt = aspath->data;
  446.   assegment = (struct assegment *) pnt;
  447.   if (assegment
  448.       && assegment->type == AS_SEQUENCE
  449.       && assegment->asval[0] == htons (asno))
  450.     return 1;
  451.   return 0;
  452. }
  453. /* AS path loop check.  If aspath contains asno then return 1. */
  454. int
  455. aspath_loop_check (struct aspath *aspath, as_t asno)
  456. {
  457.   caddr_t pnt;
  458.   caddr_t end;
  459.   struct assegment *assegment;
  460.   int count = 0;
  461.   if (aspath == NULL)
  462.     return 0;
  463.   pnt = aspath->data;
  464.   end = aspath->data + aspath->length;
  465.   while (pnt < end)
  466.     {
  467.       int i;
  468.       assegment = (struct assegment *) pnt;
  469.       
  470.       for (i = 0; i < assegment->length; i++)
  471. if (assegment->asval[i] == htons (asno))
  472.   count++;
  473.       pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE;
  474.     }
  475.   return count;
  476. }
  477. /* When all of AS path is private AS return 1.  */
  478. int
  479. aspath_private_as_check (struct aspath *aspath)
  480. {
  481.   caddr_t pnt;
  482.   caddr_t end;
  483.   struct assegment *assegment;
  484.   if (aspath == NULL)
  485.     return 0;
  486.   if (aspath->length == 0)
  487.     return 0;
  488.   pnt = aspath->data;
  489.   end = aspath->data + aspath->length;
  490.   while (pnt < end)
  491.     {
  492.       int i;
  493.       assegment = (struct assegment *) pnt;
  494.       
  495.       for (i = 0; i < assegment->length; i++)
  496. {
  497.   if (ntohs (assegment->asval[i]) < BGP_PRIVATE_AS_MIN
  498.       || ntohs (assegment->asval[i]) > BGP_PRIVATE_AS_MAX)
  499.     return 0;
  500. }
  501.       pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE;
  502.     }
  503.   return 1;
  504. }
  505. /* Merge as1 to as2.  as2 should be uninterned aspath. */
  506. struct aspath *
  507. aspath_merge (struct aspath *as1, struct aspath *as2)
  508. {
  509.   caddr_t data;
  510.   if (! as1 || ! as2)
  511.     return NULL;
  512.   data = XMALLOC (MTYPE_AS_SEG, as1->length + as2->length);
  513.   memcpy (data, as1->data, as1->length);
  514.   memcpy (data + as1->length, as2->data, as2->length);
  515.   XFREE (MTYPE_AS_SEG, as2->data);
  516.   as2->data = data;
  517.   as2->length += as1->length;
  518.   as2->count += as1->count;
  519.   return as2;
  520. }
  521. /* Prepend as1 to as2.  as2 should be uninterned aspath. */
  522. struct aspath *
  523. aspath_prepend (struct aspath *as1, struct aspath *as2)
  524. {
  525.   caddr_t pnt;
  526.   caddr_t end;
  527.   struct assegment *seg1 = NULL;
  528.   struct assegment *seg2 = NULL;
  529.   if (! as1 || ! as2)
  530.     return NULL;
  531.   seg2 = (struct assegment *) as2->data;
  532.   /* In case of as2 is empty AS. */
  533.   if (seg2 == NULL)
  534.     {
  535.       as2->length = as1->length;
  536.       as2->data = XMALLOC (MTYPE_AS_SEG, as1->length);
  537.       as2->count = as1->count;
  538.       memcpy (as2->data, as1->data, as1->length);
  539.       return as2;
  540.     }
  541.   /* assegment points last segment of as1. */
  542.   pnt = as1->data;
  543.   end = as1->data + as1->length;
  544.   while (pnt < end)
  545.     {
  546.       seg1 = (struct assegment *) pnt;
  547.       pnt += (seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE;
  548.     }
  549.   /* In case of as1 is empty AS. */
  550.   if (seg1 == NULL)
  551.     return as2;
  552.   /* Compare last segment type of as1 and first segment type of as2. */
  553.   if (seg1->type != seg2->type)
  554.     return aspath_merge (as1, as2);
  555.   if (seg1->type == AS_SEQUENCE)
  556.     {
  557.       caddr_t newdata;
  558.       struct assegment *seg = NULL;
  559.       
  560.       newdata = XMALLOC (MTYPE_AS_SEG, 
  561.  as1->length + as2->length - AS_HEADER_SIZE);
  562.       memcpy (newdata, as1->data, as1->length);
  563.       seg = (struct assegment *) (newdata + ((caddr_t)seg1 - as1->data));
  564.       seg->length += seg2->length;
  565.       memcpy (newdata + as1->length, as2->data + AS_HEADER_SIZE,
  566.       as2->length - AS_HEADER_SIZE);
  567.       XFREE (MTYPE_AS_SEG, as2->data);
  568.       as2->data = newdata;
  569.       as2->length += (as1->length - AS_HEADER_SIZE);
  570.       as2->count += as1->count;
  571.       return as2;
  572.     }
  573.   else
  574.     {
  575.       /* AS_SET merge code is needed at here. */
  576.       return aspath_merge (as1, as2);
  577.     }
  578.   /* Not reached */
  579. }
  580. /* Add specified AS to the leftmost of aspath. */
  581. static struct aspath *
  582. aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
  583. {
  584.   struct assegment *assegment;
  585.   assegment = (struct assegment *) aspath->data;
  586.   /* In case of empty aspath. */
  587.   if (assegment == NULL || assegment->length == 0)
  588.     {
  589.       aspath->length = AS_HEADER_SIZE + AS_VALUE_SIZE;
  590.       if (assegment)
  591. aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, aspath->length);
  592.       else
  593. aspath->data = XMALLOC (MTYPE_AS_SEG, aspath->length);
  594.       assegment = (struct assegment *) aspath->data;
  595.       assegment->type = type;
  596.       assegment->length = 1;
  597.       assegment->asval[0] = htons (asno);
  598.       return aspath;
  599.     }
  600.   if (assegment->type == type)
  601.     {
  602.       caddr_t newdata;
  603.       struct assegment *newsegment;
  604.       newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE);
  605.       newsegment = (struct assegment *) newdata;
  606.       newsegment->type = type;
  607.       newsegment->length = assegment->length + 1;
  608.       newsegment->asval[0] = htons (asno);
  609.       memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE,
  610.       aspath->data + AS_HEADER_SIZE, 
  611.       aspath->length - AS_HEADER_SIZE);
  612.       XFREE (MTYPE_AS_SEG, aspath->data);
  613.       aspath->data = newdata;
  614.       aspath->length += AS_VALUE_SIZE;
  615.     } else {
  616.       caddr_t newdata;
  617.       struct assegment *newsegment;
  618.       newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE + AS_HEADER_SIZE);
  619.       newsegment = (struct assegment *) newdata;
  620.       newsegment->type = type;
  621.       newsegment->length = 1;
  622.       newsegment->asval[0] = htons (asno);
  623.       memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE,
  624.       aspath->data,
  625.       aspath->length);
  626.       XFREE (MTYPE_AS_SEG, aspath->data);
  627.       aspath->data = newdata;
  628.       aspath->length += AS_HEADER_SIZE + AS_VALUE_SIZE;
  629.     }
  630.   return aspath;
  631. }
  632. /* Add specified AS to the leftmost of aspath. */
  633. struct aspath *
  634. aspath_add_seq (struct aspath *aspath, as_t asno)
  635. {
  636.   return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
  637. }
  638. /* Compare leftmost AS value for MED check.  If as1's leftmost AS and
  639.    as2's leftmost AS is same return 1. */
  640. int
  641. aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
  642. {
  643.   struct assegment *seg1;
  644.   struct assegment *seg2;
  645.   as_t as1;
  646.   as_t as2;
  647.   seg1 = (struct assegment *) aspath1->data;
  648.   seg2 = (struct assegment *) aspath2->data;
  649.   while (seg1 && seg1->length 
  650.  && (seg1->type == AS_CONFED_SEQUENCE || seg1->type == AS_CONFED_SET))
  651.     seg1 = (struct assegment *) ((caddr_t) seg1 + ASSEGMENT_LEN (seg1));
  652.   while (seg2 && seg2->length 
  653.  && (seg2->type == AS_CONFED_SEQUENCE || seg2->type == AS_CONFED_SET))
  654.     seg2 = (struct assegment *) ((caddr_t) seg2 + ASSEGMENT_LEN (seg2));
  655.   /* Check as1's */
  656.   if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_SEQUENCE)
  657.     return 0;
  658.   as1 = seg1->asval[0];
  659.   if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_SEQUENCE)
  660.     return 0;
  661.   as2 = seg2->asval[0];
  662.   if (as1 == as2)
  663.     return 1;
  664.   return 0;
  665. }
  666. /* Compare leftmost AS value for MED check.  If as1's leftmost AS and
  667.    as2's leftmost AS is same return 1. (confederation as-path
  668.    only).  */
  669. int
  670. aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2)
  671. {
  672.   struct assegment *seg1;
  673.   struct assegment *seg2;
  674.   as_t as1;
  675.   as_t as2;
  676.   if (aspath1->count || aspath2->count) 
  677.     return 0;
  678.   seg1 = (struct assegment *) aspath1->data;
  679.   seg2 = (struct assegment *) aspath2->data;
  680.   /* Check as1's */
  681.   if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_CONFED_SEQUENCE)
  682.     return 0;
  683.   as1 = seg1->asval[0];
  684.   /* Check as2's */
  685.   if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_CONFED_SEQUENCE)
  686.     return 0;
  687.   as2 = seg2->asval[0];
  688.   if (as1 == as2)
  689.     return 1;
  690.   return 0;
  691. }
  692. /* Delete first sequential AS_CONFED_SEQUENCE from aspath.  */
  693. struct aspath *
  694. aspath_delete_confed_seq (struct aspath *aspath)
  695. {
  696.   int seglen;
  697.   struct assegment *assegment;
  698.   if (! aspath)
  699.     return aspath;
  700.   assegment = (struct assegment *) aspath->data;
  701.   while (assegment)
  702.     {
  703.       if (assegment->type != AS_CONFED_SEQUENCE)
  704. return aspath;
  705.       seglen = ASSEGMENT_LEN (assegment);
  706.       if (seglen == aspath->length)
  707. {
  708.   XFREE (MTYPE_AS_SEG, aspath->data);
  709.   aspath->data = NULL;
  710.   aspath->length = 0;
  711. }
  712.       else
  713. {
  714.   memcpy (aspath->data, aspath->data + seglen,
  715.   aspath->length - seglen);
  716.   aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data,
  717.    aspath->length - seglen);
  718.   aspath->length -= seglen;
  719. }
  720.       assegment = (struct assegment *) aspath->data;
  721.     }
  722.   return aspath;
  723. }
  724. /* Add new AS number to the leftmost part of the aspath as
  725.    AS_CONFED_SEQUENCE.  */
  726. struct aspath*
  727. aspath_add_confed_seq (struct aspath *aspath, as_t asno)
  728. {
  729.   return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
  730. }
  731. /* Add new as value to as path structure. */
  732. void
  733. aspath_as_add (struct aspath *as, as_t asno)
  734. {
  735.   caddr_t pnt;
  736.   caddr_t end;
  737.   struct assegment *assegment;
  738.   /* Increase as->data for new as value. */
  739.   as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2);
  740.   as->length += 2;
  741.   pnt = as->data;
  742.   end = as->data + as->length;
  743.   assegment = (struct assegment *) pnt;
  744.   /* Last segment search procedure. */
  745.   while (pnt + 2 < end)
  746.     {
  747.       assegment = (struct assegment *) pnt;
  748.       /* We add 2 for segment_type and segment_length and segment
  749.          value assegment->length * 2. */
  750.       pnt += (AS_HEADER_SIZE + (assegment->length * AS_VALUE_SIZE));
  751.     }
  752.   assegment->asval[assegment->length] = htons (asno);
  753.   assegment->length++;
  754. }
  755. /* Add new as segment to the as path. */
  756. void
  757. aspath_segment_add (struct aspath *as, int type)
  758. {
  759.   struct assegment *assegment;
  760.   if (as->data == NULL)
  761.     {
  762.       as->data = XMALLOC (MTYPE_AS_SEG, 2);
  763.       assegment = (struct assegment *) as->data;
  764.       as->length = 2;
  765.     }
  766.   else
  767.     {
  768.       as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2);
  769.       assegment = (struct assegment *) (as->data + as->length);
  770.       as->length += 2;
  771.     }
  772.   assegment->type = type;
  773.   assegment->length = 0;
  774. }
  775. struct aspath *
  776. aspath_empty ()
  777. {
  778.   return aspath_parse (NULL, 0);
  779. }
  780. struct aspath *
  781. aspath_empty_get ()
  782. {
  783.   struct aspath *aspath;
  784.   aspath = aspath_new ();
  785.   aspath->str = aspath_make_str_count (aspath);
  786.   return aspath;
  787. }
  788. unsigned long
  789. aspath_count ()
  790. {
  791.   return ashash->count;
  792. }     
  793. /* 
  794.    Theoretically, one as path can have:
  795.    One BGP packet size should be less than 4096.
  796.    One BGP attribute size should be less than 4096 - BGP header size.
  797.    One BGP aspath size should be less than 4096 - BGP header size -
  798.    BGP mandantry attribute size.
  799. */
  800. /* AS path string lexical token enum. */
  801. enum as_token
  802.   {
  803.     as_token_asval,
  804.     as_token_set_start,
  805.     as_token_set_end,
  806.     as_token_confed_start,
  807.     as_token_confed_end,
  808.     as_token_unknown
  809.   };
  810. /* Return next token and point for string parse. */
  811. char *
  812. aspath_gettoken (char *buf, enum as_token *token, u_short *asno)
  813. {
  814.   char *p = buf;
  815.   /* Skip space. */
  816.   while (isspace ((int) *p))
  817.     p++;
  818.   /* Check the end of the string and type specify characters
  819.      (e.g. {}()). */
  820.   switch (*p)
  821.     {
  822.     case '':
  823.       return NULL;
  824.       break;
  825.     case '{':
  826.       *token = as_token_set_start;
  827.       p++;
  828.       return p;
  829.       break;
  830.     case '}':
  831.       *token = as_token_set_end;
  832.       p++;
  833.       return p;
  834.       break;
  835.     case '(':
  836.       *token = as_token_confed_start;
  837.       p++;
  838.       return p;
  839.       break;
  840.     case ')':
  841.       *token = as_token_confed_end;
  842.       p++;
  843.       return p;
  844.       break;
  845.     }
  846.   /* Check actual AS value. */
  847.   if (isdigit ((int) *p)) 
  848.     {
  849.       u_short asval;
  850.       *token = as_token_asval;
  851.       asval = (*p - '0');
  852.       p++;
  853.       while (isdigit ((int) *p)) 
  854. {
  855.   asval *= 10;
  856.   asval += (*p - '0');
  857.   p++;
  858. }
  859.       *asno = asval;
  860.       return p;
  861.     }
  862.   
  863.   /* There is no match then return unknown token. */
  864.   *token = as_token_unknown;
  865.   return  p++;
  866. }
  867. struct aspath *
  868. aspath_str2aspath (char *str)
  869. {
  870.   enum as_token token;
  871.   u_short as_type;
  872.   u_short asno;
  873.   struct aspath *aspath;
  874.   int needtype;
  875.   aspath = aspath_new ();
  876.   /* We start default type as AS_SEQUENCE. */
  877.   as_type = AS_SEQUENCE;
  878.   needtype = 1;
  879.   while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
  880.     {
  881.       switch (token)
  882. {
  883. case as_token_asval:
  884.   if (needtype)
  885.     {
  886.       aspath_segment_add (aspath, as_type);
  887.       needtype = 0;
  888.     }
  889.   aspath_as_add (aspath, asno);
  890.   break;
  891. case as_token_set_start:
  892.   as_type = AS_SET;
  893.   aspath_segment_add (aspath, as_type);
  894.   needtype = 0;
  895.   break;
  896. case as_token_set_end:
  897.   as_type = AS_SEQUENCE;
  898.   needtype = 1;
  899.   break;
  900. case as_token_confed_start:
  901.   as_type = AS_CONFED_SEQUENCE;
  902.   aspath_segment_add (aspath, as_type);
  903.   needtype = 0;
  904.   break;
  905. case as_token_confed_end:
  906.   as_type = AS_SEQUENCE;
  907.   needtype = 1;
  908.   break;
  909. case as_token_unknown:
  910. default:
  911.   return NULL;
  912.   break;
  913. }
  914.     }
  915.   aspath->str = aspath_make_str_count (aspath);
  916.   return aspath;
  917. }
  918. /* Make hash value by raw aspath data. */
  919. unsigned int
  920. aspath_key_make (struct aspath *aspath)
  921. {
  922.   unsigned int key = 0;
  923.   int length;
  924.   unsigned short *pnt;
  925.   length = aspath->length / 2;
  926.   pnt = (unsigned short *) aspath->data;
  927.   while (length)
  928.     {
  929.       key += *pnt++;
  930.       length--;
  931.     }
  932.   return key;
  933. }
  934. /* If two aspath have same value then return 1 else return 0 */
  935. int
  936. aspath_cmp (struct aspath *as1, struct aspath *as2)
  937. {
  938.   if (as1->length == as2->length 
  939.       && !memcmp (as1->data, as2->data, as1->length))
  940.     return 1;
  941.   else
  942.     return 0;
  943. }
  944. /* AS path hash initialize. */
  945. void
  946. aspath_init ()
  947. {
  948.   ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
  949. }
  950. /* return and as path value */
  951. const char *
  952. aspath_print (struct aspath *as)
  953. {
  954.   return as->str;
  955. }
  956. /* Printing functions */
  957. void
  958. aspath_print_vty (struct vty *vty, struct aspath *as)
  959. {
  960.   vty_out (vty, "%s", as->str);
  961. }
  962. void
  963. aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
  964. {
  965.   struct aspath *as;
  966.   as = (struct aspath *) backet->data;
  967.   vty_out (vty, "[%p:%d] (%ld) ", backet, backet->key, as->refcnt);
  968.   vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
  969. }
  970. /* Print all aspath and hash information.  This function is used from
  971.    `show ip bgp paths' command. */
  972. void
  973. aspath_print_all_vty (struct vty *vty)
  974. {
  975.   hash_iterate (ashash, 
  976. (void (*) (struct hash_backet *, void *))
  977. aspath_show_all_iterator,
  978. vty);
  979. }