diff options
| -rw-r--r-- | ChangeLog | 4 | ||||
| -rw-r--r-- | NEWS | 6 | ||||
| -rw-r--r-- | bgpd/ChangeLog | 128 | ||||
| -rw-r--r-- | bgpd/bgp_aspath.c | 357 | ||||
| -rw-r--r-- | bgpd/bgp_aspath.h | 14 | ||||
| -rw-r--r-- | bgpd/bgp_attr.c | 411 | ||||
| -rw-r--r-- | bgpd/bgp_debug.c | 118 | ||||
| -rw-r--r-- | bgpd/bgp_debug.h | 7 | ||||
| -rw-r--r-- | bgpd/bgp_dump.c | 265 | ||||
| -rw-r--r-- | bgpd/bgp_dump.h | 22 | ||||
| -rw-r--r-- | bgpd/bgp_ecommunity.c | 130 | ||||
| -rw-r--r-- | bgpd/bgp_ecommunity.h | 5 | ||||
| -rw-r--r-- | bgpd/bgp_open.c | 116 | ||||
| -rw-r--r-- | bgpd/bgp_open.h | 6 | ||||
| -rw-r--r-- | bgpd/bgp_packet.c | 88 | ||||
| -rw-r--r-- | bgpd/bgp_routemap.c | 8 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 175 | ||||
| -rw-r--r-- | bgpd/bgp_vty.h | 2 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 12 | ||||
| -rw-r--r-- | doc/BGP-TypeCode | 2 | ||||
| -rw-r--r-- | tests/ChangeLog | 36 | ||||
| -rw-r--r-- | tests/Makefile.am | 4 | ||||
| -rw-r--r-- | tests/aspath_test.c | 245 | ||||
| -rw-r--r-- | tests/bgp_capability_test.c | 157 | ||||
| -rw-r--r-- | vtysh/ChangeLog | 5 | ||||
| -rwxr-xr-x | vtysh/extract.pl.in | 4 | ||||
| -rw-r--r-- | vtysh/vtysh.c | 2 | 
27 files changed, 1897 insertions, 432 deletions
| @@ -1,3 +1,7 @@ +2007-10-14 Paul Jakma <paul.jakma@sun.com> + +	* NEWS: Note that MRT dumps are now version 2 +  2007-09-07 Paul Jakma <paul.jakma@sun.com>  	* configure.ac: Bump version to 0.99.9 @@ -1,5 +1,11 @@  * Changes in Quagga 0.99.2 +- [bgpd] 4-byte AS support added +- [bgpd] MRT format changes to version 2. Those relying on +  bgpd MRT table dumps may need to update their tools. + +* Changes in Quagga 0.99.2 +  - [bgpd] Work queues added to bgpd to split up update processing,    particularly beneficial when a peer session goes down. AS_PATH    parsing rewritten to be clearer, more robust and ready for 4-byte. diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog index c98485b4..5a31d9cb 100644 --- a/bgpd/ChangeLog +++ b/bgpd/ChangeLog @@ -1,3 +1,131 @@ +2007-09-27 Paul Jakma <paul.jakma@sun.com> + +	* bgp_aspath.c: (assegment_normalise) remove duplicates from +	  from sets. +	  (aspath_reconcile_as4) disregard a broken part of the RFC around +	  error handling in path reconciliation. + +2007-09-25 Paul Jakma <paul.jakma@sun.com> + +	* bgp_open.c: (peek_for_as4_capability) Fix to work. +	* bgp_packet.c: (bgp_open_receive) Fix sanity check of as4. +	 +2007-09-18 Paul Jakma <paul.jakma@sun.com> + +	* bgp_open.c: (bgp_capability_as4) debug printf inline with others. +	  (peek_for_as4_capability) There's no need to signal failure, as +	  failure is better dealt with through full capability parser - +	  just return the AS4, simpler. +	* bgp_packet.c: (bgp_open_receive) Update to match +	  peek_for_as4_capability change. +	  Allow use of BGP_AS_TRANS by 2b speakers. +	  Use NOTIFY_OPEN_ERR rather than CEASE for OPEN parsing errors. +	  (bgp_capability_msg_parse) missing argument to debug print +	  (bgp_capability_receive) missing return values. +	   +	   +2007-07-25 Paul Jakma <paul.jakma@sun.com> + +	* Remove 2-byte size macros, just make existing macros take +	  argument to indicate which size to use. +	  Adjust all users - typically they want '1'. +	* bgp_aspath.c: (aspath_has_as4) New, return 1 if there are any +	  as4's in a path. +	  (aspath_put) Return the number of bytes actually written, to +	  fix the bug Juergen noted: Splitting of segments will change +	  the number of bytes written from that already written to the +	  AS_PATH header. +	  (aspath_snmp_pathseg) Pass 2-byte flag to aspath_put. SNMP +	  is still defined as 2b. +	  (aspath_aggregate) fix latent bug. +	  (aspath_reconcile_as4) AS_PATH+NEW_AS_PATH reconciliation +	  function. +	  (aspath_key_make) Hash the AS_PATH string, rather than +	  just taking the addition of assegment ASes as the hash value, +	  hopefully sligthly more collision resistant. +	  (bgp_attr_munge_as4_attrs) Collide the NEW_ attributes +	  together with the OLD 2-byte forms, code Juergen +	  had in bgp_attr_parse but re-organised a bit. +	  (bgp_attr_parse) Bunch of code from Juergen moves +	  to previous function. +	  (bgp_packet_attribute) Compact significantly by +	  just /always/ using extended-length attr header. +	  Fix bug Juergen noted, by using aspath_put's +	  (new) returned size value for the attr header rather +	  than the (guesstimate) of aspath_size() - the two could +	  differ when aspath_put had to split large segments, unlikely +	  this bug was ever hit in the 'wild'. +	  (bgp_dump_routes_attr) Always use extended-len and +	  use aspath_put return for header length. Output 4b ASN +	  for AS_PATH and AGGREGATOR. +	* bgp_ecommunity.c: (ecommunity_{hash_make,cmp}) fix +	  hash callback declarations to match prototypes. +	  (ecommunity_gettoken) Updated for ECOMMUNITY_ENCODE_AS4,  +	  complete rewrite of Juergen's changes (no asdot support) +	* bgp_open.c: (bgp_capability_as4) New, does what it says +	  on the tin. +	  (peek_for_as4_capability) Rewritten to use streams and +	  bgp_capability_as4. +	* bgp_packet.c: (bgp_open_send) minor edit +	  checked (in the abstract at least) with Juergen. +	  Changes are to be more accepting, e.g, allow AS_TRANS on +	  a 2-byte session. +	* (general) Update all commands to use CMD_AS_RANGE. +	* bgp_vty.c: (bgp_clear) Fix return vals to use CMD_.. +	  Remove stuff replicated by VTY_GET_LONG +	  (bgp_clear_vty) Return bgp_clear directly to vty. +	   +	 +2007-07-25 Juergen Kammer <j.kammer@eurodata.de> + +	* (general) AS4 support. +	* bgpd.h: as_t changes to 4-bytes. +	* bgp_aspath.h: Add BGP_AS4_MAX and BGP_AS_TRANS defines. +	* bgp_aspath.c: AS_VALUE_SIZE becomes 4-byte, AS16_VALUE_SIZE +	  added for 2-byte. +	  Add AS16 versions of length calc macros. +	  (aspath_count_numas) New, count number of ASes. +	  (aspath_has_as4) New, return 1 if there are any as4's in a +	  path. +	  (assegments_parse) Interpret assegment as 4 or 2 byte, +	  according to how the caller instructs us, with a new +	  argument. +	  (aspath_parse) Add use32bit argument to pass to +	  assegments_parse. Adjust all its callers to pass 1, unless +	  otherwise noted. +	  (assegment_data_put) Adjust to be able to write 2 or 4 byte +	  AS, according to new use32bit argument. +	  (aspath_put) Adjust to write 2 or 4.  +	  (aspath_gettoken) Use a long for passed in asno. +	* bgp_attr.c: (attr_str) Add BGP_ATTR_AS4_PATH and +	  BGP_ATTR_AS4_AGGREGATOR. +	  (bgp_attr_aspath) Call aspath_parse with right 2/4 arg, as +	  determined by received-capability flag. +	  (bgp_attr_aspath_check) New, code previously in attr_aspath +	  but moved to new func so it can be run after NEW_AS_PATH +	  reconciliation. +	  (bgp_attr_as4_path) New, handle NEW_AS_PATH. +	  (bgp_attr_aggregator) Adjust to cope with 2/4 byte ASes. +	  (bgp_attr_as4_aggregator) New, read NEW_AGGREGATOR. +	  (bgp_attr_parse) Add handoffs to previous parsers for the two +	  new AS4 NEW_ attributes. +	  Various checks added for NEW/OLD reconciliation. +	  (bgp_packet_attribute) Support 2/4 for AS_PATH and +	  AGGREGATOR, detect when NEW_ attrs need to be sent. +	* bgp_debug.{c,h}: Add 'debug bgp as4'. +	* bgp_dump.c: MRTv2 support, unconditionally enabled, which +	  supports AS4. Based on patches from Erik (RIPE?). +	* bgp_ecommunity.c: (ecommunity_ecom2str) ECOMMUNITY_ENCODE_AS4 +	  support. +	* bgp_open.c: (peek_for_as4_capability) New, peek for AS4 +	  capability prior to full capability parsing, so we know which +	  ASN to use for struct peer lookup. +	  (bgp_open_capability) Always send AS4 capability. +	* bgp_packet.c: (bgp_open_send) AS4 handling for AS field +	  (bgp_open_receive) Peek for AS4 capability first, and figure +	  out which AS to believe. +	* bgp_vty.c: (bgp_show_peer) Print AS4 cap +  2007-09-17 Paul Jakma <paul.jakma@sun.com>  	* bgp_open.c: (bgp_capability_mp) We were setting diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index b328e38a..d7e985d4 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -28,15 +28,20 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "str.h"  #include "log.h"  #include "stream.h" +#include "jhash.h"  #include "bgpd/bgpd.h"  #include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_attr.h"  /* Attr. Flags and Attr. Type Code. */  #define AS_HEADER_SIZE        2	  -/* Two octet is used for AS value. */ +/* Now FOUR octets are used for AS value. */  #define AS_VALUE_SIZE         sizeof (as_t) +/* This is the old one */ +#define AS16_VALUE_SIZE	      sizeof (as16_t)  /* Maximum protocol segment length value */  #define AS_SEGMENT_MAX		255 @@ -46,16 +51,20 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA   * sizes and lengths.  At present (200508) they sort of match, however   * the ONLY functions which should now about the on-wire syntax are   * aspath_put, assegment_put and assegment_parse. + * + * aspath_put returns bytes written, the only definitive record of + * size of wire-format attribute..   */  /* Calculated size in bytes of ASN segment data to hold N ASN's */ -#define ASSEGMENT_DATA_SIZE(N) ((N) * AS_VALUE_SIZE) +#define ASSEGMENT_DATA_SIZE(N,S) \ +	((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )  /* Calculated size of segment struct to hold N ASN's */ -#define ASSEGMENT_SIZE(N)  (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N)) +#define ASSEGMENT_SIZE(N,S)  (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))  /* AS segment octet length. */ -#define ASSEGMENT_LEN(X) ASSEGMENT_SIZE((X)->length) +#define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)  /* AS_SEQUENCE segments can be packed together */  /* Can the types of X and Y be considered for packing? */ @@ -85,7 +94,7 @@ static struct stream *snmp_stream;  static inline as_t *  assegment_data_new (int num)  { -  return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num))); +  return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));  }  static inline void @@ -150,7 +159,7 @@ assegment_dup (struct assegment *seg)    struct assegment *new;    new = assegment_new (seg->type, seg->length); -  memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length) ); +  memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );    return new;  } @@ -197,7 +206,7 @@ assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)        for (i = 0; i < num; i++)          newas[i] = asnum; -      memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length)); +      memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));        XFREE (MTYPE_AS_SEG_DATA, seg->as);        seg->as = newas;         seg->length += num; @@ -215,12 +224,12 @@ assegment_append_asns (struct assegment *seg, as_t *asnos, int num)    as_t *newas;    newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as, -		      ASSEGMENT_DATA_SIZE (seg->length + num)); +		      ASSEGMENT_DATA_SIZE (seg->length + num, 1));    if (newas)      {        seg->as = newas; -      memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num)); +      memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));        seg->length += num;        return seg;      } @@ -263,7 +272,26 @@ assegment_normalise (struct assegment *head)         * and because it helps other lesser implementations ;)         */        if (seg->type == AS_SET || seg->type == AS_CONFED_SET) -        qsort (seg->as, seg->length, sizeof(as_t), int_cmp); +      	{ +	  int tail = 0; +	  int i; +	   +	  qsort (seg->as, seg->length, sizeof(as_t), int_cmp); +	   +	  /* weed out dupes */ +	  for (i=1; i < seg->length; i++) +	    { +	      if (seg->as[tail] == seg->as[i]) +	      	continue; +	       +	      tail++; +	      if (tail < i) +	      	seg->as[tail] = seg->as[i]; +	    } +	  /* seg->length can be 0.. */ +	  if (seg->length) +	    seg->length = tail + 1; +	}        /* read ahead from the current, pinned segment while the segments         * are packable/mergeable. Append all following packable segments @@ -420,6 +448,12 @@ aspath_count_hops (struct aspath *aspath)    return count;  } +/* Estimate size aspath /might/ take if encoded into an + * ASPATH attribute. + * + * This is a quick estimate, not definitive! aspath_put() + * may return a different number!! + */  unsigned int  aspath_size (struct aspath *aspath)  { @@ -428,7 +462,7 @@ aspath_size (struct aspath *aspath)    while (seg)      { -      size += ASSEGMENT_SIZE(seg->length); +      size += ASSEGMENT_SIZE(seg->length, 1);        seg = seg->next;      }    return size; @@ -454,6 +488,39 @@ aspath_highest (struct aspath *aspath)    return highest;  } +/* Return 1 if there are any 4-byte ASes in the path */ +unsigned int +aspath_has_as4 (struct aspath *aspath) +{ +  struct assegment *seg = aspath->segments; +  unsigned int i; +   +  while (seg) +    { +      for (i = 0; i < seg->length; i++) +        if (seg->as[i] > BGP_AS_MAX) +	  return 1; +      seg = seg->next; +    } +  return 0; +} + +/* Return number of as numbers in in path */ +unsigned int +aspath_count_numas (struct aspath *aspath) +{ +  struct assegment *seg = aspath->segments; +  unsigned int num; +   +  num=0; +  while (seg) +    { +      num += seg->length; +      seg = seg->next; +    } +  return num; +} +  /* Convert aspath structure to string expression. */  static char *  aspath_make_str_count (struct aspath *as) @@ -478,6 +545,9 @@ aspath_make_str_count (struct aspath *as)     * 2 chars for segment delimiters, and the final '\0'.     * Hopefully this is large enough to avoid hitting the realloc     * code below for most common sequences. +   * +   * With 32bit ASNs, this range will increase, but only worth changing +   * once there are significant numbers of ASN >= 100000     */  #define ASN_STR_LEN (5 + 1)    str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1, @@ -510,6 +580,9 @@ aspath_make_str_count (struct aspath *as)         * have been wrong.  need 5 chars for ASN, a seperator each and         * potentially two segment delimiters, plus a space between each         * segment and trailing zero. +       * +       * This may need to revised if/when significant numbers of +       * ASNs >= 100000 are assigned and in-use on the internet...         */  #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)        if ( (len + SEGMENT_STR_LEN(seg)) > str_size) @@ -605,7 +678,7 @@ aspath_hash_alloc (void *arg)  {    struct aspath *aspath; -  /* New aspath strucutre is needed. */ +  /* New aspath structure is needed. */    aspath = aspath_dup (arg);    /* Malformed AS path value. */ @@ -620,7 +693,7 @@ aspath_hash_alloc (void *arg)  /* parse as-segment byte stream in struct assegment */  static struct assegment * -assegments_parse (struct stream *s, size_t length) +assegments_parse (struct stream *s, size_t length, int use32bit)  {    struct assegment_header segh;    struct assegment *seg, *prev = NULL, *head = NULL; @@ -630,27 +703,37 @@ assegments_parse (struct stream *s, size_t length)    if (length == 0)      return NULL; +  if (BGP_DEBUG (as4, AS4_SEGMENT)) +    zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu", +		(unsigned long) length);    /* basic checks */    if ( (STREAM_READABLE(s) < length)        || (STREAM_READABLE(s) < AS_HEADER_SIZE)  -      || (length % AS_VALUE_SIZE)) +      || (length % AS16_VALUE_SIZE ))      return NULL;    while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)           && (bytes < length))      {        int i; +      int seg_size;        /* softly softly, get the header first on its own */        segh.type = stream_getc (s);        segh.length = stream_getc (s); +      seg_size = ASSEGMENT_SIZE(segh.length, use32bit); + +      if (BGP_DEBUG (as4, AS4_SEGMENT)) +	zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d", +                    segh.type, segh.length); +              /* check it.. */ -      if ( ((bytes + ASSEGMENT_SIZE(segh.length)) > length) +      if ( ((bytes + seg_size) > length)            /* 1771bis 4.3b: seg length contains one or more */            || (segh.length == 0)             /* Paranoia in case someone changes type of segment length */ -          || ((sizeof segh.length > 1) && segh.length > AS_SEGMENT_MAX)) +          || ((sizeof segh.length > 1) && (segh.length > AS_SEGMENT_MAX)) )          {            if (head)              assegment_free_all (head); @@ -666,9 +749,13 @@ assegments_parse (struct stream *s, size_t length)          head = prev = seg;        for (i = 0; i < segh.length; i++) -        seg->as[i] = stream_getw (s); +	seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s); + +      bytes += seg_size; -      bytes += ASSEGMENT_SIZE(segh.length); +      if (BGP_DEBUG (as4, AS4_SEGMENT)) +	zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu", +	            (unsigned long) bytes);        prev = seg;      } @@ -680,16 +767,22 @@ assegments_parse (struct stream *s, size_t length)     is length of byte stream.  If there is same AS path in the the AS     path hash then return it else make new AS path structure. */  struct aspath * -aspath_parse (struct stream *s, size_t length) +aspath_parse (struct stream *s, size_t length, int use32bit)  {    struct aspath as;    struct aspath *find;    /* If length is odd it's malformed AS path. */ -  if (length % AS_VALUE_SIZE) +  /* Nit-picking: if (use32bit == 0) it is malformed if odd, +   * otherwise its malformed when length is larger than 2 and (length-2)  +   * is not dividable by 4. +   * But... this time we're lazy +   */ +  if (length % AS16_VALUE_SIZE )      return NULL; -  as.segments = assegments_parse (s, length); +  memset (&as, 0, sizeof (struct aspath)); +  as.segments = assegments_parse (s, length, use32bit);    /* If already same aspath exist then return it. */    find = hash_get (ashash, &as, aspath_hash_alloc); @@ -698,6 +791,8 @@ aspath_parse (struct stream *s, size_t length)     * optimised out.     */    assegment_free_all (as.segments); +  if (as.str) +    XFREE (MTYPE_AS_STR, as.str);    if (! find)      return NULL; @@ -707,13 +802,21 @@ aspath_parse (struct stream *s, size_t length)  }  static inline void -assegment_data_put (struct stream *s, as_t *as, int num) +assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)  {    int i;    assert (num <= AS_SEGMENT_MAX);    for (i = 0; i < num; i++) -    stream_putw (s, as[i]); +    if ( use32bit ) +      stream_putl (s, as[i]); +    else +      { +        if ( as[i] <= BGP_AS_MAX ) +	  stream_putw(s, as[i]); +	else +	  stream_putw(s, BGP_AS_TRANS); +      }  }  static inline size_t @@ -728,38 +831,51 @@ assegment_header_put (struct stream *s, u_char type, int length)  }  /* write aspath data to stream */ -void -aspath_put (struct stream *s, struct aspath *as) +size_t +aspath_put (struct stream *s, struct aspath *as, int use32bit )  {    struct assegment *seg = as->segments; +  size_t bytes = 0;    if (!seg || seg->length == 0) -    return; +    return 0;    if (seg)      { -      while (seg && (ASSEGMENT_LEN (seg) <= STREAM_WRITEABLE(s))) +      /* +       * Hey, what do we do when we have > STREAM_WRITABLE(s) here? +       * At the moment, we would write out a partial aspath, and our peer +       * will complain and drop the session :-/ +       * +       * The general assumption here is that many things tested will +       * never happen.  And, in real live, up to now, they have not. +       */ +      while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))          { +          struct assegment *next = seg->next;            int written = 0; +          int asns_packed = 0;            size_t lenp;            /* Overlength segments have to be split up */            while ( (seg->length - written) > AS_SEGMENT_MAX)              {                assegment_header_put (s, seg->type, AS_SEGMENT_MAX); -              assegment_data_put (s, seg->as, AS_SEGMENT_MAX); +              assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);                written += AS_SEGMENT_MAX; +              bytes += ASSEGMENT_SIZE (written, use32bit);              }            /* write the final segment, probably is also the first */            lenp = assegment_header_put (s, seg->type, seg->length - written); -          assegment_data_put (s, (seg->as + written), seg->length - written); +          assegment_data_put (s, (seg->as + written), seg->length - written,  +                              use32bit);            /* Sequence-type segments can be 'packed' together             * Case of a segment which was overlength and split up             * will be missed here, but that doesn't matter.             */ -          if (seg->next && ASSEGMENTS_PACKABLE (seg, seg->next)) +          while (next && ASSEGMENTS_PACKABLE (seg, next))              {                /* NB: We should never normally get here given we                 * normalise aspath data when parse them. However, better @@ -771,17 +887,21 @@ aspath_put (struct stream *s, struct aspath *as)                 */                /* Next segment's data can fit in this one */ -              assegment_data_put (s, seg->next->as, seg->next->length); +              assegment_data_put (s, next->as, next->length, use32bit);                /* update the length of the segment header */ -	      stream_putc_at (s, lenp,  -	                      seg->length - written + seg->next->length); -	      seg = seg->next->next; /* skip to past next */ +	      stream_putc_at (s, lenp, seg->length - written + next->length); +              asns_packed += next->length; +                +	      next = next->next;  	    } -          else -            seg = seg->next; +           +          bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,  +				   use32bit); +          seg = next;          }      } +  return bytes;  }  /* This is for SNMP BGP4PATHATTRASPATHSEGMENT @@ -803,7 +923,7 @@ aspath_snmp_pathseg (struct aspath *as, size_t *varlen)        *varlen = 0;        return NULL;      } -  aspath_put (snmp_stream, as); +  aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */    *varlen = stream_get_endp (snmp_stream);    return stream_pnt(snmp_stream); @@ -861,8 +981,9 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)    int from;    struct assegment *seg1 = as1->segments;    struct assegment *seg2 = as2->segments; -  struct aspath *aspath; +  struct aspath *aspath = NULL;    struct assegment *asset; +  struct assegment *prevseg = NULL;    match = 0;    minlen = 0; @@ -871,7 +992,7 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)    /* First of all check common leading sequence. */    while (seg1 && seg2) -    { +    {              /* Check segment type. */        if (seg1->type != seg2->type)  	break; @@ -885,11 +1006,19 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)        if (match)  	{ +	  struct assegment *seg = assegment_new (seg1->type, 0); +	   +	  seg = assegment_append_asns (seg, seg1->as, match); +  	  if (! aspath) -	    aspath = aspath_new (); -	  aspath->segments = assegment_new (seg1->type, 0); -	  aspath->segments = assegment_append_asns (aspath->segments,  -	                                            seg1->as, match); +	    { +	      aspath = aspath_new (); +	      aspath->segments = seg; +	     } +	  else +	    prevseg->next = seg; +	   +	  prevseg = seg;  	}        if (match != minlen || match != seg1->length  @@ -1174,6 +1303,108 @@ aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)    return 0;  } +/* Truncate an aspath after a number of hops, and put the hops remaining + * at the front of another aspath.  Needed for AS4 compat. + * + * Returned aspath is a /new/ aspath, which should either by free'd or + * interned by the caller, as desired. + */ +struct aspath * +aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path) +{ +  struct assegment *seg, *newseg, *prevseg = NULL; +  struct aspath *newpath = NULL, *mergedpath; +  int hops, cpasns = 0; +   +  if (!aspath) +    return NULL; +   +  seg = aspath->segments; +   +  /* CONFEDs should get reconciled too.. */ +  hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath)) +         - aspath_count_hops (as4path); +   +  if (hops < 0) +    { +      if (BGP_DEBUG (as4, AS4)) +        zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH"); +      /* Something's gone wrong. The RFC says we should now ignore AS4_PATH, +       * which is daft behaviour - it contains vital loop-detection +       * information which must have been removed from AS_PATH. +       */ +       hops = aspath_count_hops (aspath); +    } +   +  if (!hops) +   return aspath_dup (as4path); +   +  if ( BGP_DEBUG(as4, AS4)) +    zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now", +               aspath->str, as4path->str); + +  while (seg && hops > 0) +    { +      switch (seg->type) +        { +          case AS_SET: +          case AS_CONFED_SET: +            hops--; +            cpasns = seg->length; +            break; +          case AS_CONFED_SEQUENCE: +	    /* Should never split a confed-sequence, if hop-count +	     * suggests we must then something's gone wrong somewhere. +	     * +	     * Most important goal is to preserve AS_PATHs prime function +	     * as loop-detector, so we fudge the numbers so that the entire +	     * confed-sequence is merged in. +	     */ +	    if (hops < seg->length) +	      { +	        if (BGP_DEBUG (as4, AS4)) +	          zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls" +	                      " across 2/4 ASN boundary somewhere, broken.."); +	        hops = seg->length; +	      } +	  case AS_SEQUENCE: +	    cpasns = MIN(seg->length, hops); +	    hops -= seg->length; +	} +       +      assert (cpasns <= seg->length); +       +      newseg = assegment_new (seg->type, 0); +      newseg = assegment_append_asns (newseg, seg->as, cpasns); + +      if (!newpath) +        { +          newpath = aspath_new (); +          newpath->segments = newseg; +        } +      else +        prevseg->next = newseg; + +      prevseg = newseg; +      seg = seg->next; +    } +     +  /* We may be able to join some segments here, and we must +   * do this because... we want normalised aspaths in out hash +   * and we do not want to stumble in aspath_put. +   */ +  mergedpath = aspath_merge (newpath, aspath_dup(as4path)); +  aspath_free (newpath); +  mergedpath->segments = assegment_normalise (mergedpath->segments); +  aspath_str_update (mergedpath); +   +  if ( BGP_DEBUG(as4, AS4)) +    zlog_debug ("[AS4] result of synthesizing is %s", +                mergedpath->str); +   +  return mergedpath; +} +  /* Compare leftmost AS value for MED check.  If as1's leftmost AS and     as2's leftmost AS is same return 1. (confederation as-path     only).  */ @@ -1273,7 +1504,7 @@ aspath_segment_add (struct aspath *as, int type)  struct aspath *  aspath_empty (void)  { -  return aspath_parse (NULL, 0); +  return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */  }  struct aspath * @@ -1316,7 +1547,7 @@ enum as_token  /* Return next token and point for string parse. */  static const char * -aspath_gettoken (const char *buf, enum as_token *token, u_short *asno) +aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)  {    const char *p = buf; @@ -1360,16 +1591,17 @@ aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)    if (isdigit ((int) *p))       {        u_short asval; - +              *token = as_token_asval;        asval = (*p - '0');        p++; +              while (isdigit ((int) *p))  -	{ -	  asval *= 10; -	  asval += (*p - '0'); -	  p++; -	} +        { +          asval *= 10; +          asval += (*p - '0'); +          p++; +        }        *asno = asval;        return p;      } @@ -1384,7 +1616,7 @@ aspath_str2aspath (const char *str)  {    enum as_token token = as_token_unknown;    u_short as_type; -  u_short asno = 0; +  u_long asno = 0;    struct aspath *aspath;    int needtype; @@ -1451,24 +1683,11 @@ aspath_key_make (void *p)  {    struct aspath * aspath = (struct aspath *) p;    unsigned int key = 0; -  unsigned int i; -  struct assegment *seg = aspath->segments; -  struct assegment *prev = NULL; -  while (seg) -    { -      /* segment types should be part of the hash -       * otherwise seq(1) and set(1) will hash to same value -       */ -      if (!(prev && seg->type == AS_SEQUENCE && seg->type == prev->type)) -        key += seg->type; -       -      for (i = 0; i < seg->length; i++) -	key += seg->as[i]; -       -      prev = seg; -      seg = seg->next; -    } +  if (!aspath->str) +    aspath_str_update (aspath); +   +  key = jhash (aspath->str, strlen(aspath->str), 2334325);    return key;  } diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index efec24c2..3bb616f7 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -31,7 +31,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #define BGP_PRIVATE_AS_MIN       64512U  #define BGP_PRIVATE_AS_MAX       65535U -#define BGP_AS_MAX		 65535U +/* we leave BGP_AS_MAX as the 16bit AS MAX number.  */ +#define BGP_AS_MAX		     65535U +#define BGP_AS4_MAX		4294967295U +/* Transition 16Bit AS as defined by IANA */ +#define BGP_AS_TRANS		 23456U  /* AS_PATH segment data in abstracted form, no limit is placed on length */  struct assegment @@ -61,7 +65,7 @@ struct aspath  /* Prototypes. */  extern void aspath_init (void);  extern void aspath_finish (void); -extern struct aspath *aspath_parse (struct stream *, size_t); +extern struct aspath *aspath_parse (struct stream *, size_t, int);  extern struct aspath *aspath_dup (struct aspath *);  extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *);  extern struct aspath *aspath_prepend (struct aspath *, struct aspath *); @@ -88,7 +92,11 @@ extern unsigned int aspath_count_hops (struct aspath *);  extern unsigned int aspath_count_confeds (struct aspath *);  extern unsigned int aspath_size (struct aspath *);  extern as_t aspath_highest (struct aspath *); -extern void aspath_put (struct stream *, struct aspath *); +extern size_t aspath_put (struct stream *, struct aspath *, int); + +extern struct aspath *aspath_reconcile_as4 (struct aspath *, struct aspath *); +extern unsigned int aspath_has_as4 (struct aspath *); +extern unsigned int aspath_count_numas (struct aspath *);  /* For SNMP BGP4PATHATTRASPATHSEGMENT, might be useful for debug */  extern u_char *aspath_snmp_pathseg (struct aspath *, size_t *); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 9d13ca6e..b463b3c0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -56,8 +56,10 @@ static struct message attr_str [] =    { BGP_ATTR_RCID_PATH,        "RCID_PATH" },    { BGP_ATTR_MP_REACH_NLRI,    "MP_REACH_NLRI" },    { BGP_ATTR_MP_UNREACH_NLRI,  "MP_UNREACH_NLRI" }, -  { BGP_ATTR_EXT_COMMUNITIES,  "BGP_ATTR_EXT_COMMUNITIES" }, -  { BGP_ATTR_AS_PATHLIMIT,     "BGP_ATTR_AS_PATHLIMIT" }, +  { BGP_ATTR_EXT_COMMUNITIES,  "EXT_COMMUNITIES" }, +  { BGP_ATTR_AS4_PATH,         "AS4_PATH" },  +  { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" },  +  { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },    { 0, NULL }  };  int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); @@ -794,8 +796,6 @@ static int  bgp_attr_aspath (struct peer *peer, bgp_size_t length,   		 struct attr *attr, u_char flag, u_char *startp)  { -  struct bgp *bgp; -  struct aspath *aspath;    bgp_size_t total;    total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); @@ -813,8 +813,14 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,        return -1;      } +  /* +   * peer with AS4 => will get 4Byte ASnums +   * otherwise, will get 16 Bit +   */ +  attr->aspath = aspath_parse (peer->ibuf, length,  +                               CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)); +    /* In case of IBGP, length will be zero. */ -  attr->aspath = aspath_parse (peer->ibuf, length);    if (! attr->aspath)      {        zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); @@ -824,6 +830,28 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,        return -1;      } +  /* Forward pointer. */ +/*  stream_forward_getp (peer->ibuf, length);*/ + +  /* Set aspath attribute flag. */ +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + +  return 0; +} + +static int bgp_attr_aspath_check( struct peer *peer,  +		struct attr *attr) +{ +  /* These checks were part of bgp_attr_aspath, but with +   * as4 we should to check aspath things when +   * aspath synthesizing with as4_path has already taken place. +   * Otherwise we check ASPATH and use the synthesized thing, and that is +   * not right. +   * So do the checks later, i.e. here +   */ +  struct bgp *bgp = peer->bgp; +  struct aspath *aspath; +    bgp = peer->bgp;    /* First AS check for EBGP. */ @@ -851,11 +879,20 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,        attr->aspath = aspath_intern (aspath);      } -  /* Forward pointer. */ -/*  stream_forward_getp (peer->ibuf, length);*/ +  return 0; + +} + +/* Parse AS4 path information.  This function is another wrapper of +   aspath_parse. */ +static int +bgp_attr_as4_path (struct peer *peer, bgp_size_t length,  +		 struct attr *attr, struct aspath **as4_path) +{ +  *as4_path = aspath_parse (peer->ibuf, length, 1);    /* Set aspath attribute flag. */ -  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);    return 0;  } @@ -981,18 +1018,27 @@ static int  bgp_attr_aggregator (struct peer *peer, bgp_size_t length,  		     struct attr *attr, u_char flag)  { +  int wantedlen = 6;    struct attr_extra *attre = bgp_attr_extra_get (attr); -  if (length != 6) +  /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ +  if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) +    wantedlen = 8; +   +  if (length != wantedlen)      { -      zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length); +      zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);        bgp_notify_send (peer,  		       BGP_NOTIFY_UPDATE_ERR,  		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);        return -1;      } -  attre->aggregator_as = stream_getw (peer->ibuf); +   +  if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) +    attre->aggregator_as = stream_getl (peer->ibuf); +  else +    attre->aggregator_as = stream_getw (peer->ibuf);    attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);    /* Set atomic aggregate flag. */ @@ -1001,6 +1047,145 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,    return 0;  } +/* New Aggregator attribute */ +static int +bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, +		     struct attr *attr, as_t *as4_aggregator_as, +		     struct in_addr *as4_aggregator_addr) +{ +  if (length != 8) +    { +      zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); + +      bgp_notify_send (peer, +		       BGP_NOTIFY_UPDATE_ERR, +		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +      return -1; +    } +  *as4_aggregator_as = stream_getl (peer->ibuf); +  as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); + +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR); + +  return 0; +} + +/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. + */ +static int +bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, +                          struct aspath *as4_path, as_t as4_aggregator, +                          struct in_addr *as4_aggregator_addr) +{ +  int ignore_as4_path = 0; +  struct aspath *newpath; +  struct attr_extra *attre = attr->extra; +     +  if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) ) +    { +      /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR +       * if given. +       * It is worth a warning though, because the peer really +       * should not send them +       */ +      if (BGP_DEBUG(as4, AS4)) +        { +          if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))) +            zlog_debug ("[AS4] %s %s AS4_PATH", +                        peer->host, "AS4 capable peer, yet it sent"); +           +          if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) +            zlog_debug ("[AS4] %s %s AS4_AGGREGATOR", +                        peer->host, "AS4 capable peer, yet it sent"); +        } +       +      return 0; +    } +   +  if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)) +      && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))) +    { +      /* Hu? This is not supposed to happen at all! +       * got as4_path and no aspath, +       *   This should already +       *   have been handled by 'well known attributes missing' +       *   But... yeah, paranoia +       * Take this as a "malformed attribute" +       */ +      zlog (peer->log, LOG_ERR,  +            "%s BGP not AS4 capable peer sent AS4_PATH but" +            " no AS_PATH, cant do anything here", peer->host); +      bgp_notify_send (peer,  +                       BGP_NOTIFY_UPDATE_ERR,  +                       BGP_NOTIFY_UPDATE_MAL_ATTR); +      return -1; +    } + +  /* We have a asn16 peer.  First, look for AS4_AGGREGATOR +   * because that may override AS4_PATH +   */ +  if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) ) +    { +      assert (attre); +       +      if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) +        { +          /* received both. +           * if the as_number in aggregator is not AS_TRANS, +           *  then AS4_AGGREGATOR and AS4_PATH shall be ignored +           *        and the Aggregator shall be taken as  +           *        info on the aggregating node, and the AS_PATH +           *        shall be taken as the AS_PATH +           *  otherwise +           *        the Aggregator shall be ignored and the +           *        AS4_AGGREGATOR shall be taken as the +           *        Aggregating node and the AS_PATH is to be +           *        constructed "as in all other cases" +           */ +          if ( attre->aggregator_as != BGP_AS_TRANS ) +            { +              /* ignore */ +              if ( BGP_DEBUG(as4, AS4)) +                zlog_debug ("[AS4] %s BGP not AS4 capable peer"  +                            " send AGGREGATOR != AS_TRANS and" +                            " AS4_AGGREGATOR, so ignore" +                            " AS4_AGGREGATOR and AS4_PATH", peer->host); +              ignore_as4_path = 1; +            } +          else +            { +              /* "New_aggregator shall be taken as aggregator" */ +              attre->aggregator_as = as4_aggregator; +              attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr; +            } +        } +      else +        { +          /* We received a AS4_AGGREGATOR but no AGGREGATOR. +           * That is bogus - but reading the conditions +           * we have to handle AS4_AGGREGATOR as if it were +           * AGGREGATOR in that case +           */ +          if ( BGP_DEBUG(as4, AS4)) +            zlog_debug ("[AS4] %s BGP not AS4 capable peer send" +                        " AS4_AGGREGATOR but no AGGREGATOR, will take" +                        " it as if AGGREGATOR with AS_TRANS had been there", peer->host); +          attre->aggregator_as = as4_aggregator; +          /* sweep it under the carpet and simulate a "good" AGGREGATOR */ +          attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)); +        } +    } + +  /* need to reconcile NEW_AS_PATH and AS_PATH */ +  if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) ) +    { +       newpath = aspath_reconcile_as4 (attr->aspath, as4_path); +       aspath_unintern (attr->aspath); +       attr->aspath = aspath_intern (newpath); +    } +  return 0; +} +  /* Community attribute. */  static int  bgp_attr_community (struct peer *peer, bgp_size_t length,  @@ -1318,11 +1503,16 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  {    int ret;    u_char flag; -  u_char type; +  u_char type = 0;    bgp_size_t length;    u_char *startp, *endp;    u_char *attr_endp;    u_char seen[BGP_ATTR_BITMAP_SIZE]; +  /* we need the as4_path only until we have synthesized the as_path with it */ +  /* same goes for as4_aggregator */ +  struct aspath *as4_path = NULL; +  as_t as4_aggregator = 0; +  struct in_addr as4_aggregator_addr = { 0 };    /* Initialize bitmap. */    memset (seen, 0, BGP_ATTR_BITMAP_SIZE); @@ -1339,7 +1529,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  	  /* XXX warning: long int format, int arg (arg 5) */  	  zlog (peer->log, LOG_WARNING,   		"%s error BGP attribute length %lu is smaller than min len", -		peer->host, endp - STREAM_PNT (BGP_INPUT (peer))); +		peer->host, +		(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));  	  bgp_notify_send (peer,   			   BGP_NOTIFY_UPDATE_ERR,  @@ -1401,6 +1592,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  	case BGP_ATTR_AS_PATH:  	  ret = bgp_attr_aspath (peer, length, attr, flag, startp);  	  break; +	case BGP_ATTR_AS4_PATH: +	  ret = bgp_attr_as4_path (peer, length, attr, &as4_path ); +	  break;  	case BGP_ATTR_NEXT_HOP:	  	  ret = bgp_attr_nexthop (peer, length, attr, flag, startp);  	  break; @@ -1416,6 +1610,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  	case BGP_ATTR_AGGREGATOR:  	  ret = bgp_attr_aggregator (peer, length, attr, flag);  	  break; +	case BGP_ATTR_AS4_AGGREGATOR: +	  ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr); +	  break;  	case BGP_ATTR_COMMUNITIES:  	  ret = bgp_attr_community (peer, length, attr, flag);  	  break; @@ -1480,6 +1677,51 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,        return -1;      } +  /*  +   * At this place we can see whether we got AS4_PATH and/or +   * AS4_AGGREGATOR from a 16Bit peer and act accordingly. +   * We can not do this before we've read all attributes because +   * the as4 handling does not say whether AS4_PATH has to be sent +   * after AS_PATH or not - and when AS4_AGGREGATOR will be send +   * in relationship to AGGREGATOR. +   * So, to be defensive, we are not relying on any order and read +   * all attributes first, including these 32bit ones, and now, +   * afterwards, we look what and if something is to be done for as4. +   */ +  if (bgp_attr_munge_as4_attrs (peer, attr, as4_path, +                                as4_aggregator, &as4_aggregator_addr)) +    return -1; + +  /* At this stage, we have done all fiddling with as4, and the +   * resulting info is in attr->aggregator resp. attr->aspath +   * so we can chuck as4_aggregator and as4_path alltogether in +   * order to save memory +   */ +  if ( as4_path ) +    { +      aspath_unintern( as4_path ); /* unintern - it is in the hash */ +      as4_path = NULL; +      /* The flag that we got this is still there, but that does not +       * do any trouble +       */ +    } +  /* +   * The "rest" of the code does nothing with as4_aggregator. +   * there is no memory attached specifically which is not part +   * of the attr. +   * so ignoring just means do nothing. +   */ +  /* +   * Finally do the checks on the aspath we did not do yet +   * because we waited for a potentially synthesized aspath. +   */ +  if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))) +    { +      ret = bgp_attr_aspath_check( peer, attr ); +      if ( ret < 0 ) +	return ret; +    } +    /* Finally intern unknown attribute. */    if (attr->extra && attr->extra->transit)      attr->extra->transit = transit_intern (attr->extra->transit); @@ -1530,8 +1772,11 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,  		      struct prefix_rd *prd, u_char *tag)  {    size_t cp; -  unsigned int aspath_data_size; +  size_t aspath_sizep;    struct aspath *aspath; +  int send_as4_path = 0; +  int send_as4_aggregator = 0; +  int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;    if (! bgp)      bgp = bgp_get_default (); @@ -1578,25 +1823,27 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,    else      aspath = attr->aspath; -  /* AS path attribute extended length bit check. */ -  aspath_data_size = aspath_size (aspath); -  if (aspath_data_size > 255) -    { -      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); -      stream_putc (s, BGP_ATTR_AS_PATH); -      stream_putw (s, aspath_data_size); -    } -  else -    { -      stream_putc (s, BGP_ATTR_FLAG_TRANS); -      stream_putc (s, BGP_ATTR_AS_PATH); -      stream_putc (s, aspath_data_size); -    } -  aspath_put (s, aspath); - -  if (aspath != attr->aspath) -    aspath_free (aspath); - +  /* If peer is not AS4 capable, then: +   * - send the created AS_PATH out as AS4_PATH (optional, transitive), +   *   but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment +   *   types are in it (i.e. exclude them if they are there) +   *   AND do this only if there is at least one asnum > 65535 in the path! +   * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change +   *   all ASnums > 65535 to BGP_AS_TRANS +   */ + +  stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); +  stream_putc (s, BGP_ATTR_AS_PATH); +  aspath_sizep = stream_get_endp (s); +  stream_putw (s, 0); +  stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit)); +   +  /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs  +   * in the path +   */ +  if (!use32bit && aspath_has_as4 (aspath)) +      send_as4_path = 1; /* we'll do this later, at the correct place */ +      /* Nexthop attribute. */    if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)      { @@ -1645,10 +1892,36 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,    if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))      {        assert (attr->extra); +       +      /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */        stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);        stream_putc (s, BGP_ATTR_AGGREGATOR); -      stream_putc (s, 6); -      stream_putw (s, attr->extra->aggregator_as); +       +      if (use32bit) +        { +          /* AS4 capable peer */ +          stream_putc (s, 8); +          stream_putl (s, attr->extra->aggregator_as); +        } +      else +        { +          /* 2-byte AS peer */ +          stream_putc (s, 6); +           +          /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */ +          if ( attr->extra->aggregator_as > 65535 ) +            { +              stream_putw (s, BGP_AS_TRANS); +               +              /* we have to send AS4_AGGREGATOR, too. +               * we'll do that later in order to send attributes in ascending +               * order. +               */ +              send_as4_aggregator = 1; +            } +          else +            stream_putw (s, (u_int16_t) attr->extra->aggregator_as); +        }        stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);      } @@ -1873,6 +2146,47 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,  	    }  	}      } + +  if ( send_as4_path ) +    { +      /* If the peer is NOT As4 capable, AND */ +      /* there are ASnums > 65535 in path  THEN +       * give out AS4_PATH */ + +      /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET +       * path segments! +       * Hm, I wonder...  confederation things *should* only be at +       * the beginning of an aspath, right?  Then we should use +       * aspath_delete_confed_seq for this, because it is already +       * there! (JK)  +       * Folks, talk to me: what is reasonable here!? +       */ +      aspath = aspath_delete_confed_seq (aspath); + +      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); +      stream_putc (s, BGP_ATTR_AS4_PATH); +      aspath_sizep = stream_get_endp (s); +      stream_putw (s, 0); +      stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1)); +    } + +  if (aspath != attr->aspath) +    aspath_free (aspath); + +  if ( send_as4_aggregator )  +    { +      assert (attr->extra); + +      /* send AS4_AGGREGATOR, at this place */ +      /* this section of code moved here in order to ensure the correct +       * *ascending* order of attributes +       */ +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); +      stream_putc (s, BGP_ATTR_AS4_AGGREGATOR); +      stream_putc (s, 8); +      stream_putl (s, attr->extra->aggregator_as); +      stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); +    }    /* AS-Pathlimit */    if (attr->pathlimit.ttl) @@ -1967,7 +2281,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,  {    unsigned long cp;    unsigned long len; -  unsigned int aspathlen; +  size_t aspath_lenp;    struct aspath *aspath;    /* Remember current pointer. */ @@ -1983,20 +2297,13 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,    stream_putc (s, attr->origin);    aspath = attr->aspath; - -  if ( (aspathlen = aspath_size (aspath)) > 255 ) -    { -      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); -      stream_putc (s, BGP_ATTR_AS_PATH); -      stream_putw (s, aspathlen); -    } -  else -    { -      stream_putc (s, BGP_ATTR_FLAG_TRANS); -      stream_putc (s, BGP_ATTR_AS_PATH); -      stream_putc (s, aspathlen); -    } -  aspath_put (s, aspath); +   +  stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); +  stream_putc (s, BGP_ATTR_AS_PATH); +  aspath_lenp = stream_get_endp (s); +  stream_putw (s, 0); +   +  stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));    /* Nexthop attribute. */    /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */ @@ -2044,8 +2351,8 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,        assert (attr->extra);        stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);        stream_putc (s, BGP_ATTR_AGGREGATOR); -      stream_putc (s, 6); -      stream_putw (s, attr->extra->aggregator_as); +      stream_putc (s, 8); +      stream_putl (s, attr->extra->aggregator_as);        stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);      } diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 60284a2d..acb1de7f 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgp_debug.h"  #include "bgpd/bgp_community.h" +unsigned long conf_bgp_debug_as4;  unsigned long conf_bgp_debug_fsm;  unsigned long conf_bgp_debug_events;  unsigned long conf_bgp_debug_packet; @@ -45,6 +46,7 @@ unsigned long conf_bgp_debug_update;  unsigned long conf_bgp_debug_normal;  unsigned long conf_bgp_debug_zebra; +unsigned long term_bgp_debug_as4;  unsigned long term_bgp_debug_fsm;  unsigned long term_bgp_debug_events;  unsigned long term_bgp_debug_packet; @@ -297,6 +299,92 @@ debug (unsigned int option)    return bgp_debug_option & option;   } +DEFUN (debug_bgp_as4, +       debug_bgp_as4_cmd, +       "debug bgp as4", +       DEBUG_STR +       BGP_STR +       "BGP AS4 actions\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_ON (as4, AS4); +  else +    { +      TERM_DEBUG_ON (as4, AS4); +      vty_out (vty, "BGP as4 debugging is on%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_as4, +       no_debug_bgp_as4_cmd, +       "no debug bgp as4", +       NO_STR +       DEBUG_STR +       BGP_STR +       "BGP AS4 actions\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_OFF (as4, AS4); +  else +    { +      TERM_DEBUG_OFF (as4, AS4); +      vty_out (vty, "BGP as4 debugging is off%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_as4, +       undebug_bgp_as4_cmd, +       "undebug bgp as4", +       UNDEBUG_STR +       DEBUG_STR +       BGP_STR +       "BGP AS4 actions\n") + +DEFUN (debug_bgp_as4_segment, +       debug_bgp_as4_segment_cmd, +       "debug bgp as4 segment", +       DEBUG_STR +       BGP_STR +       "BGP AS4 aspath segment handling\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_ON (as4, AS4_SEGMENT); +  else +    { +      TERM_DEBUG_ON (as4, AS4_SEGMENT); +      vty_out (vty, "BGP as4 segment debugging is on%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_as4_segment, +       no_debug_bgp_as4_segment_cmd, +       "no debug bgp as4 segment", +       NO_STR +       DEBUG_STR +       BGP_STR +       "BGP AS4 aspath segment handling\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_OFF (as4, AS4_SEGMENT); +  else +    { +      TERM_DEBUG_OFF (as4, AS4_SEGMENT); +      vty_out (vty, "BGP as4 segment debugging is off%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_as4_segment, +       undebug_bgp_as4_segment_cmd, +       "undebug bgp as4 segment", +       UNDEBUG_STR +       DEBUG_STR +       BGP_STR +       "BGP AS4 aspath segment handling\n") +  DEFUN (debug_bgp_fsm,         debug_bgp_fsm_cmd,         "debug bgp fsm", @@ -651,6 +739,8 @@ DEFUN (no_debug_bgp_all,    TERM_DEBUG_OFF (keepalive, KEEPALIVE);    TERM_DEBUG_OFF (update, UPDATE_IN);    TERM_DEBUG_OFF (update, UPDATE_OUT); +  TERM_DEBUG_OFF (as4, AS4); +  TERM_DEBUG_OFF (as4, AS4_SEGMENT);    TERM_DEBUG_OFF (fsm, FSM);    TERM_DEBUG_OFF (filter, FILTER);    TERM_DEBUG_OFF (zebra, ZEBRA); @@ -693,6 +783,10 @@ DEFUN (show_debugging_bgp,      vty_out (vty, "  BGP filter debugging is on%s", VTY_NEWLINE);    if (BGP_DEBUG (zebra, ZEBRA))      vty_out (vty, "  BGP zebra debugging is on%s", VTY_NEWLINE); +  if (BGP_DEBUG (as4, AS4)) +    vty_out (vty, "  BGP as4 debugging is on%s", VTY_NEWLINE); +  if (BGP_DEBUG (as4, AS4_SEGMENT)) +    vty_out (vty, "  BGP as4 aspath segment debugging is on%s", VTY_NEWLINE);    vty_out (vty, "%s", VTY_NEWLINE);    return CMD_SUCCESS;  } @@ -708,6 +802,18 @@ bgp_config_write_debug (struct vty *vty)        write++;      } +  if (CONF_BGP_DEBUG (as4, AS4)) +    { +      vty_out (vty, "debug bgp as4%s", VTY_NEWLINE); +      write++; +    } + +  if (CONF_BGP_DEBUG (as4, AS4_SEGMENT)) +    { +      vty_out (vty, "debug bgp as4 segment%s", VTY_NEWLINE); +      write++; +    } +    if (CONF_BGP_DEBUG (events, EVENTS))      {        vty_out (vty, "debug bgp events%s", VTY_NEWLINE); @@ -771,6 +877,11 @@ bgp_debug_init (void)    install_element (ENABLE_NODE, &show_debugging_bgp_cmd); +  install_element (ENABLE_NODE, &debug_bgp_as4_cmd); +  install_element (CONFIG_NODE, &debug_bgp_as4_cmd); +  install_element (ENABLE_NODE, &debug_bgp_as4_segment_cmd); +  install_element (CONFIG_NODE, &debug_bgp_as4_segment_cmd); +    install_element (ENABLE_NODE, &debug_bgp_fsm_cmd);    install_element (CONFIG_NODE, &debug_bgp_fsm_cmd);    install_element (ENABLE_NODE, &debug_bgp_events_cmd); @@ -788,6 +899,13 @@ bgp_debug_init (void)    install_element (ENABLE_NODE, &debug_bgp_zebra_cmd);    install_element (CONFIG_NODE, &debug_bgp_zebra_cmd); +  install_element (ENABLE_NODE, &no_debug_bgp_as4_cmd); +  install_element (ENABLE_NODE, &undebug_bgp_as4_cmd); +  install_element (CONFIG_NODE, &no_debug_bgp_as4_cmd); +  install_element (ENABLE_NODE, &no_debug_bgp_as4_segment_cmd); +  install_element (ENABLE_NODE, &undebug_bgp_as4_segment_cmd); +  install_element (CONFIG_NODE, &no_debug_bgp_as4_segment_cmd); +    install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd);    install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd);    install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd); diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 7015cb77..71e110ce 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #ifndef _QUAGGA_BGP_DEBUG_H  #define _QUAGGA_BGP_DEBUG_H +#include "bgp_attr.h" +  /* sort of packet direction */  #define DUMP_ON        1  #define DUMP_SEND      2 @@ -56,6 +58,7 @@ extern void bgp_packet_dump (struct stream *);  extern int debug (unsigned int option); +extern unsigned long conf_bgp_debug_as4;  extern unsigned long conf_bgp_debug_fsm;  extern unsigned long conf_bgp_debug_events;  extern unsigned long conf_bgp_debug_packet; @@ -65,6 +68,7 @@ extern unsigned long conf_bgp_debug_update;  extern unsigned long conf_bgp_debug_normal;  extern unsigned long conf_bgp_debug_zebra; +extern unsigned long term_bgp_debug_as4;  extern unsigned long term_bgp_debug_fsm;  extern unsigned long term_bgp_debug_events;  extern unsigned long term_bgp_debug_packet; @@ -74,6 +78,9 @@ extern unsigned long term_bgp_debug_update;  extern unsigned long term_bgp_debug_normal;  extern unsigned long term_bgp_debug_zebra; +#define BGP_DEBUG_AS4                 0x01 +#define BGP_DEBUG_AS4_SEGMENT         0x02 +  #define BGP_DEBUG_FSM                 0x01  #define BGP_DEBUG_EVENTS              0x01  #define BGP_DEBUG_PACKET              0x01 diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 601ff2b2..e815ea3c 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "command.h"  #include "prefix.h"  #include "thread.h" +#include "linklist.h"  #include "bgpd/bgp_table.h"  #include "bgpd/bgpd.h" @@ -53,7 +54,8 @@ enum MRT_MSG_TYPES {     MSG_PROTOCOL_BGP4PLUS,       /* msg is a BGP4+ packet */     MSG_PROTOCOL_BGP4PLUS_01,    /* msg is a BGP4+ (draft 01) packet */     MSG_PROTOCOL_OSPF,           /* msg is an OSPF packet */ -   MSG_TABLE_DUMP               /* routing table dump */ +   MSG_TABLE_DUMP,              /* routing table dump */ +   MSG_TABLE_DUMP_V2            /* routing table dump, version 2 */  };  static int bgp_dump_interval_func (struct thread *); @@ -191,137 +193,189 @@ bgp_dump_set_size (struct stream *s, int type)  }  static void -bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi, -		       int type, unsigned int seq) +bgp_dump_routes_index_table(struct bgp *bgp)  { -  struct stream *obuf; -  struct attr *attr;    struct peer *peer; -  int plen; -  int safi = 0; +  struct listnode *node; +  uint16_t peerno = 0; +  struct stream *obuf; -  /* Make dump stream. */    obuf = bgp_dump_obuf;    stream_reset (obuf); -  attr = info->attr; -  peer = info->peer; +  /* MRT header */ +  bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE); -  /* We support MRT's old format. */ -  if (type == MSG_TABLE_DUMP) +  /* Collector BGP ID */ +  stream_put_in_addr (obuf, &bgp->router_id); + +  /* View name */ +  if(bgp->name)      { -      bgp_dump_header (obuf, MSG_TABLE_DUMP, afi); -      stream_putw (obuf, 0);	/* View # */ -      stream_putw (obuf, seq);	/* Sequence number. */ +      stream_putw (obuf, strlen(bgp->name)); +      stream_put(obuf, bgp->name, strlen(bgp->name));      }    else      { -      bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY); -       -      stream_putl (obuf, info->uptime); /* Time Last Change */ -      stream_putw (obuf, afi);	/* Address Family */ -      stream_putc (obuf, safi);	/* SAFI */ +      stream_putw(obuf, 0);      } -  if (afi == AFI_IP) -    { -      if (type == MSG_TABLE_DUMP) -	{ -	  /* Prefix */ -	  stream_put_in_addr (obuf, &p->u.prefix4); -	  stream_putc (obuf, p->prefixlen); - -	  /* Status */ -	  stream_putc (obuf, 1); - -	  /* Originated */ -	  stream_putl (obuf, info->uptime); - -	  /* Peer's IP address */ -	  stream_put_in_addr (obuf, &peer->su.sin.sin_addr); +  /* Peer count */ +  stream_putw (obuf, listcount(bgp->peer)); -	  /* Peer's AS number. */ -	  stream_putw (obuf, peer->as); - -	  /* Dump attribute. */ -	  bgp_dump_routes_attr (obuf, attr, p); -	} -      else -	{ -	  /* Next-Hop-Len */ -	  stream_putc (obuf, IPV4_MAX_BYTELEN); -	  stream_put_in_addr (obuf, &attr->nexthop); -	  stream_putc (obuf, p->prefixlen); -	  plen = PSIZE (p->prefixlen); -	  stream_put (obuf, &p->u.prefix4, plen); -	  bgp_dump_routes_attr (obuf, attr, p); -	} -    } -#ifdef HAVE_IPV6 -  else if (afi == AFI_IP6) +  /* Walk down all peers */ +  for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))      { -      if (type == MSG_TABLE_DUMP) -	{ -	  /* Prefix */ -	  stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN); -	  stream_putc (obuf, p->prefixlen); -	  /* Status */ -	  stream_putc (obuf, 1); +      /* Peer's type */ +      if (sockunion_family(&peer->su) == AF_INET) +        { +          stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP); +        } +#ifdef HAVE_IPV6 +      else if (sockunion_family(&peer->su) == AF_INET6) +        { +          stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6); +        } +#endif /* HAVE_IPV6 */ -	  /* Originated */ -	  stream_putl (obuf, info->uptime); +      /* Peer's BGP ID */ +      stream_put_in_addr (obuf, &peer->remote_id); -	  /* Peer's IP address */ -	  stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr, -			IPV6_MAX_BYTELEN); +      /* Peer's IP address */ +      if (sockunion_family(&peer->su) == AF_INET) +        { +          stream_put_in_addr (obuf, &peer->su.sin.sin_addr); +        } +#ifdef HAVE_IPV6 +      else if (sockunion_family(&peer->su) == AF_INET6) +        { +          stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr, +                        IPV6_MAX_BYTELEN); +        } +#endif /* HAVE_IPV6 */ -	  /* Peer's AS number. */ -	  stream_putw (obuf, peer->as); +      /* Peer's AS number. */ +      /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */ +      stream_putl (obuf, peer->as); -	  /* Dump attribute. */ -	  bgp_dump_routes_attr (obuf, attr, p); -	} -      else -	{ -	  ; -	} +      /* Store the peer number for this peer */ +      peer->table_dump_index = peerno; +      peerno++;      } -#endif /* HAVE_IPV6 */ -  /* Set length. */ -  bgp_dump_set_size (obuf, type); +  bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);    fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);    fflush (bgp_dump_routes.fp);  } +  /* Runs under child process. */ -static void -bgp_dump_routes_func (int afi) +static unsigned int +bgp_dump_routes_func (int afi, int first_run, unsigned int seq)  {    struct stream *obuf; -  struct bgp_node *rn;    struct bgp_info *info; +  struct bgp_node *rn;    struct bgp *bgp;    struct bgp_table *table; -  unsigned int seq = 0; - -  obuf = bgp_dump_obuf;    bgp = bgp_get_default ();    if (!bgp) -    return; +    return seq;    if (bgp_dump_routes.fp == NULL) -    return; +    return seq; + +  /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers, +     so this should only be done on the first call to bgp_dump_routes_func. +     ( this function will be called once for ipv4 and once for ipv6 ) */ +  if(first_run) +    bgp_dump_routes_index_table(bgp); + +  obuf = bgp_dump_obuf; +  stream_reset(obuf);    /* Walk down each BGP route. */    table = bgp->rib[afi][SAFI_UNICAST];    for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) -    for (info = rn->info; info; info = info->next) -      bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++); +    { +      if(!rn->info) +        continue; + +      stream_reset(obuf); + +      /* MRT header */ +      if (afi == AFI_IP) +        { +          bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST); +        } +#ifdef HAVE_IPV6 +      else if (afi == AFI_IP6) +        { +          bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST); +        } +#endif /* HAVE_IPV6 */ + +      /* Sequence number */ +      stream_putl(obuf, seq); + +      /* Prefix length */ +      stream_putc (obuf, rn->p.prefixlen); + +      /* Prefix */ +      if (afi == AFI_IP) +        { +          /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ +          stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8); +        } +#ifdef HAVE_IPV6 +      else if (afi == AFI_IP6) +        { +          /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ +          stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8); +        } +#endif /* HAVE_IPV6 */ + +      /* Save where we are now, so we can overwride the entry count later */ +      int sizep = stream_get_endp(obuf); + +      /* Entry count */ +      uint16_t entry_count = 0; + +      /* Entry count, note that this is overwritten later */ +      stream_putw(obuf, 0); + +      for (info = rn->info; info; info = info->next) +        { +          entry_count++; + +          /* Peer index */ +          stream_putw(obuf, info->peer->table_dump_index); + +          /* Originated */ +          stream_putl (obuf, info->uptime); + +          /* Dump attribute. */ +          /* Skip prefix & AFI/SAFI for MP_NLRI */ +          bgp_dump_routes_attr (obuf, info->attr, &rn->p); +        } + +      /* Overwrite the entry count, now that we know the right number */ +      stream_putw_at (obuf, sizep, entry_count); + +      seq++; + +      bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); +      fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); + +    } + +  fflush (bgp_dump_routes.fp); + +  return seq;  }  static int @@ -337,9 +391,9 @@ bgp_dump_interval_func (struct thread *t)        /* In case of bgp_dump_routes, we need special route dump function. */        if (bgp_dump->type == BGP_DUMP_ROUTES)  	{ -	  bgp_dump_routes_func (AFI_IP); +	  unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);  #ifdef HAVE_IPV6 -	  bgp_dump_routes_func (AFI_IP6); +	  bgp_dump_routes_func (AFI_IP6, 0, seq);  #endif /* HAVE_IPV6 */  	  /* Close the file now. For a RIB dump there's no point in leaving  	   * it open until the next scheduled dump starts. */ @@ -356,13 +410,21 @@ bgp_dump_interval_func (struct thread *t)  /* Dump common information. */  static void -bgp_dump_common (struct stream *obuf, struct peer *peer) +bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)  {    char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};    /* Source AS number and Destination AS number. */ -  stream_putw (obuf, peer->as); -  stream_putw (obuf, peer->local_as); +  if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) ) +    { +      stream_putl (obuf, peer->as); +      stream_putl (obuf, peer->local_as); +    } +  else +    { +      stream_putw (obuf, peer->as); +      stream_putw (obuf, peer->local_as); +    }    if (peer->su.sa.sa_family == AF_INET)      { @@ -408,8 +470,8 @@ bgp_dump_state (struct peer *peer, int status_old, int status_new)    obuf = bgp_dump_obuf;    stream_reset (obuf); -  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE); -  bgp_dump_common (obuf, peer); +  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4); +  bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/    stream_putw (obuf, status_old);    stream_putw (obuf, status_new); @@ -437,8 +499,15 @@ bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,    stream_reset (obuf);    /* Dump header and common part. */ -  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE); -  bgp_dump_common (obuf, peer); +  if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) ) +    {  +      bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4); +    } +  else +    { +      bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE); +    } +  bgp_dump_common (obuf, peer, 0);    /* Packet contents. */    stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet)); diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h index 36447e93..6bb1197b 100644 --- a/bgpd/bgp_dump.h +++ b/bgpd/bgp_dump.h @@ -25,14 +25,28 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  /* type value */  #define MSG_PROTOCOL_BGP4MP  16  /* subtype value */ -#define BGP4MP_STATE_CHANGE   0 -#define BGP4MP_MESSAGE        1 -#define BGP4MP_ENTRY          2 -#define BGP4MP_SNAPSHOT       3 +#define BGP4MP_STATE_CHANGE          0 +#define BGP4MP_MESSAGE               1 +#define BGP4MP_ENTRY                 2 +#define BGP4MP_SNAPSHOT              3 +#define BGP4MP_MESSAGE_AS4           4 +#define BGP4MP_STATE_CHANGE_AS4      5  #define BGP_DUMP_HEADER_SIZE 12  #define BGP_DUMP_MSG_HEADER  40 +#define TABLE_DUMP_V2_PEER_INDEX_TABLE   1 +#define TABLE_DUMP_V2_RIB_IPV4_UNICAST   2 +#define TABLE_DUMP_V2_RIB_IPV4_MULTICAST 3 +#define TABLE_DUMP_V2_RIB_IPV6_UNICAST   4 +#define TABLE_DUMP_V2_RIB_IPV6_MULTICAST 5 +#define TABLE_DUMP_V2_RIB_GENERIC        6 + +#define TABLE_DUMP_V2_PEER_INDEX_TABLE_IP  0 +#define TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6 1 +#define TABLE_DUMP_V2_PEER_INDEX_TABLE_AS2 0 +#define TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4 2 +  extern void bgp_dump_init (void);  extern void bgp_dump_state (struct peer *, int, int);  extern void bgp_dump_packet (struct peer *, int, struct stream *); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 64f4438f..9e7ae1b3 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgpd.h"  #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_aspath.h"  /* Hash of community attribute. */  struct hash *ecomhash; @@ -228,8 +229,9 @@ ecommunity_unintern (struct ecommunity *ecom)  /* Utinity function to make hash key.  */  unsigned int -ecommunity_hash_make (struct ecommunity *ecom) +ecommunity_hash_make (void *arg)  { +  const struct ecommunity *ecom = arg;    int c;    unsigned int key;    u_int8_t *pnt; @@ -245,9 +247,11 @@ ecommunity_hash_make (struct ecommunity *ecom)  /* Compare two Extended Communities Attribute structure.  */  int -ecommunity_cmp (const struct ecommunity *ecom1,  -                const struct ecommunity *ecom2) +ecommunity_cmp (void *arg1, void *arg2)  { +  const struct ecommunity *ecom1 = arg1; +  const struct ecommunity *ecom2 = arg2; +      if (ecom1->size == ecom2->size        && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0)      return 1; @@ -256,7 +260,7 @@ ecommunity_cmp (const struct ecommunity *ecom1,  /* Initialize Extended Comminities related hash. */  void -ecommunity_init () +ecommunity_init (void)  {    ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);  } @@ -279,11 +283,12 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,    int dot = 0;    int digit = 0;    int separator = 0; -  u_int32_t val_low = 0; -  u_int32_t val_high = 0;    const char *p = str; +  char *endptr;    struct in_addr ip; -  char ipstr[INET_ADDRSTRLEN + 1]; +  as_t as = 0; +  u_int32_t val = 0; +  char buf[INET_ADDRSTRLEN + 1];    /* Skip white space. */    while (isspace ((int) *p)) @@ -346,32 +351,50 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,        goto error;      } +  /* What a mess, there are several possibilities: +   * +   * a) A.B.C.D:MN +   * b) EF:OPQR +   * c) GHJK:MN +   * +   * A.B.C.D: Four Byte IP +   * EF:      Two byte ASN +   * GHJK:    Four-byte ASN +   * MN:      Two byte value +   * OPQR:    Four byte value +   * +   */    while (isdigit ((int) *p) || *p == ':' || *p == '.')       { -      if (*p == ':')  +      if (*p == ':')  	{  	  if (separator)  	    goto error;  	  separator = 1;  	  digit = 0; - +	   +	  if ((p - str) > INET_ADDRSTRLEN) +	    goto error; +          memset (buf, 0, INET_ADDRSTRLEN + 1); +          memcpy (buf, str, p - str); +            	  if (dot)  	    { -	      if ((p - str) > INET_ADDRSTRLEN) -		goto error; - -	      memset (ipstr, 0, INET_ADDRSTRLEN + 1); -	      memcpy (ipstr, str, p - str); - -	      ret = inet_aton (ipstr, &ip); +	      /* Parsing A.B.C.D in: +               * A.B.C.D:MN +               */ +	      ret = inet_aton (buf, &ip);  	      if (ret == 0) -		goto error; +	        goto error;  	    } -	  else -	    val_high = val_low; - -	  val_low = 0; +          else +            { +              /* ASN */ +              as = strtoul (buf, &endptr, 10); +              if (*endptr != '\0' || as == BGP_AS4_MAX) +                goto error; +            }  	}        else if (*p == '.')  	{ @@ -384,35 +407,58 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,        else  	{  	  digit = 1; -	  val_low *= 10; -	  val_low += (*p - '0'); +	   +	  /* We're past the IP/ASN part */ +	  if (separator) +	    { +	      val *= 10; +	      val += (*p - '0'); +            }  	}        p++;      }    /* Low digit part must be there. */ -  if (! digit || ! separator) +  if (!digit || !separator)      goto error;    /* Encode result into routing distinguisher.  */    if (dot)      { +      if (val > UINT16_MAX) +        goto error; +              eval->val[0] = ECOMMUNITY_ENCODE_IP;        eval->val[1] = 0;        memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); -      eval->val[6] = (val_low >> 8) & 0xff; -      eval->val[7] = val_low & 0xff; +      eval->val[6] = (val >> 8) & 0xff; +      eval->val[7] = val & 0xff; +    } +  else if (as > BGP_AS_MAX) +    { +      if (val > UINT16_MAX) +        goto error; +       +      eval->val[0] = ECOMMUNITY_ENCODE_AS4; +      eval->val[1] = 0; +      eval->val[2] = (as >>24) & 0xff; +      eval->val[3] = (as >>16) & 0xff; +      eval->val[4] = (as >>8) & 0xff; +      eval->val[5] =  as & 0xff; +      eval->val[6] = (val >> 8) & 0xff; +      eval->val[7] = val & 0xff;      }    else      {        eval->val[0] = ECOMMUNITY_ENCODE_AS;        eval->val[1] = 0; -      eval->val[2] = (val_high >>8) & 0xff; -      eval->val[3] = val_high & 0xff; -      eval->val[4] = (val_low >>24) & 0xff; -      eval->val[5] = (val_low >>16) & 0xff; -      eval->val[6] = (val_low >>8) & 0xff; -      eval->val[7] = val_low & 0xff; +       +      eval->val[2] = (as >>8) & 0xff; +      eval->val[3] = as & 0xff; +      eval->val[4] = (val >>24) & 0xff; +      eval->val[5] = (val >>16) & 0xff; +      eval->val[6] = (val >>8) & 0xff; +      eval->val[7] = val & 0xff;      }    *token = ecommunity_token_val;    return p; @@ -533,7 +579,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)    u_int8_t *pnt;    int encode = 0;    int type = 0; -#define ECOMMUNITY_STR_DEFAULT_LEN  26 +#define ECOMMUNITY_STR_DEFAULT_LEN  27    int str_size;    int str_pnt;    char *str_buf; @@ -576,7 +622,8 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)        /* High-order octet of type. */        encode = *pnt++; -      if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP) +      if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP +		      && encode != ECOMMUNITY_ENCODE_AS4)  	{  	  len = sprintf (str_buf + str_pnt, "?");  	  str_pnt += len; @@ -618,6 +665,21 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)  	}        /* Put string into buffer.  */ +      if (encode == ECOMMUNITY_ENCODE_AS4) +	{ +	  eas.as = (*pnt++ << 24); +	  eas.as |= (*pnt++ << 16); +	  eas.as |= (*pnt++ << 8); +	  eas.as |= (*pnt++); + +	  eas.val = (*pnt++ << 8); +	  eas.val |= (*pnt++); + +	  len = sprintf( str_buf + str_pnt, "%s%d:%d", prefix, +                        eas.as, eas.val ); +	  str_pnt += len; +	  first = 0; +	}        if (encode == ECOMMUNITY_ENCODE_AS)  	{  	  eas.as = (*pnt++ << 8); diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 7b2564ad..69014237 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  /* High-order octet of the Extended Communities type field.  */  #define ECOMMUNITY_ENCODE_AS                0x00  #define ECOMMUNITY_ENCODE_IP                0x01 +#define ECOMMUNITY_ENCODE_AS4               0x02  /* Low-order octet of the Extended Communityes type field.  */  #define ECOMMUNITY_ROUTE_TARGET             0x02 @@ -71,9 +72,9 @@ extern struct ecommunity *ecommunity_parse (u_int8_t *, u_short);  extern struct ecommunity *ecommunity_dup (struct ecommunity *);  extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *);  extern struct ecommunity *ecommunity_intern (struct ecommunity *); -extern int ecommunity_cmp (const struct ecommunity *, const struct ecommunity *); +extern int ecommunity_cmp (void *, void *);  extern void ecommunity_unintern (struct ecommunity *); -extern unsigned int ecommunity_hash_make (struct ecommunity *); +extern unsigned int ecommunity_hash_make (void *);  extern struct ecommunity *ecommunity_str2com (const char *, int, int);  extern char *ecommunity_ecom2str (struct ecommunity *, int);  extern int ecommunity_match (const struct ecommunity *, const struct ecommunity *); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index cd235770..38431d4c 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgp_fsm.h"  #include "bgpd/bgp_packet.h"  #include "bgpd/bgp_open.h" +#include "bgpd/bgp_aspath.h"  #include "bgpd/bgp_vty.h"  /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can @@ -427,6 +428,19 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)    return 0;  } +static as_t +bgp_capability_as4 (struct peer *peer, struct capability_header *hdr) +{ +  as_t as4 = stream_getl (BGP_INPUT(peer)); +   +  if (BGP_DEBUG (as4, AS4)) +    zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", +                peer->host, as4); +  SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); +   +  return as4; +} +  static struct message capcode_str[] =  {    { 0,	""}, @@ -507,6 +521,7 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)            case CAPABILITY_CODE_ORF:            case CAPABILITY_CODE_ORF_OLD:            case CAPABILITY_CODE_RESTART: +          case CAPABILITY_CODE_AS4:            case CAPABILITY_CODE_DYNAMIC:                /* Check length. */                if (caphdr.length < cap_minsizes[caphdr.code]) @@ -566,6 +581,14 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)            case CAPABILITY_CODE_DYNAMIC:              SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);              break; +          case CAPABILITY_CODE_AS4: +              /* Already handled as a special-case parsing of the capabilities +               * at the beginning of OPEN processing. So we care not a jot +               * for the value really, only error case. +               */ +              if (!bgp_capability_as4 (peer, &caphdr)) +                return -1; +              break;                        default:              if (caphdr.code > 128)                { @@ -615,6 +638,86 @@ strict_capability_same (struct peer *peer)    return 1;  } +/* peek into option, stores ASN to *as4 if the AS4 capability was found. + * Returns  0 if no as4 found, as4cap value otherwise. + */ +as_t +peek_for_as4_capability (struct peer *peer, u_char length) +{ +  struct stream *s = BGP_INPUT (peer); +  size_t orig_getp = stream_get_getp (s); +  size_t end = orig_getp + length; +  as_t as4 = 0; +   +  /* The full capability parser will better flag the error.. */ +  if (STREAM_READABLE(s) < length) +    return 0; + +  if (BGP_DEBUG (as4, AS4)) +    zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u," +                " peeking for as4", +	        peer->host, length); +  /* the error cases we DONT handle, we ONLY try to read as4 out of +   * correctly formatted options. +   */ +  while (stream_get_getp(s) < end)  +    { +      u_char opt_type; +      u_char opt_length; +       +      /* Check the length. */ +      if (stream_get_getp (s) + 2 > end) +        goto end; +       +      /* Fetch option type and length. */ +      opt_type = stream_getc (s); +      opt_length = stream_getc (s); +       +      /* Option length check. */ +      if (stream_get_getp (s) + opt_length > end) +        goto end; +       +      if (opt_type == BGP_OPEN_OPT_CAP) +        { +          unsigned long capd_start = stream_get_getp (s); +          unsigned long capd_end = capd_start + opt_length; +           +          assert (capd_end <= end); +           +	  while (stream_get_getp (s) < capd_end) +	    { +	      struct capability_header hdr; +	       +	      if (stream_get_getp (s) + 2 > capd_end) +                goto end; +               +              hdr.code = stream_getc (s); +              hdr.length = stream_getc (s); +               +	      if ((stream_get_getp(s) +  hdr.length) > capd_end) +		goto end; + +	      if (hdr.code == CAPABILITY_CODE_AS4) +	        { +	          if (hdr.length != CAPABILITY_CODE_AS4_LEN) +	            goto end; +                   +	          if (BGP_DEBUG (as4, AS4)) +	            zlog_info ("[AS4] found AS4 capability, about to parse"); +	          as4 = bgp_capability_as4 (peer, &hdr); +	           +	          goto end; +                } +              stream_forward_getp (s, hdr.length); +	    } +	} +    } + +end: +  stream_set_getp (s, orig_getp); +  return as4; +} +  /* Parse open option */  int  bgp_open_option_parse (struct peer *peer, u_char length, int *capability) @@ -815,6 +918,7 @@ bgp_open_capability (struct stream *s, struct peer *peer)    unsigned long cp;    afi_t afi;    safi_t safi; +  as_t local_as;    /* Remember current pointer for Opt Parm Len. */    cp = stream_get_endp (s); @@ -901,6 +1005,18 @@ bgp_open_capability (struct stream *s, struct peer *peer)    stream_putc (s, CAPABILITY_CODE_REFRESH);    stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); +  /* AS4 */ +  SET_FLAG (peer->cap, PEER_CAP_AS4_ADV); +  stream_putc (s, BGP_OPEN_OPT_CAP); +  stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2); +  stream_putc (s, CAPABILITY_CODE_AS4); +  stream_putc (s, CAPABILITY_CODE_AS4_LEN); +  if ( peer->change_local_as ) +    local_as = peer->change_local_as; +  else +    local_as = peer->local_as; +  stream_putl (s, local_as ); +    /* ORF capability. */    for (afi = AFI_IP ; afi < AFI_MAX ; afi++)      for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 436eb01c..59265dc9 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -48,6 +48,11 @@ struct capability_orf_entry  } __attribute__ ((packed));  #pragma pack() +struct capability_as4 +{ +  uint32_t as4; +}; +  struct graceful_restart_af  {    u_int16_t afi; @@ -100,6 +105,7 @@ struct capability_gr  extern int bgp_open_option_parse (struct peer *, u_char, int *);  extern void bgp_open_capability (struct stream *, struct peer *);  extern void bgp_capability_vty_out (struct vty *, struct peer *); +extern as_t peek_for_as4_capability (struct peer *, u_char);  extern int bgp_afi_safi_valid_indices (afi_t, safi_t *);  #endif /* _QUAGGA_BGP_OPEN_H */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 17ac1f73..1fa2fdfd 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -804,7 +804,8 @@ bgp_open_send (struct peer *peer)    /* Set open packet values. */    stream_putc (s, BGP_VERSION_4);        /* BGP version */ -  stream_putw (s, local_as);		 /* My Autonomous System*/ +  stream_putw (s, (local_as <= BGP_AS_MAX) ? (u_int16_t) local_as  +                                           : BGP_AS_TRANS);    stream_putw (s, send_holdtime);     	 /* Hold Time */    stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */ @@ -1168,6 +1169,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)    u_int16_t holdtime;    u_int16_t send_holdtime;    as_t remote_as; +  as_t as4 = 0;    struct peer *realpeer;    struct in_addr remote_id;    int capability; @@ -1186,10 +1188,75 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)    /* Receive OPEN message log  */    if (BGP_DEBUG (normal, NORMAL)) -    zlog_debug ("%s rcv OPEN, version %d, remote-as %d, holdtime %d, id %s", -	       peer->host, version, remote_as, holdtime, -	       inet_ntoa (remote_id)); -	   +    zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %d," +                " holdtime %d, id %s", +	        peer->host, version, remote_as, holdtime, +	        inet_ntoa (remote_id)); +   +  /* BEGIN to read the capability here, but dont do it yet */ +  capability = 0; +  optlen = stream_getc (peer->ibuf); +   +  if (optlen != 0) +    { +      /* We need the as4 capability value *right now* because +       * if it is there, we have not got the remote_as yet, and without +       * that we do not know which peer is connecting to us now. +       */  +      as4 = peek_for_as4_capability (peer, optlen); +    } +   +  /* Just in case we have a silly peer who sends AS4 capability set to 0 */ +  if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) && !as4) +    { +      zlog_err ("%s bad OPEN, got AS4 capability, but AS4 set to 0", +                peer->host); +      bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, +                       BGP_NOTIFY_OPEN_BAD_PEER_AS); +      return -1; +    } +   +  if (remote_as == BGP_AS_TRANS) +    { +	  /* Take the AS4 from the capability.  We must have received the +	   * capability now!  Otherwise we have a asn16 peer who uses +	   * BGP_AS_TRANS, for some unknown reason. +	   */ +      if (as4 == BGP_AS_TRANS) +        { +          zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed", +                    peer->host); +          bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, +                 BGP_NOTIFY_OPEN_BAD_PEER_AS); +          return -1; +        } +       +      if (!as4 && BGP_DEBUG (as4, AS4)) +        zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4." +                    " Odd, but proceeding.", peer->host); +      else if (as4 < BGP_AS_MAX && BGP_DEBUG (as4, AS4)) +        zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but AS4 fits " +                    "in 2-bytes, very odd peer.", peer->host, as4); +      if (as4) +        remote_as = as4; +    }  +  else  +    { +      /* We may have a partner with AS4 who has an asno < BGP_AS_MAX */ +      /* If we have got the capability, peer->as4cap must match remote_as */ +      if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) +          && as4 != remote_as) +        { +	  /* raise error, log this, close session */ +	  zlog_err ("%s bad OPEN, got AS4 capability, but remote_as %u" +	            " mismatch with 16bit 'myasn' %u in open", +	            peer->host, as4, remote_as); +	  bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, +			   BGP_NOTIFY_OPEN_BAD_PEER_AS); +	  return -1; +	} +    } +    /* Lookup peer from Open packet. */    if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))      { @@ -1364,8 +1431,6 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)    peer->v_keepalive = peer->v_holdtime / 3;    /* Open option part parse. */ -  capability = 0; -  optlen = stream_getc (peer->ibuf);    if (optlen != 0)       {        ret = bgp_open_option_parse (peer, optlen, &capability); @@ -2049,8 +2114,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)            if (!bgp_afi_safi_valid_indices (afi, &safi))              {                if (BGP_DEBUG (normal, NORMAL)) -                zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid", -                            peer->host, afi, safi); +                zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid " +                            "(%u/%u)", peer->host, afi, safi);                continue;              } @@ -2097,7 +2162,6 @@ int  bgp_capability_receive (struct peer *peer, bgp_size_t size)  {    u_char *pnt; -  int ret;    /* Fetch pointer. */    pnt = stream_pnt (peer->ibuf); @@ -2113,7 +2177,7 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size)        bgp_notify_send (peer,  		       BGP_NOTIFY_HEADER_ERR,  		       BGP_NOTIFY_HEADER_BAD_MESTYPE); -      return; +      return -1;      }    /* Status must be Established. */ @@ -2122,7 +2186,7 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size)        plog_err (peer->log,  		"%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status));        bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); -      return; +      return -1;      }    /* Parse packet. */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 305d6796..d51375b7 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3337,7 +3337,7 @@ DEFUN (no_set_atomic_aggregate,  DEFUN (set_aggregator_as,         set_aggregator_as_cmd, -       "set aggregator as <1-65535> A.B.C.D", +       "set aggregator as CMD_AS_RANGE A.B.C.D",         SET_STR         "BGP aggregator attribute\n"         "AS number of aggregator\n" @@ -3349,7 +3349,7 @@ DEFUN (set_aggregator_as,    struct in_addr address;    char *argstr; -  VTY_GET_INTEGER_RANGE ("AS Path", as, argv[0], 1, BGP_AS_MAX); +  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX);    ret = inet_aton (argv[1], &address);    if (ret == 0) @@ -3386,7 +3386,7 @@ DEFUN (no_set_aggregator_as,    if (argv == 0)      return bgp_route_set_delete (vty, vty->index, "aggregator as", NULL); -  VTY_GET_INTEGER_RANGE ("AS Path", as, argv[0], 1, BGP_AS_MAX); +  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX);    ret = inet_aton (argv[1], &address);    if (ret == 0) @@ -3409,7 +3409,7 @@ DEFUN (no_set_aggregator_as,  ALIAS (no_set_aggregator_as,         no_set_aggregator_as_val_cmd, -       "no set aggregator as <1-65535> A.B.C.D", +       "no set aggregator as CMD_AS_RANGE A.B.C.D",         NO_STR         SET_STR         "BGP aggregator attribute\n" diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 3eeb5f92..927e99a1 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -308,7 +308,7 @@ DEFUN_DEPRECATED (neighbor_version,  /* "router bgp" commands. */  DEFUN (router_bgp,          router_bgp_cmd,  -       "router bgp <1-65535>", +       "router bgp CMD_AS_RANGE",         ROUTER_STR         BGP_STR         AS_STR) @@ -318,7 +318,7 @@ DEFUN (router_bgp,    struct bgp *bgp;    const char *name = NULL; -  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535); +  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX);    if (argc == 2)      name = argv[1]; @@ -348,7 +348,7 @@ DEFUN (router_bgp,  ALIAS (router_bgp,         router_bgp_view_cmd, -       "router bgp <1-65535> view WORD", +       "router bgp CMD_AS_RANGE view WORD",         ROUTER_STR         BGP_STR         AS_STR @@ -358,7 +358,7 @@ ALIAS (router_bgp,  /* "no router bgp" commands. */  DEFUN (no_router_bgp,         no_router_bgp_cmd, -       "no router bgp <1-65535>", +       "no router bgp CMD_AS_RANGE",         NO_STR         ROUTER_STR         BGP_STR @@ -368,7 +368,7 @@ DEFUN (no_router_bgp,    struct bgp *bgp;    const char *name = NULL; -  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535); +  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX);    if (argc == 2)      name = argv[1]; @@ -388,7 +388,7 @@ DEFUN (no_router_bgp,  ALIAS (no_router_bgp,         no_router_bgp_view_cmd, -       "no router bgp <1-65535> view WORD", +       "no router bgp CMD_AS_RANGE view WORD",         NO_STR         ROUTER_STR         BGP_STR @@ -539,7 +539,7 @@ ALIAS (no_bgp_cluster_id,  DEFUN (bgp_confederation_identifier,         bgp_confederation_identifier_cmd, -       "bgp confederation identifier <1-65535>", +       "bgp confederation identifier CMD_AS_RANGE",         "BGP specific commands\n"         "AS confederation parameters\n"         "AS number\n" @@ -550,7 +550,7 @@ DEFUN (bgp_confederation_identifier,    bgp = vty->index; -  VTY_GET_INTEGER ("AS", as, argv[0]); +  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX);    bgp_confederation_id_set (bgp, as); @@ -571,7 +571,7 @@ DEFUN (no_bgp_confederation_identifier,    bgp = vty->index;    if (argc == 1) -    VTY_GET_INTEGER ("AS", as, argv[0]); +    VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX);    bgp_confederation_id_unset (bgp); @@ -580,7 +580,7 @@ DEFUN (no_bgp_confederation_identifier,  ALIAS (no_bgp_confederation_identifier,         no_bgp_confederation_identifier_arg_cmd, -       "no bgp confederation identifier <1-65535>", +       "no bgp confederation identifier CMD_AS_RANGE",         NO_STR         "BGP specific commands\n"         "AS confederation parameters\n" @@ -589,7 +589,7 @@ ALIAS (no_bgp_confederation_identifier,  DEFUN (bgp_confederation_peers,         bgp_confederation_peers_cmd, -       "bgp confederation peers .<1-65535>", +       "bgp confederation peers .CMD_AS_RANGE",         "BGP specific commands\n"         "AS confederation parameters\n"         "Peer ASs in BGP confederation\n" @@ -603,7 +603,7 @@ DEFUN (bgp_confederation_peers,    for (i = 0; i < argc; i++)      { -      VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535); +      VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, BGP_AS4_MAX);        if (bgp->as == as)  	{ @@ -619,7 +619,7 @@ DEFUN (bgp_confederation_peers,  DEFUN (no_bgp_confederation_peers,         no_bgp_confederation_peers_cmd, -       "no bgp confederation peers .<1-65535>", +       "no bgp confederation peers .CMD_AS_RANGE",         NO_STR         "BGP specific commands\n"         "AS confederation parameters\n" @@ -634,8 +634,8 @@ DEFUN (no_bgp_confederation_peers,    for (i = 0; i < argc; i++)      { -      VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535); -       +      VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, BGP_AS4_MAX); +        bgp_confederation_peers_remove (bgp, as);      }    return CMD_SUCCESS; @@ -1249,7 +1249,7 @@ peer_remote_as_vty (struct vty *vty, const char *peer_str,    bgp = vty->index;    /* Get AS number.  */ -  VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, 65535); +  VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, BGP_AS4_MAX);    /* If peer is peer group, call proper function.  */    ret = str2sockunion (peer_str, &su); @@ -1288,7 +1288,7 @@ peer_remote_as_vty (struct vty *vty, const char *peer_str,  DEFUN (neighbor_remote_as,         neighbor_remote_as_cmd, -       NEIGHBOR_CMD2 "remote-as <1-65535>", +       NEIGHBOR_CMD2 "remote-as CMD_AS_RANGE",         NEIGHBOR_STR         NEIGHBOR_ADDR_STR2         "Specify a BGP neighbor\n" @@ -1352,7 +1352,7 @@ DEFUN (no_neighbor,  ALIAS (no_neighbor,         no_neighbor_remote_as_cmd, -       NO_NEIGHBOR_CMD "remote-as <1-65535>", +       NO_NEIGHBOR_CMD "remote-as CMD_AS_RANGE",         NO_STR         NEIGHBOR_STR         NEIGHBOR_ADDR_STR @@ -1382,7 +1382,7 @@ DEFUN (no_neighbor_peer_group,  DEFUN (no_neighbor_peer_group_remote_as,         no_neighbor_peer_group_remote_as_cmd, -       "no neighbor WORD remote-as <1-65535>", +       "no neighbor WORD remote-as CMD_AS_RANGE",         NO_STR         NEIGHBOR_STR         "Neighbor tag\n" @@ -1404,7 +1404,7 @@ DEFUN (no_neighbor_peer_group_remote_as,  DEFUN (neighbor_local_as,         neighbor_local_as_cmd, -       NEIGHBOR_CMD2 "local-as <1-65535>", +       NEIGHBOR_CMD2 "local-as CMD_AS_RANGE",         NEIGHBOR_STR         NEIGHBOR_ADDR_STR2         "Specify a local-as number\n" @@ -1423,7 +1423,7 @@ DEFUN (neighbor_local_as,  DEFUN (neighbor_local_as_no_prepend,         neighbor_local_as_no_prepend_cmd, -       NEIGHBOR_CMD2 "local-as <1-65535> no-prepend", +       NEIGHBOR_CMD2 "local-as CMD_AS_RANGE no-prepend",         NEIGHBOR_STR         NEIGHBOR_ADDR_STR2         "Specify a local-as number\n" @@ -1462,7 +1462,7 @@ DEFUN (no_neighbor_local_as,  ALIAS (no_neighbor_local_as,         no_neighbor_local_as_val_cmd, -       NO_NEIGHBOR_CMD2 "local-as <1-65535>", +       NO_NEIGHBOR_CMD2 "local-as CMD_AS_RANGE",         NO_STR         NEIGHBOR_STR         NEIGHBOR_ADDR_STR2 @@ -1471,7 +1471,7 @@ ALIAS (no_neighbor_local_as,  ALIAS (no_neighbor_local_as,         no_neighbor_local_as_val2_cmd, -       NO_NEIGHBOR_CMD2 "local-as <1-65535> no-prepend", +       NO_NEIGHBOR_CMD2 "local-as CMD_AS_RANGE no-prepend",         NO_STR         NEIGHBOR_STR         NEIGHBOR_ADDR_STR2 @@ -4037,7 +4037,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi,  	  if (ret < 0)  	    bgp_clear_vty_error (vty, peer, afi, safi, ret);  	} -      return 0; +      return CMD_SUCCESS;      }    /* Clear specified neighbors. */ @@ -4051,13 +4051,13 @@ bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi,        if (ret < 0)  	{  	  vty_out (vty, "Malformed address: %s%s", arg, VTY_NEWLINE); -	  return -1; +	  return CMD_WARNING;  	}        peer = peer_lookup (bgp, &su);        if (! peer)  	{  	  vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE); -	  return -1; +	  return CMD_WARNING;  	}        if (stype == BGP_CLEAR_SOFT_NONE) @@ -4068,7 +4068,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi,        if (ret < 0)  	bgp_clear_vty_error (vty, peer, afi, safi, ret); -      return 0; +      return CMD_SUCCESS;      }    /* Clear all peer-group members. */ @@ -4080,7 +4080,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi,        if (! group)  	{  	  vty_out (vty, "%%BGP: No such peer-group %s%s", arg, VTY_NEWLINE); -	  return -1;  +	  return CMD_WARNING;   	}        for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) @@ -4099,7 +4099,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi,  	  if (ret < 0)  	    bgp_clear_vty_error (vty, peer, afi, safi, ret);  	} -      return 0; +      return CMD_SUCCESS;      }    if (sort == clear_external) @@ -4117,22 +4117,21 @@ bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi,  	  if (ret < 0)  	    bgp_clear_vty_error (vty, peer, afi, safi, ret);  	} -      return 0; +      return CMD_SUCCESS;      }    if (sort == clear_as)      {        as_t as;        unsigned long as_ul; -      char *endptr = NULL;        int find = 0; -      as_ul = strtoul(arg, &endptr, 10); - -      if ((as_ul == ULONG_MAX) || (*endptr != '\0') || (as_ul > USHRT_MAX)) +      VTY_GET_LONG ("AS", as_ul, arg); +       +      if (!as_ul)  	{  	  vty_out (vty, "Invalid AS number%s", VTY_NEWLINE);  -	  return -1; +	  return CMD_WARNING;  	}        as = (as_t) as_ul; @@ -4153,10 +4152,10 @@ bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi,        if (! find)  	vty_out (vty, "%%BGP: No peer is configured with AS %s%s", arg,  		 VTY_NEWLINE); -      return 0; +      return CMD_SUCCESS;      } -  return 0; +  return CMD_SUCCESS;  }  static int @@ -4164,7 +4163,6 @@ bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi,                 enum clear_sort sort, enum bgp_clear_type stype,                  const char *arg)  { -  int ret;    struct bgp *bgp;    /* BGP structure lookup. */ @@ -4187,11 +4185,7 @@ bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi,          }      } -  ret =  bgp_clear (vty, bgp, afi, safi, sort, stype, arg); -  if (ret < 0) -    return CMD_WARNING; - -  return CMD_SUCCESS; +  return bgp_clear (vty, bgp, afi, safi, sort, stype, arg);  }  DEFUN (clear_ip_bgp_all, @@ -4328,7 +4322,7 @@ ALIAS (clear_ip_bgp_external,  DEFUN (clear_ip_bgp_as,         clear_ip_bgp_as_cmd, -       "clear ip bgp <1-65535>", +       "clear ip bgp CMD_AS_RANGE",         CLEAR_STR         IP_STR         BGP_STR @@ -4339,14 +4333,14 @@ DEFUN (clear_ip_bgp_as,  ALIAS (clear_ip_bgp_as,         clear_bgp_as_cmd, -       "clear bgp <1-65535>", +       "clear bgp CMD_AS_RANGE",         CLEAR_STR         BGP_STR         "Clear peers with the AS number\n")  ALIAS (clear_ip_bgp_as,         clear_bgp_ipv6_as_cmd, -       "clear bgp ipv6 <1-65535>", +       "clear bgp ipv6 CMD_AS_RANGE",         CLEAR_STR         BGP_STR         "Address family\n" @@ -4858,7 +4852,7 @@ ALIAS (clear_bgp_external_soft_out,  DEFUN (clear_ip_bgp_as_soft_out,         clear_ip_bgp_as_soft_out_cmd, -       "clear ip bgp <1-65535> soft out", +       "clear ip bgp CMD_AS_RANGE soft out",         CLEAR_STR         IP_STR         BGP_STR @@ -4872,7 +4866,7 @@ DEFUN (clear_ip_bgp_as_soft_out,  ALIAS (clear_ip_bgp_as_soft_out,         clear_ip_bgp_as_out_cmd, -       "clear ip bgp <1-65535> out", +       "clear ip bgp CMD_AS_RANGE out",         CLEAR_STR         IP_STR         BGP_STR @@ -4881,7 +4875,7 @@ ALIAS (clear_ip_bgp_as_soft_out,  DEFUN (clear_ip_bgp_as_ipv4_soft_out,         clear_ip_bgp_as_ipv4_soft_out_cmd, -       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft out", +       "clear ip bgp CMD_AS_RANGE ipv4 (unicast|multicast) soft out",         CLEAR_STR         IP_STR         BGP_STR @@ -4902,7 +4896,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_out,  ALIAS (clear_ip_bgp_as_ipv4_soft_out,         clear_ip_bgp_as_ipv4_out_cmd, -       "clear ip bgp <1-65535> ipv4 (unicast|multicast) out", +       "clear ip bgp CMD_AS_RANGE ipv4 (unicast|multicast) out",         CLEAR_STR         IP_STR         BGP_STR @@ -4914,7 +4908,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_out,  DEFUN (clear_ip_bgp_as_vpnv4_soft_out,         clear_ip_bgp_as_vpnv4_soft_out_cmd, -       "clear ip bgp <1-65535> vpnv4 unicast soft out", +       "clear ip bgp CMD_AS_RANGE vpnv4 unicast soft out",         CLEAR_STR         IP_STR         BGP_STR @@ -4930,7 +4924,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_out,  ALIAS (clear_ip_bgp_as_vpnv4_soft_out,         clear_ip_bgp_as_vpnv4_out_cmd, -       "clear ip bgp <1-65535> vpnv4 unicast out", +       "clear ip bgp CMD_AS_RANGE vpnv4 unicast out",         CLEAR_STR         IP_STR         BGP_STR @@ -4941,7 +4935,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_out,  DEFUN (clear_bgp_as_soft_out,         clear_bgp_as_soft_out_cmd, -       "clear bgp <1-65535> soft out", +       "clear bgp CMD_AS_RANGE soft out",         CLEAR_STR         BGP_STR         "Clear peers with the AS number\n" @@ -4954,7 +4948,7 @@ DEFUN (clear_bgp_as_soft_out,  ALIAS (clear_bgp_as_soft_out,         clear_bgp_ipv6_as_soft_out_cmd, -       "clear bgp ipv6 <1-65535> soft out", +       "clear bgp ipv6 CMD_AS_RANGE soft out",         CLEAR_STR         BGP_STR         "Address family\n" @@ -4964,7 +4958,7 @@ ALIAS (clear_bgp_as_soft_out,  ALIAS (clear_bgp_as_soft_out,         clear_bgp_as_out_cmd, -       "clear bgp <1-65535> out", +       "clear bgp CMD_AS_RANGE out",         CLEAR_STR         BGP_STR         "Clear peers with the AS number\n" @@ -4972,7 +4966,7 @@ ALIAS (clear_bgp_as_soft_out,  ALIAS (clear_bgp_as_soft_out,         clear_bgp_ipv6_as_out_cmd, -       "clear bgp ipv6 <1-65535> out", +       "clear bgp ipv6 CMD_AS_RANGE out",         CLEAR_STR         BGP_STR         "Address family\n" @@ -5762,7 +5756,7 @@ ALIAS (clear_bgp_external_in_prefix_filter,  DEFUN (clear_ip_bgp_as_soft_in,         clear_ip_bgp_as_soft_in_cmd, -       "clear ip bgp <1-65535> soft in", +       "clear ip bgp CMD_AS_RANGE soft in",         CLEAR_STR         IP_STR         BGP_STR @@ -5776,7 +5770,7 @@ DEFUN (clear_ip_bgp_as_soft_in,  ALIAS (clear_ip_bgp_as_soft_in,         clear_ip_bgp_as_in_cmd, -       "clear ip bgp <1-65535> in", +       "clear ip bgp CMD_AS_RANGE in",         CLEAR_STR         IP_STR         BGP_STR @@ -5785,7 +5779,7 @@ ALIAS (clear_ip_bgp_as_soft_in,  DEFUN (clear_ip_bgp_as_in_prefix_filter,         clear_ip_bgp_as_in_prefix_filter_cmd, -       "clear ip bgp <1-65535> in prefix-filter", +       "clear ip bgp CMD_AS_RANGE in prefix-filter",         CLEAR_STR         IP_STR         BGP_STR @@ -5799,7 +5793,7 @@ DEFUN (clear_ip_bgp_as_in_prefix_filter,  DEFUN (clear_ip_bgp_as_ipv4_soft_in,         clear_ip_bgp_as_ipv4_soft_in_cmd, -       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft in", +       "clear ip bgp CMD_AS_RANGE ipv4 (unicast|multicast) soft in",         CLEAR_STR         IP_STR         BGP_STR @@ -5820,7 +5814,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_in,  ALIAS (clear_ip_bgp_as_ipv4_soft_in,         clear_ip_bgp_as_ipv4_in_cmd, -       "clear ip bgp <1-65535> ipv4 (unicast|multicast) in", +       "clear ip bgp CMD_AS_RANGE ipv4 (unicast|multicast) in",         CLEAR_STR         IP_STR         BGP_STR @@ -5832,7 +5826,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_in,  DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter,         clear_ip_bgp_as_ipv4_in_prefix_filter_cmd, -       "clear ip bgp <1-65535> ipv4 (unicast|multicast) in prefix-filter", +       "clear ip bgp CMD_AS_RANGE ipv4 (unicast|multicast) in prefix-filter",         CLEAR_STR         IP_STR         BGP_STR @@ -5853,7 +5847,7 @@ DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter,  DEFUN (clear_ip_bgp_as_vpnv4_soft_in,         clear_ip_bgp_as_vpnv4_soft_in_cmd, -       "clear ip bgp <1-65535> vpnv4 unicast soft in", +       "clear ip bgp CMD_AS_RANGE vpnv4 unicast soft in",         CLEAR_STR         IP_STR         BGP_STR @@ -5869,7 +5863,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_in,  ALIAS (clear_ip_bgp_as_vpnv4_soft_in,         clear_ip_bgp_as_vpnv4_in_cmd, -       "clear ip bgp <1-65535> vpnv4 unicast in", +       "clear ip bgp CMD_AS_RANGE vpnv4 unicast in",         CLEAR_STR         IP_STR         BGP_STR @@ -5880,7 +5874,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_in,  DEFUN (clear_bgp_as_soft_in,         clear_bgp_as_soft_in_cmd, -       "clear bgp <1-65535> soft in", +       "clear bgp CMD_AS_RANGE soft in",         CLEAR_STR         BGP_STR         "Clear peers with the AS number\n" @@ -5893,7 +5887,7 @@ DEFUN (clear_bgp_as_soft_in,  ALIAS (clear_bgp_as_soft_in,         clear_bgp_ipv6_as_soft_in_cmd, -       "clear bgp ipv6 <1-65535> soft in", +       "clear bgp ipv6 CMD_AS_RANGE soft in",         CLEAR_STR         BGP_STR         "Address family\n" @@ -5903,7 +5897,7 @@ ALIAS (clear_bgp_as_soft_in,  ALIAS (clear_bgp_as_soft_in,         clear_bgp_as_in_cmd, -       "clear bgp <1-65535> in", +       "clear bgp CMD_AS_RANGE in",         CLEAR_STR         BGP_STR         "Clear peers with the AS number\n" @@ -5911,7 +5905,7 @@ ALIAS (clear_bgp_as_soft_in,  ALIAS (clear_bgp_as_soft_in,         clear_bgp_ipv6_as_in_cmd, -       "clear bgp ipv6 <1-65535> in", +       "clear bgp ipv6 CMD_AS_RANGE in",         CLEAR_STR         BGP_STR         "Address family\n" @@ -5920,7 +5914,7 @@ ALIAS (clear_bgp_as_soft_in,  DEFUN (clear_bgp_as_in_prefix_filter,         clear_bgp_as_in_prefix_filter_cmd, -       "clear bgp <1-65535> in prefix-filter", +       "clear bgp CMD_AS_RANGE in prefix-filter",         CLEAR_STR         BGP_STR         "Clear peers with the AS number\n" @@ -5933,7 +5927,7 @@ DEFUN (clear_bgp_as_in_prefix_filter,  ALIAS (clear_bgp_as_in_prefix_filter,         clear_bgp_ipv6_as_in_prefix_filter_cmd, -       "clear bgp ipv6 <1-65535> in prefix-filter", +       "clear bgp ipv6 CMD_AS_RANGE in prefix-filter",         CLEAR_STR         BGP_STR         "Address family\n" @@ -6248,7 +6242,7 @@ ALIAS (clear_bgp_external_soft,  DEFUN (clear_ip_bgp_as_soft,         clear_ip_bgp_as_soft_cmd, -       "clear ip bgp <1-65535> soft", +       "clear ip bgp CMD_AS_RANGE soft",         CLEAR_STR         IP_STR         BGP_STR @@ -6261,7 +6255,7 @@ DEFUN (clear_ip_bgp_as_soft,  DEFUN (clear_ip_bgp_as_ipv4_soft,         clear_ip_bgp_as_ipv4_soft_cmd, -       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft", +       "clear ip bgp CMD_AS_RANGE ipv4 (unicast|multicast) soft",         CLEAR_STR         IP_STR         BGP_STR @@ -6281,7 +6275,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft,  DEFUN (clear_ip_bgp_as_vpnv4_soft,         clear_ip_bgp_as_vpnv4_soft_cmd, -       "clear ip bgp <1-65535> vpnv4 unicast soft", +       "clear ip bgp CMD_AS_RANGE vpnv4 unicast soft",         CLEAR_STR         IP_STR         BGP_STR @@ -6296,7 +6290,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft,  DEFUN (clear_bgp_as_soft,         clear_bgp_as_soft_cmd, -       "clear bgp <1-65535> soft", +       "clear bgp CMD_AS_RANGE soft",         CLEAR_STR         BGP_STR         "Clear peers with the AS number\n" @@ -6308,7 +6302,7 @@ DEFUN (clear_bgp_as_soft,  ALIAS (clear_bgp_as_soft,         clear_bgp_ipv6_as_soft_cmd, -       "clear bgp ipv6 <1-65535> soft", +       "clear bgp ipv6 CMD_AS_RANGE soft",         CLEAR_STR         BGP_STR         "Address family\n" @@ -6688,7 +6682,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)  		   peer->open_out + peer->update_out + peer->keepalive_out  		   + peer->notify_out + peer->refresh_out  		   + peer->dynamic_cap_out, -		   0, 0, (unsigned long)peer->obuf->count); +		   0, 0, (unsigned long) peer->obuf->count);  	  vty_out (vty, "%8s",   		   peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN)); @@ -7271,6 +7265,18 @@ bgp_show_peer (struct vty *vty, struct peer *p)  	{  	  vty_out (vty, "  Neighbor capabilities:%s", VTY_NEWLINE); +	  /* AS4 */ +	  if (CHECK_FLAG (p->cap, PEER_CAP_AS4_RCV) +	      || CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV)) +	    { +	      vty_out (vty, "    4 Byte AS:"); +	      if (CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV)) +		vty_out (vty, " advertised"); +	      if (CHECK_FLAG (p->cap, PEER_CAP_AS4_RCV)) +		vty_out (vty, " %sreceived", +			 CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV) ? "and " : ""); +	      vty_out (vty, "%s", VTY_NEWLINE); +	    }  	  /* Dynamic */  	  if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV)  	      || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)) @@ -7389,21 +7395,18 @@ bgp_show_peer (struct vty *vty, struct peer *p)  	}        if (p->t_gr_restart) -        { -	  vty_out (vty, "    The remaining time of restart timer is %ld%s", -		   thread_timer_remain_second (p->t_gr_restart), VTY_NEWLINE); -	} +        vty_out (vty, "    The remaining time of restart timer is %ld%s", +                 thread_timer_remain_second (p->t_gr_restart), VTY_NEWLINE); +              if (p->t_gr_stale) -	{ -	  vty_out (vty, "    The remaining time of stalepath timer is %ld%s", -		   thread_timer_remain_second (p->t_gr_stale), VTY_NEWLINE); -	} +        vty_out (vty, "    The remaining time of stalepath timer is %ld%s", +                 thread_timer_remain_second (p->t_gr_stale), VTY_NEWLINE);      }    /* Packet counts. */    vty_out (vty, "  Message statistics:%s", VTY_NEWLINE);    vty_out (vty, "    Inq depth is 0%s", VTY_NEWLINE); -  vty_out (vty, "    Outq depth is %lu%s", (unsigned long)p->obuf->count, VTY_NEWLINE); +  vty_out (vty, "    Outq depth is %lu%s", (unsigned long) p->obuf->count, VTY_NEWLINE);    vty_out (vty, "                         Sent       Rcvd%s", VTY_NEWLINE);    vty_out (vty, "    Opens:         %10d %10d%s", p->open_out, p->open_in, VTY_NEWLINE);    vty_out (vty, "    Notifications: %10d %10d%s", p->notify_out, p->notify_in, VTY_NEWLINE); @@ -7907,7 +7910,7 @@ bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient,    vty_out (vty, "4 "); -  vty_out (vty, "%5d ", rsclient->as); +  vty_out (vty, "%11d ", rsclient->as);    rmname = ROUTE_MAP_EXPORT_NAME(&rsclient->filter[afi][safi]);    if ( rmname && strlen (rmname) > 13 ) diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index d3b4e2b4..2df8aaa5 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #ifndef _QUAGGA_BGP_VTY_H  #define _QUAGGA_BGP_VTY_H +#define CMD_AS_RANGE "<1-4294967295>" +  extern void bgp_vty_init (void);  extern const char *afi_safi_print (afi_t, safi_t); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 3fba6042..e04575d8 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -25,7 +25,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "sockunion.h"  /* Typedef BGP specific types.  */ -typedef u_int16_t as_t; +typedef u_int32_t as_t; +typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */  typedef u_int16_t bgp_size_t;  /* BGP master for system wide configurations and variables.  */ @@ -287,6 +288,9 @@ struct peer    int status;    int ostatus; +  /* Peer index, used for dumping TABLE_DUMP_V2 format */ +  uint16_t table_dump_index; +    /* Peer information */    int fd;			/* File descriptor */    int ttl;			/* TTL of TCP connection to the peer. */ @@ -316,7 +320,7 @@ struct peer    u_char afc_recv[AFI_MAX][SAFI_MAX];    /* Capability flags (reset in bgp_stop) */ -  u_char cap; +  u_int16_t cap;  #define PEER_CAP_REFRESH_ADV                (1 << 0) /* refresh advertised */  #define PEER_CAP_REFRESH_OLD_RCV            (1 << 1) /* refresh old received */  #define PEER_CAP_REFRESH_NEW_RCV            (1 << 2) /* refresh rfc received */ @@ -324,6 +328,8 @@ struct peer  #define PEER_CAP_DYNAMIC_RCV                (1 << 4) /* dynamic received */  #define PEER_CAP_RESTART_ADV                (1 << 5) /* restart advertised */  #define PEER_CAP_RESTART_RCV                (1 << 6) /* restart received */ +#define PEER_CAP_AS4_ADV                    (1 << 7) /* as4 advertised */ +#define PEER_CAP_AS4_RCV                    (1 << 8) /* as4 received */    /* Capability flags (reset in bgp_stop) */    u_int16_t af_cap[AFI_MAX][SAFI_MAX]; @@ -591,6 +597,8 @@ struct bgp_nlri  #define BGP_ATTR_MP_REACH_NLRI                  14  #define BGP_ATTR_MP_UNREACH_NLRI                15  #define BGP_ATTR_EXT_COMMUNITIES                16 +#define BGP_ATTR_AS4_PATH                       17 +#define BGP_ATTR_AS4_AGGREGATOR                 18  #define BGP_ATTR_AS_PATHLIMIT                   21  /* BGP update origin.  */ diff --git a/doc/BGP-TypeCode b/doc/BGP-TypeCode index 0904e19f..5663c4d7 100644 --- a/doc/BGP-TypeCode +++ b/doc/BGP-TypeCode @@ -19,6 +19,8 @@     14    MP_REACH_NLRI        [RFC 2283]     15    MP_UNREACH_NLRI      [RFC 2283]     16    EXT_COMMUNITIES      [draft-ramachandra-bgp-ext-communities-09.txt] +   17    AS4_PATH             [RFC 4893] +   18    AS4_AGGREGATOR       [RFC 4893]    254    RCID_PATH            [RFC 1863]    255    ADVERTISER           [RFC 1863]  ========================================================================= diff --git a/tests/ChangeLog b/tests/ChangeLog index 46ab9766..94f58749 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,28 @@ +2007-09-27 Paul Jakma <paul.jakma@sun.com> + +	* aspath_test.c: Test dupe-weeding from sets. +	  Test that reconciliation merges AS_PATH and AS4_PATH where +	  former is shorter than latter. + +2007-09-26 Paul Jakma <paul.jakma@sun.com> + +	* aspath_test.c: Test AS4_PATH reconcilation where length +	  of AS_PATH and AS4_PATH is same. + +2007-09-25 Paul Jakma <paul.jakma@sun.com> + +	* bgp_capability_test.c: (general) Extend tests to validate +	  peek_for_as4_capability. +	  Add test of full OPEN Option block, with multiple capabilities, +	  both as a series of Option, and a single option. +	  Add some crap to beginning of stream, to prevent code depending +	  on getp == 0. + +2007-09-18 Paul Jakma <paul.jakma@sun.com> + +	* bgp_capability_test.c: (parse_test) update for changes to +	  peek_for_as4_capability +  2007-09-17 Paul Jakma <paul.jakma@sun.com>  	* bgp_capability_test.c: Test that peer's adv_recv and adv_nego get @@ -9,6 +34,17 @@  	* bgp_capability_test.c: new, capability parser unit tests.  	* Makefile.am: add previous. +2007-07-25 Paul Jakma <paul.jakma@sun.com> + +	* aspath_test.c: Exercise 32bit parsing. Test reconcile +	  function. +	* ecommunity_test.c: New, test AS4 ecommunity changes, positive +	  test only at this time, error cases not tested yet. +	 +2006-12-01 Juergen Kammer <j.kammer@eurodata.de> + +	* aspath_test.c: Support asn32 changes, call aspath_parse with 16 bit. +  2006-08-26 Paul Jakma <paul.jakma@sun.com>  	* heavy-wq.c: (slow_func_del,slow_func) update to match workqueue diff --git a/tests/Makefile.am b/tests/Makefile.am index a63416ff..2045496e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -2,7 +2,7 @@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib  DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\"  noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ -		aspathtest testprivs teststream testbgpcap +		aspathtest testprivs teststream testbgpcap ecommtest  testsig_SOURCES = test-sig.c  testbuffer_SOURCES = test-buffer.c  testmemory_SOURCES = test-memory.c @@ -13,6 +13,7 @@ heavywq_SOURCES = heavy-wq.c main.c  heavythread_SOURCES = heavy-thread.c main.c  aspathtest_SOURCES = aspath_test.c  testbgpcap_SOURCES = bgp_capability_test.c +ecommtest_SOURCES = ecommunity_test.c  testsig_LDADD = ../lib/libzebra.la @LIBCAP@  testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ @@ -24,3 +25,4 @@ heavywq_LDADD = ../lib/libzebra.la @LIBCAP@ -lm  heavythread_LDADD = ../lib/libzebra.la @LIBCAP@ -lm  aspathtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a  testbgpcap_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a +ecommtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a diff --git a/tests/aspath_test.c b/tests/aspath_test.c index 1d28dbed..c12d07a5 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -7,6 +7,13 @@  #include "bgpd/bgpd.h"  #include "bgpd/bgp_aspath.h" +#define VT100_RESET "\x1b[0m" +#define VT100_RED "\x1b[31m" +#define VT100_GREEN "\x1b[32m" +#define VT100_YELLOW "\x1b[33m" +#define OK VT100_GREEN "OK" VT100_RESET +#define FAILED VT100_RED "failed" VT100_RESET +  /* need these to link in libbgp */  struct zebra_privs_t *bgpd_privs = NULL;  struct thread_master *master = NULL; @@ -312,8 +319,87 @@ static struct test_segment {       /* We shouldn't ever /generate/ such paths. However, we should        * cope with them fine.        */ -     "8466 3 52737 4096 3456 {7099,8153,8153,8153}", -      "8466 3 52737 4096 3456 {7099,8153,8153,8153}", +     "8466 3 52737 4096 3456 {7099,8153}", +      "8466 3 52737 4096 3456 {7099,8153}", +      6, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, +  }, +  { /* 18 */ +    "reconcile_lead_asp", +    "seq(6435,59408,21665) set(23456,23456,23456), seq(23456,23456,23456)", +    { 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, +      0x1,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, +      0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0 }, +    24, +    { "6435 59408 21665 {23456} 23456 23456 23456", +      "6435 59408 21665 {23456} 23456 23456 23456", +      7, 0, NOT_ALL_PRIVATE, 23456, 1, 6435 }, +  }, +  { /* 19 */ +    "reconcile_new_asp", +    "set(2457,61697,4369), seq(1842,41591,51793)", +    {  +      0x1,0x3, 0x09,0x99, 0xf1,0x01, 0x11,0x11, +      0x2,0x3, 0x07,0x32, 0xa2,0x77, 0xca,0x51 }, +    16, +    { "{2457,4369,61697} 1842 41591 51793", +      "{2457,4369,61697} 1842 41591 51793", +      4, 0, NOT_ALL_PRIVATE, 51793, 1, 2457 }, +  }, +  { /* 20 */ +    "reconcile_confed", +    "confseq(123,456,789) confset(456,124,788) seq(6435,59408,21665)" +    " set(23456,23456,23456), seq(23456,23456,23456)", +    { 0x3,0x3, 0x00,0x7b, 0x01,0xc8, 0x03,0x15, +      0x4,0x3, 0x01,0xc8, 0x00,0x7c, 0x03,0x14, +      0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, +      0x1,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, +      0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0 }, +    40, +    { "(123 456 789) [124,456,788] 6435 59408 21665" +      " {23456} 23456 23456 23456", +      "6435 59408 21665 {23456} 23456 23456 23456", +      7, 4, NOT_ALL_PRIVATE, 23456, 1, 6435 }, +  }, +  { /* 21 */ +    "reconcile_start_trans", +    "seq(23456,23456,23456) seq(6435,59408,21665)", +    { 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, +      0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, }, +    16, +    { "23456 23456 23456 6435 59408 21665", +      "23456 23456 23456 6435 59408 21665", +      6, 0, NOT_ALL_PRIVATE, 21665, 1, 23456 }, +  }, +  { /* 22 */ +    "reconcile_start_trans4", +    "seq(1842,41591,51793) seq(6435,59408,21665)", +    { 0x2,0x3, 0x07,0x32, 0xa2,0x77, 0xca,0x51, +      0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, }, +    16, +    { "1842 41591 51793 6435 59408 21665", +      "1842 41591 51793 6435 59408 21665", +      6, 0, NOT_ALL_PRIVATE, 41591, 1, 1842 }, +  }, +  { /* 23 */ +    "reconcile_start_trans_error", +    "seq(23456,23456,23456) seq(6435,59408)", +    { 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, +      0x2,0x2, 0x19,0x23, 0xe8,0x10, }, +    14, +    { "23456 23456 23456 6435 59408", +      "23456 23456 23456 6435 59408", +      5, 0, NOT_ALL_PRIVATE, 59408, 1, 23456 }, +  }, +  { /* 24 */  +    "redundantset2", +    "seq(8466,3,52737,4096,3456) set(7099,8153,8153,8153,7099)", +    { 0x2,0x5, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80, +      0x1,0x5, 0x1b,0xbb, 0x1f,0xd9, 0x1f,0xd9, 0x1f,0xd9, 0x1b,0xbb,}, +    24, +    { +     /* We should weed out duplicate set members. */ +     "8466 3 52737 4096 3456 {7099,8153}", +      "8466 3 52737 4096 3456 {7099,8153}",        6, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 },    },    { NULL, NULL, {0}, 0, { NULL, 0, 0 } } @@ -432,13 +518,43 @@ static struct tests {    { NULL, NULL, { NULL, 0, 0, 0, 0, 0, 0, } },  }; -struct tests aggregate_tests[] = +struct tests reconcile_tests[] =  { -  { &test_segments[0], &test_segments[1], -    { "{3,4,4096,8466,8722,52737}", -      "{3,4,4096,8466,8722,52737}", -      1, 0, NOT_ALL_PRIVATE, 52737, 1, NULL_ASN }, +  { &test_segments[18], &test_segments[19], +    { "6435 59408 21665 {2457,4369,61697} 1842 41591 51793", +      "6435 59408 21665 {2457,4369,61697} 1842 41591 51793", +      7, 0, NOT_ALL_PRIVATE, 51793, 1, 6435 }, +  }, +  { &test_segments[19], &test_segments[18], +    /* AS_PATH (19) has more hops than NEW_AS_PATH, +     * so just AS_PATH should be used (though, this practice +     * is bad imho). +     */ +    { "{2457,4369,61697} 1842 41591 51793 6435 59408 21665 {23456} 23456 23456 23456", +      "{2457,4369,61697} 1842 41591 51793 6435 59408 21665 {23456} 23456 23456 23456", +      11, 0, NOT_ALL_PRIVATE, 51793, 1, 6435 }, +  }, +  { &test_segments[20], &test_segments[19], +    { "(123 456 789) [124,456,788] 6435 59408 21665" +      " {2457,4369,61697} 1842 41591 51793", +      "6435 59408 21665 {2457,4369,61697} 1842 41591 51793", +      7, 4, NOT_ALL_PRIVATE, 51793, 1, 6435 }, +  }, +  { &test_segments[21], &test_segments[22], +    { "1842 41591 51793 6435 59408 21665", +      "1842 41591 51793 6435 59408 21665", +      6, 0, NOT_ALL_PRIVATE, 51793, 1, 1842 }, +  }, +  { &test_segments[23], &test_segments[22], +    { "23456 23456 23456 6435 59408 1842 41591 51793 6435 59408 21665", +      "23456 23456 23456 6435 59408 1842 41591 51793 6435 59408 21665", +      11, 0, NOT_ALL_PRIVATE, 51793, 1, 1842 },    }, +  { NULL, NULL, { NULL, 0, 0, 0, 0, 0, 0, } }, +}; +   +struct tests aggregate_tests[] = +{    { &test_segments[0], &test_segments[2],      { "8466 3 52737 4096 {4,8722}",        "8466 3 52737 4096 {4,8722}", @@ -459,6 +575,13 @@ struct tests aggregate_tests[] =        "8466 {2,3,4,4096,8722,52737}",        2, 0, NOT_ALL_PRIVATE, 2, 20000, 8466 },    }, + +  { &test_segments[5], &test_segments[18], +    { "6435 59408 21665 {1842,2457,4369,23456,41590,51793,61697}", +      "6435 59408 21665 {1842,2457,4369,23456,41590,51793,61697}", +      4, 0, NOT_ALL_PRIVATE, 41590, 1, 6435 }, +  }, +    { NULL, NULL, { NULL, 0, 0}  },  }; @@ -498,7 +621,7 @@ struct compare_tests  /* make an aspath from a data stream */  static struct aspath * -make_aspath (const u_char *data, size_t len) +make_aspath (const u_char *data, size_t len, int use32bit)  {    struct stream *s = NULL;    struct aspath *as; @@ -508,7 +631,7 @@ make_aspath (const u_char *data, size_t len)        s = stream_new (len);        stream_put (s, data, len);      } -  as = aspath_parse (s, len); +  as = aspath_parse (s, len, use32bit);    if (s)      stream_free (s); @@ -535,18 +658,27 @@ printbytes (const u_char *bytes, int len)  static int  validate (struct aspath *as, const struct test_spec *sp)  { -  size_t bytes; +  size_t bytes, bytes4;    int fails = 0;    const u_char *out; -  struct aspath *asinout, *asconfeddel, *asstr; +  static struct stream *s; +  struct aspath *asinout, *asconfeddel, *asstr, *as4;    out = aspath_snmp_pathseg (as, &bytes); -  asinout = make_aspath (out, bytes); +  asinout = make_aspath (out, bytes, 0); +   +  /* Excercise AS4 parsing a bit, with a dogfood test */ +  if (!s) +    s = stream_new (4096); +  bytes4 = aspath_put (s, as, 1); +  as4 = make_aspath (STREAM_DATA(s), bytes4, 1);    asstr = aspath_str2aspath (sp->shouldbe);    asconfeddel = aspath_delete_confed_seq (aspath_dup (asinout)); +  printf ("got: %s\n", aspath_print(as)); +      /* the parsed path should match the specified 'shouldbe' string.     * We should pass the "eat our own dog food" test, be able to output     * this path and then input it again. Ie the path resulting from: @@ -562,6 +694,10 @@ validate (struct aspath *as, const struct test_spec *sp)     *     * aspath_str2aspath() and shouldbe should match     * +   * We do the same for: +   * +   *   aspath_parse(aspath_put(as,USE32BIT)) +   *     * Confederation related tests:      * - aspath_delete_confed_seq(aspath) should match shouldbe_confed     * - aspath_delete_confed_seq should be idempotent. @@ -571,6 +707,8 @@ validate (struct aspath *as, const struct test_spec *sp)        || (aspath_key_make (as) != aspath_key_make (asinout))           /* by string */        || strcmp(aspath_print (asinout), sp->shouldbe) +         /* By 4-byte parsing */ +      || strcmp(aspath_print (as4), sp->shouldbe)           /* by various path counts */        || (aspath_count_hops (as) != sp->hops)        || (aspath_count_confeds (as) != sp->confeds) @@ -580,7 +718,7 @@ validate (struct aspath *as, const struct test_spec *sp)        failed++;        fails++;        printf ("shouldbe:\n%s\n", sp->shouldbe); -      printf ("got:\n%s\n", aspath_print(as)); +      printf ("as4:\n%s\n", aspath_print (as4));        printf ("hash keys: in: %d out->in: %d\n",                 aspath_key_make (as), aspath_key_make (asinout));        printf ("hops: %d, counted %d %d\n", sp->hops,  @@ -635,11 +773,13 @@ validate (struct aspath *as, const struct test_spec *sp)                aspath_private_as_check (as));      }    aspath_unintern (asinout); +  aspath_unintern (as4); +      aspath_free (asconfeddel);    aspath_free (asstr); +  stream_reset (s);    return fails; -    }  static void @@ -650,9 +790,9 @@ empty_get_test ()    printf ("empty_get_test, as: %s\n",aspath_print (as));    if (!validate (as, &sp)) -    printf ("OK\n"); +    printf ("%s\n", OK);    else -    printf ("failed!\n"); +    printf ("%s!\n", FAILED);    printf ("\n"); @@ -667,14 +807,14 @@ parse_test (struct test_segment *t)    printf ("%s: %s\n", t->name, t->desc); -  asp = make_aspath (t->asdata, t->len); +  asp = make_aspath (t->asdata, t->len, 0);    printf ("aspath: %s\nvalidating...:\n", aspath_print (asp));    if (!validate (asp, &t->sp)) -    printf ("OK\n"); +    printf (OK "\n");    else -    printf ("failed\n"); +    printf (FAILED "\n");    printf ("\n");    aspath_unintern (asp); @@ -689,8 +829,8 @@ prepend_test (struct tests *t)    printf ("prepend %s: %s\n", t->test1->name, t->test1->desc);    printf ("to %s: %s\n", t->test2->name, t->test2->desc); -  asp1 = make_aspath (t->test1->asdata, t->test1->len); -  asp2 = make_aspath (t->test2->asdata, t->test2->len); +  asp1 = make_aspath (t->test1->asdata, t->test1->len, 0); +  asp2 = make_aspath (t->test2->asdata, t->test2->len, 0);    ascratch = aspath_dup (asp2);    aspath_unintern (asp2); @@ -700,9 +840,9 @@ prepend_test (struct tests *t)    printf ("aspath: %s\n", aspath_print (asp2));    if (!validate (asp2, &t->sp)) -    printf ("OK\n"); +    printf ("%s\n", OK);    else -    printf ("failed!\n"); +    printf ("%s!\n", FAILED);    printf ("\n");    aspath_unintern (asp1); @@ -717,7 +857,7 @@ empty_prepend_test (struct test_segment *t)    printf ("empty prepend %s: %s\n", t->name, t->desc); -  asp1 = make_aspath (t->asdata, t->len); +  asp1 = make_aspath (t->asdata, t->len, 0);    asp2 = aspath_empty ();    ascratch = aspath_dup (asp2); @@ -728,15 +868,41 @@ empty_prepend_test (struct test_segment *t)    printf ("aspath: %s\n", aspath_print (asp2));    if (!validate (asp2, &t->sp)) -    printf ("OK\n"); +    printf (OK "\n");    else -    printf ("failed!\n"); +    printf (FAILED "!\n");    printf ("\n");    aspath_unintern (asp1);    aspath_free (asp2);  } +/* as2+as4 reconciliation testing */ +static void +as4_reconcile_test (struct tests *t) +{ +  struct aspath *asp1, *asp2, *ascratch; +   +  printf ("reconciling %s:\n  %s\n", t->test1->name, t->test1->desc); +  printf ("with %s:\n  %s\n", t->test2->name, t->test2->desc); +   +  asp1 = make_aspath (t->test1->asdata, t->test1->len, 0); +  asp2 = make_aspath (t->test2->asdata, t->test2->len, 0); +   +  ascratch = aspath_reconcile_as4 (asp1, asp2); +   +  if (!validate (ascratch, &t->sp)) +    printf (OK "\n"); +  else +    printf (FAILED "!\n"); +   +  printf ("\n"); +  aspath_unintern (asp1); +  aspath_unintern (asp2); +  aspath_free (ascratch); +} + +  /* aggregation testing */  static void  aggregate_test (struct tests *t) @@ -746,17 +912,15 @@ aggregate_test (struct tests *t)    printf ("aggregate %s: %s\n", t->test1->name, t->test1->desc);    printf ("with %s: %s\n", t->test2->name, t->test2->desc); -  asp1 = make_aspath (t->test1->asdata, t->test1->len); -  asp2 = make_aspath (t->test2->asdata, t->test2->len); +  asp1 = make_aspath (t->test1->asdata, t->test1->len, 0); +  asp2 = make_aspath (t->test2->asdata, t->test2->len, 0);    ascratch = aspath_aggregate (asp1, asp2); -  printf ("aspath: %s\n", aspath_print (ascratch)); -      if (!validate (ascratch, &t->sp)) -    printf ("OK\n"); +    printf (OK "\n");    else -    printf ("failed!\n"); +    printf (FAILED "!\n");    printf ("\n");    aspath_unintern (asp1); @@ -782,8 +946,8 @@ cmp_test ()        printf ("left cmp %s: %s\n", t1->name, t1->desc);        printf ("and %s: %s\n", t2->name, t2->desc); -      asp1 = make_aspath (t1->asdata, t1->len); -      asp2 = make_aspath (t2->asdata, t2->len); +      asp1 = make_aspath (t1->asdata, t1->len, 0); +      asp2 = make_aspath (t2->asdata, t2->len, 0);        if (aspath_cmp_left (asp1, asp2) != left_compare[i].shouldbe_cmp            || aspath_cmp_left (asp2, asp1) != left_compare[i].shouldbe_cmp @@ -792,7 +956,8 @@ cmp_test ()            || aspath_cmp_left_confed (asp2, asp1)                  != left_compare[i].shouldbe_confed)          { -          printf ("failed\n"); +          failed++; +          printf (FAILED "\n");            printf ("result should be: cmp: %d, confed: %d\n",                     left_compare[i].shouldbe_cmp,                    left_compare[i].shouldbe_confed); @@ -801,10 +966,9 @@ cmp_test ()                    aspath_cmp_left_confed (asp1, asp2));            printf("path1: %s\npath2: %s\n", aspath_print (asp1),                   aspath_print (asp2)); -          failed++;          }        else -        printf ("OK\n"); +        printf (OK "\n");        printf ("\n");        aspath_unintern (asp1); @@ -831,6 +995,13 @@ main (void)    while (aggregate_tests[i].test1)      aggregate_test (&aggregate_tests[i++]); +  i = 0; +   +  while (reconcile_tests[i].test1) +    as4_reconcile_test (&reconcile_tests[i++]); +   +  i = 0; +      cmp_test();    i = 0; diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c index 020dfb0f..6771b579 100644 --- a/tests/bgp_capability_test.c +++ b/tests/bgp_capability_test.c @@ -15,8 +15,9 @@  #define VT100_YELLOW "\x1b[33m" -#define OPEN	0 -#define DYNCAP	1 +#define CAPABILITY 0 +#define DYNCAP     1 +#define OPT_PARAM  2  /* need these to link in libbgp */  struct zebra_privs_t *bgpd_privs = NULL; @@ -34,7 +35,8 @@ static struct test_segment {  #define SHOULD_PARSE	0  #define SHOULD_ERR	-1    int parses; /* whether it should parse or not */ - +  int peek_for; /* what peek_for_as4_capability should say */ +      /* AFI/SAFI validation */    int validate_afi;    afi_t afi; @@ -76,54 +78,55 @@ static struct test_segment mp_segments[] =    { "MP4",      "MP IP/Uni",      { 0x1, 0x4, 0x0, 0x1, 0x0, 0x1 }, -    6, SHOULD_PARSE, AFI_IP, SAFI_UNICAST, +    6, SHOULD_PARSE, 0, +    1, AFI_IP, SAFI_UNICAST, VALID_AFI,    },    { "MPv6",      "MP IPv6/Uni",      { 0x1, 0x4, 0x0, 0x2, 0x0, 0x1 }, -    6, SHOULD_PARSE,  +    6, SHOULD_PARSE, 0,      1, AFI_IP6, SAFI_UNICAST, VALID_AFI,    },    /* 5 */    { "MP2",      "MP IP/Multicast",      { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x2 }, -    6, SHOULD_PARSE,  +    6, SHOULD_PARSE, 0,      1, AFI_IP, SAFI_MULTICAST, VALID_AFI,    },    /* 6 */    { "MP3",      "MP IP6/VPNv4",      { CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x80 }, -    6, SHOULD_PARSE, /* parses, but invalid afi,safi */ +    6, SHOULD_PARSE, 0, /* parses, but invalid afi,safi */      1, AFI_IP6, BGP_SAFI_VPNV4, INVALID_AFI,    },    /* 7 */    { "MP5",      "MP IP6/MPLS-VPN",      { CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x4 }, -    6, SHOULD_PARSE,  +    6, SHOULD_PARSE, 0,      1, AFI_IP6, SAFI_MPLS_VPN, VALID_AFI,    },    /* 8 */    { "MP6",      "MP IP4/VPNv4",      { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80 }, -    6, SHOULD_PARSE,  +    6, SHOULD_PARSE, 0,      1, AFI_IP, BGP_SAFI_VPNV4, VALID_AFI,    },      /* 9 */    { "MP7",      "MP IP4/VPNv6",      { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x81 }, -    6, SHOULD_PARSE, /* parses, but invalid afi,safi tuple */ +    6, SHOULD_PARSE, 0, /* parses, but invalid afi,safi tuple */      1, AFI_IP, BGP_SAFI_VPNV6, INVALID_AFI,    },    /* 10 */    { "MP8",      "MP unknown AFI",      { CAPABILITY_CODE_MP, 0x4, 0x0, 0xa, 0x0, 0x81 }, -    6, SHOULD_PARSE,  +    6, SHOULD_PARSE, 0,      1, 0xa, 0x81, INVALID_AFI, /* parses, but unknown */    },    /* 11 */ @@ -136,7 +139,7 @@ static struct test_segment mp_segments[] =    { "MP-overflow",      "MP IP4/Unicast, length too long",      { CAPABILITY_CODE_MP, 0x6, 0x0, 0x1, 0x0, 0x1 }, -    6, SHOULD_ERR, +    6, SHOULD_ERR, 0,      1, AFI_IP, SAFI_UNICAST, VALID_AFI,    },    { NULL, NULL, {0}, 0, 0} @@ -290,8 +293,8 @@ static struct test_segment misc_segments[] =    /* 19 */    { "AS4",      "AS4 capability", -    { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12 }, -    6, SHOULD_PARSE, +    { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12 }, /* AS: 2882400018 */ +    6, SHOULD_PARSE, 2882400018,    },    /* 20 */    { "GR", @@ -367,7 +370,7 @@ static struct test_segment misc_segments[] =    { NULL, NULL, {0}, 0, 0}  }; - +/* DYNAMIC message */  struct test_segment dynamic_cap_msgs[] =   {    { "DynCap", @@ -397,18 +400,97 @@ struct test_segment dynamic_cap_msgs[] =    },    { NULL, NULL, {0}, 0, 0}  }; + +/* Entire Optional-Parameters block */ +struct test_segment opt_params[] = +{ +  { "Cap-singlets", +    "One capability per Optional-Param", +    { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ +      0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ +      0x02, 0x02, 0x80, 0x00, /* RR (old) */ +      0x02, 0x02, 0x02, 0x00, /* RR */   +    }, +    24, SHOULD_PARSE, +  }, +  { "Cap-series", +    "Series of capability, one Optional-Param", +    { 0x02, 0x10, +      0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ +      0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ +      0x80, 0x00, /* RR (old) */ +      0x02, 0x00, /* RR */   +    }, +    18, SHOULD_PARSE, +  }, +  { "AS4more", +    "AS4 capability after other caps (singlets)", +    { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ +      0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ +      0x02, 0x02, 0x80, 0x00, /* RR (old) */ +      0x02, 0x02, 0x02, 0x00, /* RR */ +      0x02, 0x06, 0x41, 0x04, 0x00, 0x03, 0x00, 0x06  /* AS4: 1996614 */ +    }, +    32, SHOULD_PARSE, 196614, +  }, +  { "AS4series", +    "AS4 capability, in series of capabilities", +    { 0x02, 0x16, +      0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ +      0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ +      0x80, 0x00, /* RR (old) */ +      0x02, 0x00, /* RR */   +      0x41, 0x04, 0x00, 0x03, 0x00, 0x06  /* AS4: 1996614 */ +    }, +    24, SHOULD_PARSE, 196614, +  }, +  { "AS4real", +    "AS4 capability, in series of capabilities", +    { +      0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/uni */ +      0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/uni */ +      0x02, 0x02, 0x80, 0x00, /* RR old */ +      0x02, 0x02, 0x02, 0x00, /* RR */ +      0x02, 0x06, 0x41, 0x04, 0x00, 0x03, 0x00, 0x06, /* AS4 */ +    }, +    32, SHOULD_PARSE, 196614, +  }, +  { "AS4real2", +    "AS4 capability, in series of capabilities", +    { +      0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, +      0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, +      0x02, 0x02, 0x80, 0x00, +      0x02, 0x02, 0x02, 0x00, +      0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0xfc, 0x03, +      0x02, 0x09, 0x82, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x80, 0x03, +      0x02, 0x09, 0x03, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x40, 0x03, +      0x02, 0x02, 0x42, 0x00, +    }, +    58, SHOULD_PARSE, 64515, +  }, + +  { NULL, NULL, {0}, 0, 0} +}; +  /* basic parsing test */  static void  parse_test (struct peer *peer, struct test_segment *t, int type)  {    int ret;    int capability = 0; +  as_t as4 = 0;    int oldfailed = failed; +  int len = t->len; +#define RANDOM_FUZZ 35    stream_reset (peer->ibuf); +  stream_put (peer->ibuf, NULL, RANDOM_FUZZ); +  stream_set_getp (peer->ibuf, RANDOM_FUZZ); +      switch (type)      { -      case OPEN: +      case CAPABILITY:          stream_putc (peer->ibuf, BGP_OPEN_OPT_CAP);          stream_putc (peer->ibuf, t->len);          break; @@ -422,11 +504,20 @@ parse_test (struct peer *peer, struct test_segment *t, int type)    stream_write (peer->ibuf, t->data, t->len);    printf ("%s: %s\n", t->name, t->desc); -   +    switch (type)      { -      case OPEN: -        ret = bgp_open_option_parse (peer, t->len + 2, &capability); +      case CAPABILITY: +        len += 2; /* to cover the OPT-Param header */ +      case OPT_PARAM: +        printf ("len: %u\n", len); +        /* peek_for_as4 wants getp at capibility*/ +        as4 = peek_for_as4_capability (peer, len); +        printf ("peek_for_as4: as4 is %u\n", as4); +        /* and it should leave getp as it found it */ +        assert (stream_get_getp (peer->ibuf) == RANDOM_FUZZ); +         +        ret = bgp_open_option_parse (peer, len, &capability);          break;        case DYNCAP:          ret = bgp_capability_receive (peer, t->len); @@ -458,18 +549,27 @@ parse_test (struct peer *peer, struct test_segment *t, int type)          }      } +  if (as4 != t->peek_for) +    { +      printf ("as4 %u != %u\n", as4, t->peek_for); +      failed++; +    } +      printf ("parsed?: %s\n", ret ? "no" : "yes");    if (ret != t->parses)      failed++;    if (tty) -    printf ("%s\n", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET  +    printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET                                            : VT100_GREEN "OK" VT100_RESET);    else -    printf ("%s\n", (failed > oldfailed) ? "failed!" : "OK" ); +    printf ("%s", (failed > oldfailed) ? "failed!" : "OK" ); +   +  if (failed) +    printf (" (%u)", failed); -  printf ("\n"); +  printf ("\n\n");  }  static struct bgp *bgp; @@ -485,10 +585,12 @@ main (void)    conf_bgp_debug_events = -1UL;    conf_bgp_debug_packet = -1UL;    conf_bgp_debug_normal = -1UL; +  conf_bgp_debug_as4 = -1UL;    term_bgp_debug_fsm = -1UL;    term_bgp_debug_events = -1UL;    term_bgp_debug_packet = -1UL;    term_bgp_debug_normal = -1UL; +  term_bgp_debug_as4 = -1UL;    master = thread_master_create ();    bgp_master_init (); @@ -500,6 +602,7 @@ main (void)      return -1;    peer = peer_create_accept (bgp); +  peer->host = "foo";    for (i = AFI_IP; i < AFI_MAX; i++)      for (j = SAFI_UNICAST; j < SAFI_MAX; j++) @@ -510,18 +613,22 @@ main (void)    i = 0;    while (mp_segments[i].name) -    parse_test (peer, &mp_segments[i++], OPEN); +    parse_test (peer, &mp_segments[i++], CAPABILITY);    /* These tests assume mp_segments tests set at least     * one of the afc_nego's     */    i = 0;    while (test_segments[i].name)    -    parse_test (peer, &test_segments[i++], OPEN); +    parse_test (peer, &test_segments[i++], CAPABILITY);    i = 0;    while (misc_segments[i].name) -    parse_test (peer, &misc_segments[i++], OPEN); +    parse_test (peer, &misc_segments[i++], CAPABILITY); + +  i = 0; +  while (opt_params[i].name) +    parse_test (peer, &opt_params[i++], OPT_PARAM);    SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);    peer->status = Established; diff --git a/vtysh/ChangeLog b/vtysh/ChangeLog index f2ba3332..de62763c 100644 --- a/vtysh/ChangeLog +++ b/vtysh/ChangeLog @@ -18,6 +18,11 @@  	  precision commands: send to all daemons.  	  (vtysh_init_vty) Install new log timestamp precision commands. +2007-02-12 Juergen Kammer <j.kammer@eurodata.de> +	* extract.pl: AS4 compatibility for router bgp ASNUMBER +	* extract.pl.in: AS4 compatibility for router bgp ASNUMBER +	* vtysh.c: AS4 compatibility for router bgp ASNUMBER +  2006-07-27 Andrew J. Schorr <ajschorr@alumni.princeton.edu>  	* vtysh_main.c: (usage) Add new -d and -E options.  And note that diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 723fe8d6..789819c6 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -37,8 +37,8 @@ $ignore{'"router ripng"'} = "ignore";  $ignore{'"router ospf"'} = "ignore";  $ignore{'"router ospf <0-65535>"'} = "ignore";  $ignore{'"router ospf6"'} = "ignore"; -$ignore{'"router bgp <1-65535>"'} = "ignore"; -$ignore{'"router bgp <1-65535> view WORD"'} = "ignore"; +$ignore{'"router bgp CMD_AS_RANGE"'} = "ignore"; +$ignore{'"router bgp CMD_AS_RANGE view WORD"'} = "ignore";  $ignore{'"router isis WORD"'} = "ignore";  $ignore{'"router zebra"'} = "ignore";  $ignore{'"address-family ipv4"'} = "ignore"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index c7efa91b..9f47515d 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -838,7 +838,7 @@ DEFUNSH (VTYSH_ALL,  DEFUNSH (VTYSH_BGPD,  	 router_bgp,  	 router_bgp_cmd, -	 "router bgp <1-65535>", +	 "router bgp CMD_AS_RANGE",  	 ROUTER_STR  	 BGP_STR  	 AS_STR) | 
