]> git.proxmox.com Git - mirror_frr.git/commitdiff
[bgpd] Merge AS4 support
authorPaul Jakma <paul.jakma@sun.com>
Sun, 14 Oct 2007 22:32:21 +0000 (22:32 +0000)
committerPaul Jakma <paul.jakma@sun.com>
Sun, 14 Oct 2007 22:32:21 +0000 (22:32 +0000)
2007-10-14 Paul Jakma <paul.jakma@sun.com>

* NEWS: Note that MRT dumps are now version 2
* (general) Merge in Juergen Kammer's AS4 patch.

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.
* 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_open.c: (peek_for_as4_capability) Fix to work.
* bgp_packet.c: (bgp_open_receive) Fix sanity check of as4.
* tests/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_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.
* tests/bgp_capability_test.c: (parse_test) update for changes to
  peek_for_as4_capability

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.
* tests/aspath_test.c: Exercise 32bit parsing. Test reconcile
  function.
* tests/ecommunity_test.c: New, test AS4 ecommunity changes,
  positive test only at this time, error cases not tested yet.

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
* tests/aspath_test.c: Support asn32 changes, call aspath_parse
  with 16 bit.
* vtysh/extract.pl: AS4 compatibility for router bgp ASNUMBER
* vtysh/extract.pl.in: AS4 compatibility for router bgp ASNUMBER
* vtysh/vtysh.c: AS4 compatibility for router bgp ASNUMBER

27 files changed:
ChangeLog
NEWS
bgpd/ChangeLog
bgpd/bgp_aspath.c
bgpd/bgp_aspath.h
bgpd/bgp_attr.c
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_dump.c
bgpd/bgp_dump.h
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h
bgpd/bgp_open.c
bgpd/bgp_open.h
bgpd/bgp_packet.c
bgpd/bgp_routemap.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgpd.h
doc/BGP-TypeCode
tests/ChangeLog
tests/Makefile.am
tests/aspath_test.c
tests/bgp_capability_test.c
vtysh/ChangeLog
vtysh/extract.pl.in
vtysh/vtysh.c

index 2501a078a5670257afa0f464912cfd9e3050cd97..6cde4262ba63a0682060e1ef074ea3137eb7fe47 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index 0a9269c5599e22b30dead463be599c536f001680..e045ec102ecb8eb024493110f59e77a0577e0792 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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.
index c98485b46a1df9e627b3e01fd2591c8a48c35422..5a31d9cb5452178324d10efe41a9d1290463d123 100644 (file)
@@ -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
index b328e38a5b2c324327ab96dd54c1be363ad38570..d7e985d4f0b90f3dcef10fe51a77696e852a8d26 100644 (file)
@@ -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"
 \f
 /* 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;
 }
index efec24c2e985c92c62ed963f0b1c2c6ccdd97e42..3bb616f7b0dea19dcfdd235beebb3ebd66e0d67b 100644 (file)
@@ -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 *);
index 9d13ca6ec90f8cf3a38b6684a507e8d998854353..b463b3c0fc36a3b6b29c984a5b752791caeb97d5 100644 (file)
@@ -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);
     }
 
index 60284a2d8c4cd6dd382c670dc96d2b439fdd5703..acb1de7facd54e744f88fd2024d3a2d63d976d1a 100644 (file)
@@ -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);
index 7015cb77ad20991f3fa71fa3d9a5fc8e59129443..71e110ce64c2d45a1d20c1550f33b7348d8a182a 100644 (file)
@@ -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
index 601ff2b2242c9e8e80155b5941c5f78877e1d3cb..e815ea3cc90f284fef1c46a9605c60609b11ae92 100644 (file)
@@ -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));
index 36447e93208a0c94b5de22b7b4a677d94420b5e9..6bb1197bb212760ef4d63cb68efb314dd8bde19e 100644 (file)
@@ -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 *);
index 64f4438f88787bae8a84712873652d99468c2e63..9e7ae1b3e4bdeefb1ee2cf6c09dc8867b5725610 100644 (file)
@@ -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);
index 7b2564adaf0fe333de3252762be00e8fac77b076..69014237d7fdeabb3d4b442302994cbd07eebb22 100644 (file)
@@ -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 *);
index cd235770a1733157e09311480a2070af58512f8a..38431d4c63d91875c69663c7a466006a3160de8b 100644 (file)
@@ -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++)
index 436eb01ccaeb2fca604d5d1e081a38ae3f76d7cd..59265dc990282a76537672803ad7f4be33bb4048 100644 (file)
@@ -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 */
index 17ac1f73029d378783ff971886d26b3267cebbd2..1fa2fdfde988a7a99a71814e9899196e9320a68f 100644 (file)
@@ -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. */
index 305d6796b36e692191e9bef45cd63f201c55dd24..d51375b74c70aa2097da933a52444351f3d28cb5 100644 (file)
@@ -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"
index 3eeb5f929e6ecb6bf7d6b7e1e692a92c8ad7e9c9..927e99a14c73d9ad106340f79c2dac20a704a4f6 100644 (file)
@@ -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,
 \f
 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,
 \f
 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,
 \f
 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 )
index d3b4e2b46dd3c79127a12a36085236d606d50fe1..2df8aaa5dec270dd02f410c24c92d53a19bd9d44 100644 (file)
@@ -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);
 
index 3fba6042c87c0c0e7b48532415b4b4d9f138e2f1..e04575d80a18bec5c566c0f48df0a6c4468cf165 100644 (file)
@@ -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.  */
index 0904e19f9ad0c5eb99866954ae6ac90b1b250272..5663c4d7a2c89f3a0c6d619fa178ea2925615ea1 100644 (file)
@@ -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]
 =========================================================================
index 46ab976643accbc20b2969df88c6cb862189711e..94f587492b46b3e8705dcde28d4c358875d8c886 100644 (file)
@@ -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
index a63416fffa26616c0f72175f4c7ac4ee68dc8b34..2045496e3fc090d6412d2cf46fbf2c3bdd95c04e 100644 (file)
@@ -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
index 1d28dbedc4b2fd95c02dc78dd3dd466dbc881d05..c12d07a59db44b8a8ae5465d2a7df9c857fed2a4 100644 (file)
@@ -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;
index 020dfb0f7fabb7e0c953ac13cee77646c89c9ca3..6771b57998e4485d5ea7a515f1bb0fb5c89ab717 100644 (file)
@@ -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;
index f2ba3332603f55fe5cd7d7a30b39639f65f3910d..de62763c463c85e34d9c6022bba723bd117e929a 100644 (file)
          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
index 723fe8d613b1f7d389c1e9cae66cfe4f240a82a9..789819c6354a4b266499968840850dd317475311 100755 (executable)
@@ -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";
index c7efa91bd44335e45dee7f25e1d01460546fa6af..9f47515d819fc58b9dc97126256103e0804b1006 100644 (file)
@@ -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)