[bgpd] Merge AS4 support

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
This commit is contained in:
Paul Jakma 2007-10-14 22:32:21 +00:00
parent 7593fddfa1
commit 0b2aa3a0a8
27 changed files with 1900 additions and 435 deletions

View File

@ -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> 2007-09-07 Paul Jakma <paul.jakma@sun.com>
* configure.ac: Bump version to 0.99.9 * configure.ac: Bump version to 0.99.9

6
NEWS
View File

@ -1,5 +1,11 @@
* Changes in Quagga 0.99.2 * 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, - [bgpd] Work queues added to bgpd to split up update processing,
particularly beneficial when a peer session goes down. AS_PATH particularly beneficial when a peer session goes down. AS_PATH
parsing rewritten to be clearer, more robust and ready for 4-byte. parsing rewritten to be clearer, more robust and ready for 4-byte.

View 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> 2007-09-17 Paul Jakma <paul.jakma@sun.com>
* bgp_open.c: (bgp_capability_mp) We were setting * bgp_open.c: (bgp_capability_mp) We were setting

View File

@ -28,15 +28,20 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "str.h" #include "str.h"
#include "log.h" #include "log.h"
#include "stream.h" #include "stream.h"
#include "jhash.h"
#include "bgpd/bgpd.h" #include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h" #include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_attr.h"
/* Attr. Flags and Attr. Type Code. */ /* Attr. Flags and Attr. Type Code. */
#define AS_HEADER_SIZE 2 #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) #define AS_VALUE_SIZE sizeof (as_t)
/* This is the old one */
#define AS16_VALUE_SIZE sizeof (as16_t)
/* Maximum protocol segment length value */ /* Maximum protocol segment length value */
#define AS_SEGMENT_MAX 255 #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 * sizes and lengths. At present (200508) they sort of match, however
* the ONLY functions which should now about the on-wire syntax are * the ONLY functions which should now about the on-wire syntax are
* aspath_put, assegment_put and assegment_parse. * 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 */ /* 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 */ /* 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. */ /* 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 */ /* AS_SEQUENCE segments can be packed together */
/* Can the types of X and Y be considered for packing? */ /* Can the types of X and Y be considered for packing? */
@ -85,7 +94,7 @@ static struct stream *snmp_stream;
static inline as_t * static inline as_t *
assegment_data_new (int num) 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 static inline void
@ -150,7 +159,7 @@ assegment_dup (struct assegment *seg)
struct assegment *new; struct assegment *new;
new = assegment_new (seg->type, seg->length); 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; return new;
} }
@ -197,7 +206,7 @@ assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
for (i = 0; i < num; i++) for (i = 0; i < num; i++)
newas[i] = asnum; 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); XFREE (MTYPE_AS_SEG_DATA, seg->as);
seg->as = newas; seg->as = newas;
seg->length += num; seg->length += num;
@ -215,12 +224,12 @@ assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
as_t *newas; as_t *newas;
newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as, newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
ASSEGMENT_DATA_SIZE (seg->length + num)); ASSEGMENT_DATA_SIZE (seg->length + num, 1));
if (newas) if (newas)
{ {
seg->as = 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; seg->length += num;
return seg; return seg;
} }
@ -263,8 +272,27 @@ assegment_normalise (struct assegment *head)
* and because it helps other lesser implementations ;) * and because it helps other lesser implementations ;)
*/ */
if (seg->type == AS_SET || seg->type == AS_CONFED_SET) if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
{
int tail = 0;
int i;
qsort (seg->as, seg->length, sizeof(as_t), int_cmp); 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 /* read ahead from the current, pinned segment while the segments
* are packable/mergeable. Append all following packable segments * are packable/mergeable. Append all following packable segments
* to the segment we have pinned and remove these appended * to the segment we have pinned and remove these appended
@ -420,6 +448,12 @@ aspath_count_hops (struct aspath *aspath)
return count; 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 unsigned int
aspath_size (struct aspath *aspath) aspath_size (struct aspath *aspath)
{ {
@ -428,7 +462,7 @@ aspath_size (struct aspath *aspath)
while (seg) while (seg)
{ {
size += ASSEGMENT_SIZE(seg->length); size += ASSEGMENT_SIZE(seg->length, 1);
seg = seg->next; seg = seg->next;
} }
return size; return size;
@ -454,6 +488,39 @@ aspath_highest (struct aspath *aspath)
return highest; 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. */ /* Convert aspath structure to string expression. */
static char * static char *
aspath_make_str_count (struct aspath *as) 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'. * 2 chars for segment delimiters, and the final '\0'.
* Hopefully this is large enough to avoid hitting the realloc * Hopefully this is large enough to avoid hitting the realloc
* code below for most common sequences. * 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) #define ASN_STR_LEN (5 + 1)
str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 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 * have been wrong. need 5 chars for ASN, a seperator each and
* potentially two segment delimiters, plus a space between each * potentially two segment delimiters, plus a space between each
* segment and trailing zero. * 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) #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
if ( (len + SEGMENT_STR_LEN(seg)) > str_size) if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
@ -605,7 +678,7 @@ aspath_hash_alloc (void *arg)
{ {
struct aspath *aspath; struct aspath *aspath;
/* New aspath strucutre is needed. */ /* New aspath structure is needed. */
aspath = aspath_dup (arg); aspath = aspath_dup (arg);
/* Malformed AS path value. */ /* Malformed AS path value. */
@ -620,7 +693,7 @@ aspath_hash_alloc (void *arg)
/* parse as-segment byte stream in struct assegment */ /* parse as-segment byte stream in struct assegment */
static 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_header segh;
struct assegment *seg, *prev = NULL, *head = NULL; struct assegment *seg, *prev = NULL, *head = NULL;
@ -630,27 +703,37 @@ assegments_parse (struct stream *s, size_t length)
if (length == 0) if (length == 0)
return NULL; return NULL;
if (BGP_DEBUG (as4, AS4_SEGMENT))
zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
(unsigned long) length);
/* basic checks */ /* basic checks */
if ( (STREAM_READABLE(s) < length) if ( (STREAM_READABLE(s) < length)
|| (STREAM_READABLE(s) < AS_HEADER_SIZE) || (STREAM_READABLE(s) < AS_HEADER_SIZE)
|| (length % AS_VALUE_SIZE)) || (length % AS16_VALUE_SIZE ))
return NULL; return NULL;
while ( (STREAM_READABLE(s) > AS_HEADER_SIZE) while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
&& (bytes < length)) && (bytes < length))
{ {
int i; int i;
int seg_size;
/* softly softly, get the header first on its own */ /* softly softly, get the header first on its own */
segh.type = stream_getc (s); segh.type = stream_getc (s);
segh.length = 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.. */ /* check it.. */
if ( ((bytes + ASSEGMENT_SIZE(segh.length)) > length) if ( ((bytes + seg_size) > length)
/* 1771bis 4.3b: seg length contains one or more */ /* 1771bis 4.3b: seg length contains one or more */
|| (segh.length == 0) || (segh.length == 0)
/* Paranoia in case someone changes type of segment length */ /* 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) if (head)
assegment_free_all (head); assegment_free_all (head);
@ -666,9 +749,13 @@ assegments_parse (struct stream *s, size_t length)
head = prev = seg; head = prev = seg;
for (i = 0; i < segh.length; i++) for (i = 0; i < segh.length; i++)
seg->as[i] = stream_getw (s); seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
bytes += ASSEGMENT_SIZE(segh.length); bytes += seg_size;
if (BGP_DEBUG (as4, AS4_SEGMENT))
zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
(unsigned long) bytes);
prev = seg; 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 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. */ path hash then return it else make new AS path structure. */
struct aspath * 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 as;
struct aspath *find; struct aspath *find;
/* If length is odd it's malformed AS path. */ /* 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; 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. */ /* If already same aspath exist then return it. */
find = hash_get (ashash, &as, aspath_hash_alloc); find = hash_get (ashash, &as, aspath_hash_alloc);
@ -698,6 +791,8 @@ aspath_parse (struct stream *s, size_t length)
* optimised out. * optimised out.
*/ */
assegment_free_all (as.segments); assegment_free_all (as.segments);
if (as.str)
XFREE (MTYPE_AS_STR, as.str);
if (! find) if (! find)
return NULL; return NULL;
@ -707,13 +802,21 @@ aspath_parse (struct stream *s, size_t length)
} }
static inline void 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; int i;
assert (num <= AS_SEGMENT_MAX); assert (num <= AS_SEGMENT_MAX);
for (i = 0; i < num; i++) for (i = 0; i < num; i++)
if ( use32bit )
stream_putl (s, as[i]);
else
{
if ( as[i] <= BGP_AS_MAX )
stream_putw(s, as[i]); stream_putw(s, as[i]);
else
stream_putw(s, BGP_AS_TRANS);
}
} }
static inline size_t static inline size_t
@ -728,38 +831,51 @@ assegment_header_put (struct stream *s, u_char type, int length)
} }
/* write aspath data to stream */ /* write aspath data to stream */
void size_t
aspath_put (struct stream *s, struct aspath *as) aspath_put (struct stream *s, struct aspath *as, int use32bit )
{ {
struct assegment *seg = as->segments; struct assegment *seg = as->segments;
size_t bytes = 0;
if (!seg || seg->length == 0) if (!seg || seg->length == 0)
return; return 0;
if (seg) 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 written = 0;
int asns_packed = 0;
size_t lenp; size_t lenp;
/* Overlength segments have to be split up */ /* Overlength segments have to be split up */
while ( (seg->length - written) > AS_SEGMENT_MAX) while ( (seg->length - written) > AS_SEGMENT_MAX)
{ {
assegment_header_put (s, seg->type, 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; written += AS_SEGMENT_MAX;
bytes += ASSEGMENT_SIZE (written, use32bit);
} }
/* write the final segment, probably is also the first */ /* write the final segment, probably is also the first */
lenp = assegment_header_put (s, seg->type, seg->length - written); 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 /* Sequence-type segments can be 'packed' together
* Case of a segment which was overlength and split up * Case of a segment which was overlength and split up
* will be missed here, but that doesn't matter. * 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 /* NB: We should never normally get here given we
* normalise aspath data when parse them. However, better * 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 */ /* 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 */ /* update the length of the segment header */
stream_putc_at (s, lenp, stream_putc_at (s, lenp, seg->length - written + next->length);
seg->length - written + seg->next->length); asns_packed += next->length;
seg = seg->next->next; /* skip to past next */
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 /* This is for SNMP BGP4PATHATTRASPATHSEGMENT
@ -803,7 +923,7 @@ aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
*varlen = 0; *varlen = 0;
return NULL; 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); *varlen = stream_get_endp (snmp_stream);
return stream_pnt(snmp_stream); return stream_pnt(snmp_stream);
@ -861,8 +981,9 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)
int from; int from;
struct assegment *seg1 = as1->segments; struct assegment *seg1 = as1->segments;
struct assegment *seg2 = as2->segments; struct assegment *seg2 = as2->segments;
struct aspath *aspath; struct aspath *aspath = NULL;
struct assegment *asset; struct assegment *asset;
struct assegment *prevseg = NULL;
match = 0; match = 0;
minlen = 0; minlen = 0;
@ -885,11 +1006,19 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)
if (match) if (match)
{ {
struct assegment *seg = assegment_new (seg1->type, 0);
seg = assegment_append_asns (seg, seg1->as, match);
if (! aspath) if (! aspath)
{
aspath = aspath_new (); aspath = aspath_new ();
aspath->segments = assegment_new (seg1->type, 0); aspath->segments = seg;
aspath->segments = assegment_append_asns (aspath->segments, }
seg1->as, match); else
prevseg->next = seg;
prevseg = seg;
} }
if (match != minlen || match != seg1->length if (match != minlen || match != seg1->length
@ -1174,6 +1303,108 @@ aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
return 0; 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 /* Compare leftmost AS value for MED check. If as1's leftmost AS and
as2's leftmost AS is same return 1. (confederation as-path as2's leftmost AS is same return 1. (confederation as-path
only). */ only). */
@ -1273,7 +1504,7 @@ aspath_segment_add (struct aspath *as, int type)
struct aspath * struct aspath *
aspath_empty (void) aspath_empty (void)
{ {
return aspath_parse (NULL, 0); return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
} }
struct aspath * struct aspath *
@ -1316,7 +1547,7 @@ enum as_token
/* Return next token and point for string parse. */ /* Return next token and point for string parse. */
static const char * 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; const char *p = buf;
@ -1364,6 +1595,7 @@ aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
*token = as_token_asval; *token = as_token_asval;
asval = (*p - '0'); asval = (*p - '0');
p++; p++;
while (isdigit ((int) *p)) while (isdigit ((int) *p))
{ {
asval *= 10; asval *= 10;
@ -1384,7 +1616,7 @@ aspath_str2aspath (const char *str)
{ {
enum as_token token = as_token_unknown; enum as_token token = as_token_unknown;
u_short as_type; u_short as_type;
u_short asno = 0; u_long asno = 0;
struct aspath *aspath; struct aspath *aspath;
int needtype; int needtype;
@ -1451,24 +1683,11 @@ aspath_key_make (void *p)
{ {
struct aspath * aspath = (struct aspath *) p; struct aspath * aspath = (struct aspath *) p;
unsigned int key = 0; unsigned int key = 0;
unsigned int i;
struct assegment *seg = aspath->segments;
struct assegment *prev = NULL;
while (seg) if (!aspath->str)
{ aspath_str_update (aspath);
/* 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 = jhash (aspath->str, strlen(aspath->str), 2334325);
key += seg->as[i];
prev = seg;
seg = seg->next;
}
return key; return key;
} }

View 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_MIN 64512U
#define BGP_PRIVATE_AS_MAX 65535U #define BGP_PRIVATE_AS_MAX 65535U
/* we leave BGP_AS_MAX as the 16bit AS MAX number. */
#define BGP_AS_MAX 65535U #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 */ /* AS_PATH segment data in abstracted form, no limit is placed on length */
struct assegment struct assegment
@ -61,7 +65,7 @@ struct aspath
/* Prototypes. */ /* Prototypes. */
extern void aspath_init (void); extern void aspath_init (void);
extern void aspath_finish (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_dup (struct aspath *);
extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *); extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *);
extern struct aspath *aspath_prepend (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_count_confeds (struct aspath *);
extern unsigned int aspath_size (struct aspath *); extern unsigned int aspath_size (struct aspath *);
extern as_t aspath_highest (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 */ /* For SNMP BGP4PATHATTRASPATHSEGMENT, might be useful for debug */
extern u_char *aspath_snmp_pathseg (struct aspath *, size_t *); extern u_char *aspath_snmp_pathseg (struct aspath *, size_t *);

View File

@ -56,8 +56,10 @@ static struct message attr_str [] =
{ BGP_ATTR_RCID_PATH, "RCID_PATH" }, { BGP_ATTR_RCID_PATH, "RCID_PATH" },
{ BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
{ BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
{ BGP_ATTR_EXT_COMMUNITIES, "BGP_ATTR_EXT_COMMUNITIES" }, { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
{ BGP_ATTR_AS_PATHLIMIT, "BGP_ATTR_AS_PATHLIMIT" }, { BGP_ATTR_AS4_PATH, "AS4_PATH" },
{ BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
{ BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
{ 0, NULL } { 0, NULL }
}; };
int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); 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, bgp_attr_aspath (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag, u_char *startp) struct attr *attr, u_char flag, u_char *startp)
{ {
struct bgp *bgp;
struct aspath *aspath;
bgp_size_t total; bgp_size_t total;
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); 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; 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. */ /* In case of IBGP, length will be zero. */
attr->aspath = aspath_parse (peer->ibuf, length);
if (! attr->aspath) if (! attr->aspath)
{ {
zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); 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; 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; bgp = peer->bgp;
/* First AS check for EBGP. */ /* First AS check for EBGP. */
@ -851,11 +879,20 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
attr->aspath = aspath_intern (aspath); attr->aspath = aspath_intern (aspath);
} }
/* Forward pointer. */ return 0;
/* stream_forward_getp (peer->ibuf, length);*/
}
/* 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. */ /* Set aspath attribute flag. */
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
return 0; return 0;
} }
@ -981,17 +1018,26 @@ static int
bgp_attr_aggregator (struct peer *peer, bgp_size_t length, bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag) struct attr *attr, u_char flag)
{ {
int wantedlen = 6;
struct attr_extra *attre = bgp_attr_extra_get (attr); 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_send (peer,
BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1; return -1;
} }
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_as = stream_getw (peer->ibuf);
attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf); attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
@ -1001,6 +1047,145 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
return 0; 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. */ /* Community attribute. */
static int static int
bgp_attr_community (struct peer *peer, bgp_size_t length, 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; int ret;
u_char flag; u_char flag;
u_char type; u_char type = 0;
bgp_size_t length; bgp_size_t length;
u_char *startp, *endp; u_char *startp, *endp;
u_char *attr_endp; u_char *attr_endp;
u_char seen[BGP_ATTR_BITMAP_SIZE]; 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. */ /* Initialize bitmap. */
memset (seen, 0, BGP_ATTR_BITMAP_SIZE); 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) */ /* XXX warning: long int format, int arg (arg 5) */
zlog (peer->log, LOG_WARNING, zlog (peer->log, LOG_WARNING,
"%s error BGP attribute length %lu is smaller than min len", "%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_send (peer,
BGP_NOTIFY_UPDATE_ERR, 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: case BGP_ATTR_AS_PATH:
ret = bgp_attr_aspath (peer, length, attr, flag, startp); ret = bgp_attr_aspath (peer, length, attr, flag, startp);
break; break;
case BGP_ATTR_AS4_PATH:
ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
break;
case BGP_ATTR_NEXT_HOP: case BGP_ATTR_NEXT_HOP:
ret = bgp_attr_nexthop (peer, length, attr, flag, startp); ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
break; break;
@ -1416,6 +1610,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
case BGP_ATTR_AGGREGATOR: case BGP_ATTR_AGGREGATOR:
ret = bgp_attr_aggregator (peer, length, attr, flag); ret = bgp_attr_aggregator (peer, length, attr, flag);
break; break;
case BGP_ATTR_AS4_AGGREGATOR:
ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
break;
case BGP_ATTR_COMMUNITIES: case BGP_ATTR_COMMUNITIES:
ret = bgp_attr_community (peer, length, attr, flag); ret = bgp_attr_community (peer, length, attr, flag);
break; break;
@ -1480,6 +1677,51 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
return -1; 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. */ /* Finally intern unknown attribute. */
if (attr->extra && attr->extra->transit) if (attr->extra && attr->extra->transit)
attr->extra->transit = transit_intern (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) struct prefix_rd *prd, u_char *tag)
{ {
size_t cp; size_t cp;
unsigned int aspath_data_size; size_t aspath_sizep;
struct aspath *aspath; 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) if (! bgp)
bgp = bgp_get_default (); bgp = bgp_get_default ();
@ -1578,24 +1823,26 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
else else
aspath = attr->aspath; aspath = attr->aspath;
/* AS path attribute extended length bit check. */ /* If peer is not AS4 capable, then:
aspath_data_size = aspath_size (aspath); * - send the created AS_PATH out as AS4_PATH (optional, transitive),
if (aspath_data_size > 255) * 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_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_AS_PATH); stream_putc (s, BGP_ATTR_AS_PATH);
stream_putw (s, aspath_data_size); aspath_sizep = stream_get_endp (s);
} stream_putw (s, 0);
else stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
{
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) /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
aspath_free (aspath); * in the path
*/
if (!use32bit && aspath_has_as4 (aspath))
send_as4_path = 1; /* we'll do this later, at the correct place */
/* Nexthop attribute. */ /* Nexthop attribute. */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP) 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)) if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
{ {
assert (attr->extra); 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_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_AGGREGATOR); stream_putc (s, BGP_ATTR_AGGREGATOR);
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); stream_putc (s, 6);
stream_putw (s, attr->extra->aggregator_as);
/* 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); stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
} }
@ -1874,6 +2147,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 */ /* AS-Pathlimit */
if (attr->pathlimit.ttl) if (attr->pathlimit.ttl)
{ {
@ -1967,7 +2281,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
{ {
unsigned long cp; unsigned long cp;
unsigned long len; unsigned long len;
unsigned int aspathlen; size_t aspath_lenp;
struct aspath *aspath; struct aspath *aspath;
/* Remember current pointer. */ /* Remember current pointer. */
@ -1984,19 +2298,12 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
aspath = attr->aspath; 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_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_AS_PATH); stream_putc (s, BGP_ATTR_AS_PATH);
stream_putw (s, aspathlen); aspath_lenp = stream_get_endp (s);
} stream_putw (s, 0);
else
{ stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
stream_putc (s, BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_AS_PATH);
stream_putc (s, aspathlen);
}
aspath_put (s, aspath);
/* Nexthop attribute. */ /* Nexthop attribute. */
/* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */ /* 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); assert (attr->extra);
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_AGGREGATOR); stream_putc (s, BGP_ATTR_AGGREGATOR);
stream_putc (s, 6); stream_putc (s, 8);
stream_putw (s, attr->extra->aggregator_as); stream_putl (s, attr->extra->aggregator_as);
stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
} }

View File

@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_debug.h" #include "bgpd/bgp_debug.h"
#include "bgpd/bgp_community.h" #include "bgpd/bgp_community.h"
unsigned long conf_bgp_debug_as4;
unsigned long conf_bgp_debug_fsm; unsigned long conf_bgp_debug_fsm;
unsigned long conf_bgp_debug_events; unsigned long conf_bgp_debug_events;
unsigned long conf_bgp_debug_packet; 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_normal;
unsigned long conf_bgp_debug_zebra; unsigned long conf_bgp_debug_zebra;
unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_fsm; unsigned long term_bgp_debug_fsm;
unsigned long term_bgp_debug_events; unsigned long term_bgp_debug_events;
unsigned long term_bgp_debug_packet; unsigned long term_bgp_debug_packet;
@ -297,6 +299,92 @@ debug (unsigned int option)
return bgp_debug_option & 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, DEFUN (debug_bgp_fsm,
debug_bgp_fsm_cmd, debug_bgp_fsm_cmd,
"debug bgp fsm", "debug bgp fsm",
@ -651,6 +739,8 @@ DEFUN (no_debug_bgp_all,
TERM_DEBUG_OFF (keepalive, KEEPALIVE); TERM_DEBUG_OFF (keepalive, KEEPALIVE);
TERM_DEBUG_OFF (update, UPDATE_IN); TERM_DEBUG_OFF (update, UPDATE_IN);
TERM_DEBUG_OFF (update, UPDATE_OUT); 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 (fsm, FSM);
TERM_DEBUG_OFF (filter, FILTER); TERM_DEBUG_OFF (filter, FILTER);
TERM_DEBUG_OFF (zebra, ZEBRA); TERM_DEBUG_OFF (zebra, ZEBRA);
@ -693,6 +783,10 @@ DEFUN (show_debugging_bgp,
vty_out (vty, " BGP filter debugging is on%s", VTY_NEWLINE); vty_out (vty, " BGP filter debugging is on%s", VTY_NEWLINE);
if (BGP_DEBUG (zebra, ZEBRA)) if (BGP_DEBUG (zebra, ZEBRA))
vty_out (vty, " BGP zebra debugging is on%s", VTY_NEWLINE); 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); vty_out (vty, "%s", VTY_NEWLINE);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -708,6 +802,18 @@ bgp_config_write_debug (struct vty *vty)
write++; 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)) if (CONF_BGP_DEBUG (events, EVENTS))
{ {
vty_out (vty, "debug bgp events%s", VTY_NEWLINE); 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, &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 (ENABLE_NODE, &debug_bgp_fsm_cmd);
install_element (CONFIG_NODE, &debug_bgp_fsm_cmd); install_element (CONFIG_NODE, &debug_bgp_fsm_cmd);
install_element (ENABLE_NODE, &debug_bgp_events_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 (ENABLE_NODE, &debug_bgp_zebra_cmd);
install_element (CONFIG_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, &no_debug_bgp_fsm_cmd);
install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd); install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd); install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd);

View File

@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_DEBUG_H #ifndef _QUAGGA_BGP_DEBUG_H
#define _QUAGGA_BGP_DEBUG_H #define _QUAGGA_BGP_DEBUG_H
#include "bgp_attr.h"
/* sort of packet direction */ /* sort of packet direction */
#define DUMP_ON 1 #define DUMP_ON 1
#define DUMP_SEND 2 #define DUMP_SEND 2
@ -56,6 +58,7 @@ extern void bgp_packet_dump (struct stream *);
extern int debug (unsigned int option); 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_fsm;
extern unsigned long conf_bgp_debug_events; extern unsigned long conf_bgp_debug_events;
extern unsigned long conf_bgp_debug_packet; 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_normal;
extern unsigned long conf_bgp_debug_zebra; 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_fsm;
extern unsigned long term_bgp_debug_events; extern unsigned long term_bgp_debug_events;
extern unsigned long term_bgp_debug_packet; 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_normal;
extern unsigned long term_bgp_debug_zebra; 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_FSM 0x01
#define BGP_DEBUG_EVENTS 0x01 #define BGP_DEBUG_EVENTS 0x01
#define BGP_DEBUG_PACKET 0x01 #define BGP_DEBUG_PACKET 0x01

View File

@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "command.h" #include "command.h"
#include "prefix.h" #include "prefix.h"
#include "thread.h" #include "thread.h"
#include "linklist.h"
#include "bgpd/bgp_table.h" #include "bgpd/bgp_table.h"
#include "bgpd/bgpd.h" #include "bgpd/bgpd.h"
@ -53,7 +54,8 @@ enum MRT_MSG_TYPES {
MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */ MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */
MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */ MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */
MSG_PROTOCOL_OSPF, /* msg is an OSPF 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 *); static int bgp_dump_interval_func (struct thread *);
@ -191,137 +193,189 @@ bgp_dump_set_size (struct stream *s, int type)
} }
static void static void
bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi, bgp_dump_routes_index_table(struct bgp *bgp)
int type, unsigned int seq)
{ {
struct stream *obuf;
struct attr *attr;
struct peer *peer; struct peer *peer;
int plen; struct listnode *node;
int safi = 0; uint16_t peerno = 0;
struct stream *obuf;
/* Make dump stream. */
obuf = bgp_dump_obuf; obuf = bgp_dump_obuf;
stream_reset (obuf); stream_reset (obuf);
attr = info->attr; /* MRT header */
peer = info->peer; bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE);
/* We support MRT's old format. */ /* Collector BGP ID */
if (type == MSG_TABLE_DUMP) stream_put_in_addr (obuf, &bgp->router_id);
/* View name */
if(bgp->name)
{ {
bgp_dump_header (obuf, MSG_TABLE_DUMP, afi); stream_putw (obuf, strlen(bgp->name));
stream_putw (obuf, 0); /* View # */ stream_put(obuf, bgp->name, strlen(bgp->name));
stream_putw (obuf, seq); /* Sequence number. */
} }
else else
{ {
bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY); stream_putw(obuf, 0);
stream_putl (obuf, info->uptime); /* Time Last Change */
stream_putw (obuf, afi); /* Address Family */
stream_putc (obuf, safi); /* SAFI */
} }
if (afi == AFI_IP) /* Peer count */
stream_putw (obuf, listcount(bgp->peer));
/* Walk down all peers */
for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
{ {
if (type == MSG_TABLE_DUMP)
/* Peer's type */
if (sockunion_family(&peer->su) == AF_INET)
{ {
/* Prefix */ stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
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'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 #ifdef HAVE_IPV6
else if (afi == AFI_IP6) else if (sockunion_family(&peer->su) == AF_INET6)
{ {
if (type == MSG_TABLE_DUMP) stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
{
/* Prefix */
stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN);
stream_putc (obuf, p->prefixlen);
/* Status */
stream_putc (obuf, 1);
/* Originated */
stream_putl (obuf, info->uptime);
/* Peer's IP address */
stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
IPV6_MAX_BYTELEN);
/* Peer's AS number. */
stream_putw (obuf, peer->as);
/* Dump attribute. */
bgp_dump_routes_attr (obuf, attr, p);
}
else
{
;
}
} }
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
/* Set length. */ /* Peer's BGP ID */
bgp_dump_set_size (obuf, type); stream_put_in_addr (obuf, &peer->remote_id);
/* 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. */
/* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
stream_putl (obuf, peer->as);
/* Store the peer number for this peer */
peer->table_dump_index = peerno;
peerno++;
}
bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
fflush (bgp_dump_routes.fp); fflush (bgp_dump_routes.fp);
} }
/* Runs under child process. */ /* Runs under child process. */
static void static unsigned int
bgp_dump_routes_func (int afi) bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
{ {
struct stream *obuf; struct stream *obuf;
struct bgp_node *rn;
struct bgp_info *info; struct bgp_info *info;
struct bgp_node *rn;
struct bgp *bgp; struct bgp *bgp;
struct bgp_table *table; struct bgp_table *table;
unsigned int seq = 0;
obuf = bgp_dump_obuf;
bgp = bgp_get_default (); bgp = bgp_get_default ();
if (!bgp) if (!bgp)
return; return seq;
if (bgp_dump_routes.fp == NULL) 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. */ /* Walk down each BGP route. */
table = bgp->rib[afi][SAFI_UNICAST]; table = bgp->rib[afi][SAFI_UNICAST];
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
{
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) for (info = rn->info; info; info = info->next)
bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++); {
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 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. */ /* In case of bgp_dump_routes, we need special route dump function. */
if (bgp_dump->type == BGP_DUMP_ROUTES) 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 #ifdef HAVE_IPV6
bgp_dump_routes_func (AFI_IP6); bgp_dump_routes_func (AFI_IP6, 0, seq);
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
/* Close the file now. For a RIB dump there's no point in leaving /* Close the file now. For a RIB dump there's no point in leaving
* it open until the next scheduled dump starts. */ * it open until the next scheduled dump starts. */
@ -356,13 +410,21 @@ bgp_dump_interval_func (struct thread *t)
/* Dump common information. */ /* Dump common information. */
static void 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}; 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. */ /* Source AS number and Destination AS number. */
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->as);
stream_putw (obuf, peer->local_as); stream_putw (obuf, peer->local_as);
}
if (peer->su.sa.sa_family == AF_INET) 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; obuf = bgp_dump_obuf;
stream_reset (obuf); stream_reset (obuf);
bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE); bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4);
bgp_dump_common (obuf, peer); bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
stream_putw (obuf, status_old); stream_putw (obuf, status_old);
stream_putw (obuf, status_new); stream_putw (obuf, status_new);
@ -437,8 +499,15 @@ bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
stream_reset (obuf); stream_reset (obuf);
/* Dump header and common part. */ /* Dump header and common part. */
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_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
bgp_dump_common (obuf, peer); }
bgp_dump_common (obuf, peer, 0);
/* Packet contents. */ /* Packet contents. */
stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet)); stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));

View File

@ -29,10 +29,24 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define BGP4MP_MESSAGE 1 #define BGP4MP_MESSAGE 1
#define BGP4MP_ENTRY 2 #define BGP4MP_ENTRY 2
#define BGP4MP_SNAPSHOT 3 #define BGP4MP_SNAPSHOT 3
#define BGP4MP_MESSAGE_AS4 4
#define BGP4MP_STATE_CHANGE_AS4 5
#define BGP_DUMP_HEADER_SIZE 12 #define BGP_DUMP_HEADER_SIZE 12
#define BGP_DUMP_MSG_HEADER 40 #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_init (void);
extern void bgp_dump_state (struct peer *, int, int); extern void bgp_dump_state (struct peer *, int, int);
extern void bgp_dump_packet (struct peer *, int, struct stream *); extern void bgp_dump_packet (struct peer *, int, struct stream *);

View File

@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h" #include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_aspath.h"
/* Hash of community attribute. */ /* Hash of community attribute. */
struct hash *ecomhash; struct hash *ecomhash;
@ -228,8 +229,9 @@ ecommunity_unintern (struct ecommunity *ecom)
/* Utinity function to make hash key. */ /* Utinity function to make hash key. */
unsigned int unsigned int
ecommunity_hash_make (struct ecommunity *ecom) ecommunity_hash_make (void *arg)
{ {
const struct ecommunity *ecom = arg;
int c; int c;
unsigned int key; unsigned int key;
u_int8_t *pnt; u_int8_t *pnt;
@ -245,9 +247,11 @@ ecommunity_hash_make (struct ecommunity *ecom)
/* Compare two Extended Communities Attribute structure. */ /* Compare two Extended Communities Attribute structure. */
int int
ecommunity_cmp (const struct ecommunity *ecom1, ecommunity_cmp (void *arg1, void *arg2)
const struct ecommunity *ecom2)
{ {
const struct ecommunity *ecom1 = arg1;
const struct ecommunity *ecom2 = arg2;
if (ecom1->size == ecom2->size if (ecom1->size == ecom2->size
&& memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0) && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0)
return 1; return 1;
@ -256,7 +260,7 @@ ecommunity_cmp (const struct ecommunity *ecom1,
/* Initialize Extended Comminities related hash. */ /* Initialize Extended Comminities related hash. */
void void
ecommunity_init () ecommunity_init (void)
{ {
ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp); 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 dot = 0;
int digit = 0; int digit = 0;
int separator = 0; int separator = 0;
u_int32_t val_low = 0;
u_int32_t val_high = 0;
const char *p = str; const char *p = str;
char *endptr;
struct in_addr ip; 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. */ /* Skip white space. */
while (isspace ((int) *p)) while (isspace ((int) *p))
@ -346,6 +351,19 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
goto error; 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 == '.') while (isdigit ((int) *p) || *p == ':' || *p == '.')
{ {
if (*p == ':') if (*p == ':')
@ -356,22 +374,27 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
separator = 1; separator = 1;
digit = 0; digit = 0;
if (dot)
{
if ((p - str) > INET_ADDRSTRLEN) if ((p - str) > INET_ADDRSTRLEN)
goto error; goto error;
memset (buf, 0, INET_ADDRSTRLEN + 1);
memcpy (buf, str, p - str);
memset (ipstr, 0, INET_ADDRSTRLEN + 1); if (dot)
memcpy (ipstr, str, p - str); {
/* Parsing A.B.C.D in:
ret = inet_aton (ipstr, &ip); * A.B.C.D:MN
*/
ret = inet_aton (buf, &ip);
if (ret == 0) if (ret == 0)
goto error; goto error;
} }
else else
val_high = val_low; {
/* ASN */
val_low = 0; as = strtoul (buf, &endptr, 10);
if (*endptr != '\0' || as == BGP_AS4_MAX)
goto error;
}
} }
else if (*p == '.') else if (*p == '.')
{ {
@ -384,8 +407,13 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
else else
{ {
digit = 1; digit = 1;
val_low *= 10;
val_low += (*p - '0'); /* We're past the IP/ASN part */
if (separator)
{
val *= 10;
val += (*p - '0');
}
} }
p++; p++;
} }
@ -397,22 +425,40 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
/* Encode result into routing distinguisher. */ /* Encode result into routing distinguisher. */
if (dot) if (dot)
{ {
if (val > UINT16_MAX)
goto error;
eval->val[0] = ECOMMUNITY_ENCODE_IP; eval->val[0] = ECOMMUNITY_ENCODE_IP;
eval->val[1] = 0; eval->val[1] = 0;
memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
eval->val[6] = (val_low >> 8) & 0xff; eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val_low & 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 else
{ {
eval->val[0] = ECOMMUNITY_ENCODE_AS; eval->val[0] = ECOMMUNITY_ENCODE_AS;
eval->val[1] = 0; eval->val[1] = 0;
eval->val[2] = (val_high >>8) & 0xff;
eval->val[3] = val_high & 0xff; eval->val[2] = (as >>8) & 0xff;
eval->val[4] = (val_low >>24) & 0xff; eval->val[3] = as & 0xff;
eval->val[5] = (val_low >>16) & 0xff; eval->val[4] = (val >>24) & 0xff;
eval->val[6] = (val_low >>8) & 0xff; eval->val[5] = (val >>16) & 0xff;
eval->val[7] = val_low & 0xff; eval->val[6] = (val >>8) & 0xff;
eval->val[7] = val & 0xff;
} }
*token = ecommunity_token_val; *token = ecommunity_token_val;
return p; return p;
@ -533,7 +579,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
u_int8_t *pnt; u_int8_t *pnt;
int encode = 0; int encode = 0;
int type = 0; int type = 0;
#define ECOMMUNITY_STR_DEFAULT_LEN 26 #define ECOMMUNITY_STR_DEFAULT_LEN 27
int str_size; int str_size;
int str_pnt; int str_pnt;
char *str_buf; char *str_buf;
@ -576,7 +622,8 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
/* High-order octet of type. */ /* High-order octet of type. */
encode = *pnt++; 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, "?"); len = sprintf (str_buf + str_pnt, "?");
str_pnt += len; str_pnt += len;
@ -618,6 +665,21 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
} }
/* Put string into buffer. */ /* 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) if (encode == ECOMMUNITY_ENCODE_AS)
{ {
eas.as = (*pnt++ << 8); eas.as = (*pnt++ << 8);

View File

@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* High-order octet of the Extended Communities type field. */ /* High-order octet of the Extended Communities type field. */
#define ECOMMUNITY_ENCODE_AS 0x00 #define ECOMMUNITY_ENCODE_AS 0x00
#define ECOMMUNITY_ENCODE_IP 0x01 #define ECOMMUNITY_ENCODE_IP 0x01
#define ECOMMUNITY_ENCODE_AS4 0x02
/* Low-order octet of the Extended Communityes type field. */ /* Low-order octet of the Extended Communityes type field. */
#define ECOMMUNITY_ROUTE_TARGET 0x02 #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_dup (struct ecommunity *);
extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *); extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *);
extern struct ecommunity *ecommunity_intern (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 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 struct ecommunity *ecommunity_str2com (const char *, int, int);
extern char *ecommunity_ecom2str (struct ecommunity *, int); extern char *ecommunity_ecom2str (struct ecommunity *, int);
extern int ecommunity_match (const struct ecommunity *, const struct ecommunity *); extern int ecommunity_match (const struct ecommunity *, const struct ecommunity *);

View File

@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_fsm.h" #include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_packet.h" #include "bgpd/bgp_packet.h"
#include "bgpd/bgp_open.h" #include "bgpd/bgp_open.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_vty.h" #include "bgpd/bgp_vty.h"
/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can /* 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; 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[] = static struct message capcode_str[] =
{ {
{ 0, ""}, { 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:
case CAPABILITY_CODE_ORF_OLD: case CAPABILITY_CODE_ORF_OLD:
case CAPABILITY_CODE_RESTART: case CAPABILITY_CODE_RESTART:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC: case CAPABILITY_CODE_DYNAMIC:
/* Check length. */ /* Check length. */
if (caphdr.length < cap_minsizes[caphdr.code]) 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: case CAPABILITY_CODE_DYNAMIC:
SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
break; 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: default:
if (caphdr.code > 128) if (caphdr.code > 128)
{ {
@ -615,6 +638,86 @@ strict_capability_same (struct peer *peer)
return 1; 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 */ /* Parse open option */
int int
bgp_open_option_parse (struct peer *peer, u_char length, int *capability) 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; unsigned long cp;
afi_t afi; afi_t afi;
safi_t safi; safi_t safi;
as_t local_as;
/* Remember current pointer for Opt Parm Len. */ /* Remember current pointer for Opt Parm Len. */
cp = stream_get_endp (s); 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);
stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); 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. */ /* ORF capability. */
for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)

View File

@ -48,6 +48,11 @@ struct capability_orf_entry
} __attribute__ ((packed)); } __attribute__ ((packed));
#pragma pack() #pragma pack()
struct capability_as4
{
uint32_t as4;
};
struct graceful_restart_af struct graceful_restart_af
{ {
u_int16_t afi; u_int16_t afi;
@ -100,6 +105,7 @@ struct capability_gr
extern int bgp_open_option_parse (struct peer *, u_char, int *); extern int bgp_open_option_parse (struct peer *, u_char, int *);
extern void bgp_open_capability (struct stream *, struct peer *); extern void bgp_open_capability (struct stream *, struct peer *);
extern void bgp_capability_vty_out (struct vty *, 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 *); extern int bgp_afi_safi_valid_indices (afi_t, safi_t *);
#endif /* _QUAGGA_BGP_OPEN_H */ #endif /* _QUAGGA_BGP_OPEN_H */

View File

@ -804,7 +804,8 @@ bgp_open_send (struct peer *peer)
/* Set open packet values. */ /* Set open packet values. */
stream_putc (s, BGP_VERSION_4); /* BGP version */ 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_putw (s, send_holdtime); /* Hold Time */
stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */ 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 holdtime;
u_int16_t send_holdtime; u_int16_t send_holdtime;
as_t remote_as; as_t remote_as;
as_t as4 = 0;
struct peer *realpeer; struct peer *realpeer;
struct in_addr remote_id; struct in_addr remote_id;
int capability; int capability;
@ -1186,10 +1188,75 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
/* Receive OPEN message log */ /* Receive OPEN message log */
if (BGP_DEBUG (normal, NORMAL)) if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s rcv OPEN, version %d, remote-as %d, holdtime %d, id %s", zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %d,"
" holdtime %d, id %s",
peer->host, version, remote_as, holdtime, peer->host, version, remote_as, holdtime,
inet_ntoa (remote_id)); 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. */ /* Lookup peer from Open packet. */
if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) 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; peer->v_keepalive = peer->v_holdtime / 3;
/* Open option part parse. */ /* Open option part parse. */
capability = 0;
optlen = stream_getc (peer->ibuf);
if (optlen != 0) if (optlen != 0)
{ {
ret = bgp_open_option_parse (peer, optlen, &capability); 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_afi_safi_valid_indices (afi, &safi))
{ {
if (BGP_DEBUG (normal, NORMAL)) if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid", zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid "
peer->host, afi, safi); "(%u/%u)", peer->host, afi, safi);
continue; continue;
} }
@ -2097,7 +2162,6 @@ int
bgp_capability_receive (struct peer *peer, bgp_size_t size) bgp_capability_receive (struct peer *peer, bgp_size_t size)
{ {
u_char *pnt; u_char *pnt;
int ret;
/* Fetch pointer. */ /* Fetch pointer. */
pnt = stream_pnt (peer->ibuf); 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_send (peer,
BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_ERR,
BGP_NOTIFY_HEADER_BAD_MESTYPE); BGP_NOTIFY_HEADER_BAD_MESTYPE);
return; return -1;
} }
/* Status must be Established. */ /* Status must be Established. */
@ -2122,7 +2186,7 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size)
plog_err (peer->log, plog_err (peer->log,
"%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); "%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); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
return; return -1;
} }
/* Parse packet. */ /* Parse packet. */

View File

@ -3337,7 +3337,7 @@ DEFUN (no_set_atomic_aggregate,
DEFUN (set_aggregator_as, DEFUN (set_aggregator_as,
set_aggregator_as_cmd, 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 SET_STR
"BGP aggregator attribute\n" "BGP aggregator attribute\n"
"AS number of aggregator\n" "AS number of aggregator\n"
@ -3349,7 +3349,7 @@ DEFUN (set_aggregator_as,
struct in_addr address; struct in_addr address;
char *argstr; 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); ret = inet_aton (argv[1], &address);
if (ret == 0) if (ret == 0)
@ -3386,7 +3386,7 @@ DEFUN (no_set_aggregator_as,
if (argv == 0) if (argv == 0)
return bgp_route_set_delete (vty, vty->index, "aggregator as", NULL); 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); ret = inet_aton (argv[1], &address);
if (ret == 0) if (ret == 0)
@ -3409,7 +3409,7 @@ DEFUN (no_set_aggregator_as,
ALIAS (no_set_aggregator_as, ALIAS (no_set_aggregator_as,
no_set_aggregator_as_val_cmd, 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 NO_STR
SET_STR SET_STR
"BGP aggregator attribute\n" "BGP aggregator attribute\n"

View File

@ -308,7 +308,7 @@ DEFUN_DEPRECATED (neighbor_version,
/* "router bgp" commands. */ /* "router bgp" commands. */
DEFUN (router_bgp, DEFUN (router_bgp,
router_bgp_cmd, router_bgp_cmd,
"router bgp <1-65535>", "router bgp CMD_AS_RANGE",
ROUTER_STR ROUTER_STR
BGP_STR BGP_STR
AS_STR) AS_STR)
@ -318,7 +318,7 @@ DEFUN (router_bgp,
struct bgp *bgp; struct bgp *bgp;
const char *name = NULL; 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) if (argc == 2)
name = argv[1]; name = argv[1];
@ -348,7 +348,7 @@ DEFUN (router_bgp,
ALIAS (router_bgp, ALIAS (router_bgp,
router_bgp_view_cmd, router_bgp_view_cmd,
"router bgp <1-65535> view WORD", "router bgp CMD_AS_RANGE view WORD",
ROUTER_STR ROUTER_STR
BGP_STR BGP_STR
AS_STR AS_STR
@ -358,7 +358,7 @@ ALIAS (router_bgp,
/* "no router bgp" commands. */ /* "no router bgp" commands. */
DEFUN (no_router_bgp, DEFUN (no_router_bgp,
no_router_bgp_cmd, no_router_bgp_cmd,
"no router bgp <1-65535>", "no router bgp CMD_AS_RANGE",
NO_STR NO_STR
ROUTER_STR ROUTER_STR
BGP_STR BGP_STR
@ -368,7 +368,7 @@ DEFUN (no_router_bgp,
struct bgp *bgp; struct bgp *bgp;
const char *name = NULL; 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) if (argc == 2)
name = argv[1]; name = argv[1];
@ -388,7 +388,7 @@ DEFUN (no_router_bgp,
ALIAS (no_router_bgp, ALIAS (no_router_bgp,
no_router_bgp_view_cmd, no_router_bgp_view_cmd,
"no router bgp <1-65535> view WORD", "no router bgp CMD_AS_RANGE view WORD",
NO_STR NO_STR
ROUTER_STR ROUTER_STR
BGP_STR BGP_STR
@ -539,7 +539,7 @@ ALIAS (no_bgp_cluster_id,
DEFUN (bgp_confederation_identifier, DEFUN (bgp_confederation_identifier,
bgp_confederation_identifier_cmd, bgp_confederation_identifier_cmd,
"bgp confederation identifier <1-65535>", "bgp confederation identifier CMD_AS_RANGE",
"BGP specific commands\n" "BGP specific commands\n"
"AS confederation parameters\n" "AS confederation parameters\n"
"AS number\n" "AS number\n"
@ -550,7 +550,7 @@ DEFUN (bgp_confederation_identifier,
bgp = vty->index; 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); bgp_confederation_id_set (bgp, as);
@ -571,7 +571,7 @@ DEFUN (no_bgp_confederation_identifier,
bgp = vty->index; bgp = vty->index;
if (argc == 1) 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); bgp_confederation_id_unset (bgp);
@ -580,7 +580,7 @@ DEFUN (no_bgp_confederation_identifier,
ALIAS (no_bgp_confederation_identifier, ALIAS (no_bgp_confederation_identifier,
no_bgp_confederation_identifier_arg_cmd, no_bgp_confederation_identifier_arg_cmd,
"no bgp confederation identifier <1-65535>", "no bgp confederation identifier CMD_AS_RANGE",
NO_STR NO_STR
"BGP specific commands\n" "BGP specific commands\n"
"AS confederation parameters\n" "AS confederation parameters\n"
@ -589,7 +589,7 @@ ALIAS (no_bgp_confederation_identifier,
DEFUN (bgp_confederation_peers, DEFUN (bgp_confederation_peers,
bgp_confederation_peers_cmd, bgp_confederation_peers_cmd,
"bgp confederation peers .<1-65535>", "bgp confederation peers .CMD_AS_RANGE",
"BGP specific commands\n" "BGP specific commands\n"
"AS confederation parameters\n" "AS confederation parameters\n"
"Peer ASs in BGP confederation\n" "Peer ASs in BGP confederation\n"
@ -603,7 +603,7 @@ DEFUN (bgp_confederation_peers,
for (i = 0; i < argc; i++) 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) if (bgp->as == as)
{ {
@ -619,7 +619,7 @@ DEFUN (bgp_confederation_peers,
DEFUN (no_bgp_confederation_peers, DEFUN (no_bgp_confederation_peers,
no_bgp_confederation_peers_cmd, no_bgp_confederation_peers_cmd,
"no bgp confederation peers .<1-65535>", "no bgp confederation peers .CMD_AS_RANGE",
NO_STR NO_STR
"BGP specific commands\n" "BGP specific commands\n"
"AS confederation parameters\n" "AS confederation parameters\n"
@ -634,7 +634,7 @@ DEFUN (no_bgp_confederation_peers,
for (i = 0; i < argc; i++) 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); bgp_confederation_peers_remove (bgp, as);
} }
@ -1249,7 +1249,7 @@ peer_remote_as_vty (struct vty *vty, const char *peer_str,
bgp = vty->index; bgp = vty->index;
/* Get AS number. */ /* 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. */ /* If peer is peer group, call proper function. */
ret = str2sockunion (peer_str, &su); ret = str2sockunion (peer_str, &su);
@ -1288,7 +1288,7 @@ peer_remote_as_vty (struct vty *vty, const char *peer_str,
DEFUN (neighbor_remote_as, DEFUN (neighbor_remote_as,
neighbor_remote_as_cmd, neighbor_remote_as_cmd,
NEIGHBOR_CMD2 "remote-as <1-65535>", NEIGHBOR_CMD2 "remote-as CMD_AS_RANGE",
NEIGHBOR_STR NEIGHBOR_STR
NEIGHBOR_ADDR_STR2 NEIGHBOR_ADDR_STR2
"Specify a BGP neighbor\n" "Specify a BGP neighbor\n"
@ -1352,7 +1352,7 @@ DEFUN (no_neighbor,
ALIAS (no_neighbor, ALIAS (no_neighbor,
no_neighbor_remote_as_cmd, no_neighbor_remote_as_cmd,
NO_NEIGHBOR_CMD "remote-as <1-65535>", NO_NEIGHBOR_CMD "remote-as CMD_AS_RANGE",
NO_STR NO_STR
NEIGHBOR_STR NEIGHBOR_STR
NEIGHBOR_ADDR_STR NEIGHBOR_ADDR_STR
@ -1382,7 +1382,7 @@ DEFUN (no_neighbor_peer_group,
DEFUN (no_neighbor_peer_group_remote_as, DEFUN (no_neighbor_peer_group_remote_as,
no_neighbor_peer_group_remote_as_cmd, no_neighbor_peer_group_remote_as_cmd,
"no neighbor WORD remote-as <1-65535>", "no neighbor WORD remote-as CMD_AS_RANGE",
NO_STR NO_STR
NEIGHBOR_STR NEIGHBOR_STR
"Neighbor tag\n" "Neighbor tag\n"
@ -1404,7 +1404,7 @@ DEFUN (no_neighbor_peer_group_remote_as,
DEFUN (neighbor_local_as, DEFUN (neighbor_local_as,
neighbor_local_as_cmd, neighbor_local_as_cmd,
NEIGHBOR_CMD2 "local-as <1-65535>", NEIGHBOR_CMD2 "local-as CMD_AS_RANGE",
NEIGHBOR_STR NEIGHBOR_STR
NEIGHBOR_ADDR_STR2 NEIGHBOR_ADDR_STR2
"Specify a local-as number\n" "Specify a local-as number\n"
@ -1423,7 +1423,7 @@ DEFUN (neighbor_local_as,
DEFUN (neighbor_local_as_no_prepend, DEFUN (neighbor_local_as_no_prepend,
neighbor_local_as_no_prepend_cmd, 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_STR
NEIGHBOR_ADDR_STR2 NEIGHBOR_ADDR_STR2
"Specify a local-as number\n" "Specify a local-as number\n"
@ -1462,7 +1462,7 @@ DEFUN (no_neighbor_local_as,
ALIAS (no_neighbor_local_as, ALIAS (no_neighbor_local_as,
no_neighbor_local_as_val_cmd, no_neighbor_local_as_val_cmd,
NO_NEIGHBOR_CMD2 "local-as <1-65535>", NO_NEIGHBOR_CMD2 "local-as CMD_AS_RANGE",
NO_STR NO_STR
NEIGHBOR_STR NEIGHBOR_STR
NEIGHBOR_ADDR_STR2 NEIGHBOR_ADDR_STR2
@ -1471,7 +1471,7 @@ ALIAS (no_neighbor_local_as,
ALIAS (no_neighbor_local_as, ALIAS (no_neighbor_local_as,
no_neighbor_local_as_val2_cmd, 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 NO_STR
NEIGHBOR_STR NEIGHBOR_STR
NEIGHBOR_ADDR_STR2 NEIGHBOR_ADDR_STR2
@ -4037,7 +4037,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
if (ret < 0) if (ret < 0)
bgp_clear_vty_error (vty, peer, afi, safi, ret); bgp_clear_vty_error (vty, peer, afi, safi, ret);
} }
return 0; return CMD_SUCCESS;
} }
/* Clear specified neighbors. */ /* Clear specified neighbors. */
@ -4051,13 +4051,13 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
if (ret < 0) if (ret < 0)
{ {
vty_out (vty, "Malformed address: %s%s", arg, VTY_NEWLINE); vty_out (vty, "Malformed address: %s%s", arg, VTY_NEWLINE);
return -1; return CMD_WARNING;
} }
peer = peer_lookup (bgp, &su); peer = peer_lookup (bgp, &su);
if (! peer) if (! peer)
{ {
vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE); vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE);
return -1; return CMD_WARNING;
} }
if (stype == BGP_CLEAR_SOFT_NONE) 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) if (ret < 0)
bgp_clear_vty_error (vty, peer, afi, safi, ret); bgp_clear_vty_error (vty, peer, afi, safi, ret);
return 0; return CMD_SUCCESS;
} }
/* Clear all peer-group members. */ /* 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) if (! group)
{ {
vty_out (vty, "%%BGP: No such peer-group %s%s", arg, VTY_NEWLINE); 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)) 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) if (ret < 0)
bgp_clear_vty_error (vty, peer, afi, safi, ret); bgp_clear_vty_error (vty, peer, afi, safi, ret);
} }
return 0; return CMD_SUCCESS;
} }
if (sort == clear_external) 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) if (ret < 0)
bgp_clear_vty_error (vty, peer, afi, safi, ret); bgp_clear_vty_error (vty, peer, afi, safi, ret);
} }
return 0; return CMD_SUCCESS;
} }
if (sort == clear_as) if (sort == clear_as)
{ {
as_t as; as_t as;
unsigned long as_ul; unsigned long as_ul;
char *endptr = NULL;
int find = 0; int find = 0;
as_ul = strtoul(arg, &endptr, 10); VTY_GET_LONG ("AS", as_ul, arg);
if ((as_ul == ULONG_MAX) || (*endptr != '\0') || (as_ul > USHRT_MAX)) if (!as_ul)
{ {
vty_out (vty, "Invalid AS number%s", VTY_NEWLINE); vty_out (vty, "Invalid AS number%s", VTY_NEWLINE);
return -1; return CMD_WARNING;
} }
as = (as_t) as_ul; 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) if (! find)
vty_out (vty, "%%BGP: No peer is configured with AS %s%s", arg, vty_out (vty, "%%BGP: No peer is configured with AS %s%s", arg,
VTY_NEWLINE); VTY_NEWLINE);
return 0; return CMD_SUCCESS;
} }
return 0; return CMD_SUCCESS;
} }
static int 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, enum clear_sort sort, enum bgp_clear_type stype,
const char *arg) const char *arg)
{ {
int ret;
struct bgp *bgp; struct bgp *bgp;
/* BGP structure lookup. */ /* 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); return bgp_clear (vty, bgp, afi, safi, sort, stype, arg);
if (ret < 0)
return CMD_WARNING;
return CMD_SUCCESS;
} }
DEFUN (clear_ip_bgp_all, DEFUN (clear_ip_bgp_all,
@ -4328,7 +4322,7 @@ ALIAS (clear_ip_bgp_external,
DEFUN (clear_ip_bgp_as, DEFUN (clear_ip_bgp_as,
clear_ip_bgp_as_cmd, clear_ip_bgp_as_cmd,
"clear ip bgp <1-65535>", "clear ip bgp CMD_AS_RANGE",
CLEAR_STR CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -4339,14 +4333,14 @@ DEFUN (clear_ip_bgp_as,
ALIAS (clear_ip_bgp_as, ALIAS (clear_ip_bgp_as,
clear_bgp_as_cmd, clear_bgp_as_cmd,
"clear bgp <1-65535>", "clear bgp CMD_AS_RANGE",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Clear peers with the AS number\n") "Clear peers with the AS number\n")
ALIAS (clear_ip_bgp_as, ALIAS (clear_ip_bgp_as,
clear_bgp_ipv6_as_cmd, clear_bgp_ipv6_as_cmd,
"clear bgp ipv6 <1-65535>", "clear bgp ipv6 CMD_AS_RANGE",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Address family\n" "Address family\n"
@ -4858,7 +4852,7 @@ ALIAS (clear_bgp_external_soft_out,
DEFUN (clear_ip_bgp_as_soft_out, DEFUN (clear_ip_bgp_as_soft_out,
clear_ip_bgp_as_soft_out_cmd, clear_ip_bgp_as_soft_out_cmd,
"clear ip bgp <1-65535> soft out", "clear ip bgp CMD_AS_RANGE soft out",
CLEAR_STR CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -4872,7 +4866,7 @@ DEFUN (clear_ip_bgp_as_soft_out,
ALIAS (clear_ip_bgp_as_soft_out, ALIAS (clear_ip_bgp_as_soft_out,
clear_ip_bgp_as_out_cmd, clear_ip_bgp_as_out_cmd,
"clear ip bgp <1-65535> out", "clear ip bgp CMD_AS_RANGE out",
CLEAR_STR CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -4881,7 +4875,7 @@ ALIAS (clear_ip_bgp_as_soft_out,
DEFUN (clear_ip_bgp_as_ipv4_soft_out, DEFUN (clear_ip_bgp_as_ipv4_soft_out,
clear_ip_bgp_as_ipv4_soft_out_cmd, 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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -4902,7 +4896,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_out,
ALIAS (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_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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -4914,7 +4908,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_out,
DEFUN (clear_ip_bgp_as_vpnv4_soft_out, DEFUN (clear_ip_bgp_as_vpnv4_soft_out,
clear_ip_bgp_as_vpnv4_soft_out_cmd, 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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -4930,7 +4924,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_out,
ALIAS (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_as_vpnv4_out_cmd,
"clear ip bgp <1-65535> vpnv4 unicast out", "clear ip bgp CMD_AS_RANGE vpnv4 unicast out",
CLEAR_STR CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -4941,7 +4935,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_out,
DEFUN (clear_bgp_as_soft_out, DEFUN (clear_bgp_as_soft_out,
clear_bgp_as_soft_out_cmd, clear_bgp_as_soft_out_cmd,
"clear bgp <1-65535> soft out", "clear bgp CMD_AS_RANGE soft out",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Clear peers with the AS number\n" "Clear peers with the AS number\n"
@ -4954,7 +4948,7 @@ DEFUN (clear_bgp_as_soft_out,
ALIAS (clear_bgp_as_soft_out, ALIAS (clear_bgp_as_soft_out,
clear_bgp_ipv6_as_soft_out_cmd, clear_bgp_ipv6_as_soft_out_cmd,
"clear bgp ipv6 <1-65535> soft out", "clear bgp ipv6 CMD_AS_RANGE soft out",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Address family\n" "Address family\n"
@ -4964,7 +4958,7 @@ ALIAS (clear_bgp_as_soft_out,
ALIAS (clear_bgp_as_soft_out, ALIAS (clear_bgp_as_soft_out,
clear_bgp_as_out_cmd, clear_bgp_as_out_cmd,
"clear bgp <1-65535> out", "clear bgp CMD_AS_RANGE out",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Clear peers with the AS number\n" "Clear peers with the AS number\n"
@ -4972,7 +4966,7 @@ ALIAS (clear_bgp_as_soft_out,
ALIAS (clear_bgp_as_soft_out, ALIAS (clear_bgp_as_soft_out,
clear_bgp_ipv6_as_out_cmd, clear_bgp_ipv6_as_out_cmd,
"clear bgp ipv6 <1-65535> out", "clear bgp ipv6 CMD_AS_RANGE out",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Address family\n" "Address family\n"
@ -5762,7 +5756,7 @@ ALIAS (clear_bgp_external_in_prefix_filter,
DEFUN (clear_ip_bgp_as_soft_in, DEFUN (clear_ip_bgp_as_soft_in,
clear_ip_bgp_as_soft_in_cmd, clear_ip_bgp_as_soft_in_cmd,
"clear ip bgp <1-65535> soft in", "clear ip bgp CMD_AS_RANGE soft in",
CLEAR_STR CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -5776,7 +5770,7 @@ DEFUN (clear_ip_bgp_as_soft_in,
ALIAS (clear_ip_bgp_as_soft_in, ALIAS (clear_ip_bgp_as_soft_in,
clear_ip_bgp_as_in_cmd, clear_ip_bgp_as_in_cmd,
"clear ip bgp <1-65535> in", "clear ip bgp CMD_AS_RANGE in",
CLEAR_STR CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -5785,7 +5779,7 @@ ALIAS (clear_ip_bgp_as_soft_in,
DEFUN (clear_ip_bgp_as_in_prefix_filter, DEFUN (clear_ip_bgp_as_in_prefix_filter,
clear_ip_bgp_as_in_prefix_filter_cmd, 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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -5799,7 +5793,7 @@ DEFUN (clear_ip_bgp_as_in_prefix_filter,
DEFUN (clear_ip_bgp_as_ipv4_soft_in, DEFUN (clear_ip_bgp_as_ipv4_soft_in,
clear_ip_bgp_as_ipv4_soft_in_cmd, 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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -5820,7 +5814,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_in,
ALIAS (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_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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -5832,7 +5826,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_in,
DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter, DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter,
clear_ip_bgp_as_ipv4_in_prefix_filter_cmd, 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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -5853,7 +5847,7 @@ DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter,
DEFUN (clear_ip_bgp_as_vpnv4_soft_in, DEFUN (clear_ip_bgp_as_vpnv4_soft_in,
clear_ip_bgp_as_vpnv4_soft_in_cmd, 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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -5869,7 +5863,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_in,
ALIAS (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_as_vpnv4_in_cmd,
"clear ip bgp <1-65535> vpnv4 unicast in", "clear ip bgp CMD_AS_RANGE vpnv4 unicast in",
CLEAR_STR CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -5880,7 +5874,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_in,
DEFUN (clear_bgp_as_soft_in, DEFUN (clear_bgp_as_soft_in,
clear_bgp_as_soft_in_cmd, clear_bgp_as_soft_in_cmd,
"clear bgp <1-65535> soft in", "clear bgp CMD_AS_RANGE soft in",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Clear peers with the AS number\n" "Clear peers with the AS number\n"
@ -5893,7 +5887,7 @@ DEFUN (clear_bgp_as_soft_in,
ALIAS (clear_bgp_as_soft_in, ALIAS (clear_bgp_as_soft_in,
clear_bgp_ipv6_as_soft_in_cmd, clear_bgp_ipv6_as_soft_in_cmd,
"clear bgp ipv6 <1-65535> soft in", "clear bgp ipv6 CMD_AS_RANGE soft in",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Address family\n" "Address family\n"
@ -5903,7 +5897,7 @@ ALIAS (clear_bgp_as_soft_in,
ALIAS (clear_bgp_as_soft_in, ALIAS (clear_bgp_as_soft_in,
clear_bgp_as_in_cmd, clear_bgp_as_in_cmd,
"clear bgp <1-65535> in", "clear bgp CMD_AS_RANGE in",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Clear peers with the AS number\n" "Clear peers with the AS number\n"
@ -5911,7 +5905,7 @@ ALIAS (clear_bgp_as_soft_in,
ALIAS (clear_bgp_as_soft_in, ALIAS (clear_bgp_as_soft_in,
clear_bgp_ipv6_as_in_cmd, clear_bgp_ipv6_as_in_cmd,
"clear bgp ipv6 <1-65535> in", "clear bgp ipv6 CMD_AS_RANGE in",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Address family\n" "Address family\n"
@ -5920,7 +5914,7 @@ ALIAS (clear_bgp_as_soft_in,
DEFUN (clear_bgp_as_in_prefix_filter, DEFUN (clear_bgp_as_in_prefix_filter,
clear_bgp_as_in_prefix_filter_cmd, clear_bgp_as_in_prefix_filter_cmd,
"clear bgp <1-65535> in prefix-filter", "clear bgp CMD_AS_RANGE in prefix-filter",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Clear peers with the AS number\n" "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, ALIAS (clear_bgp_as_in_prefix_filter,
clear_bgp_ipv6_as_in_prefix_filter_cmd, 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 CLEAR_STR
BGP_STR BGP_STR
"Address family\n" "Address family\n"
@ -6248,7 +6242,7 @@ ALIAS (clear_bgp_external_soft,
DEFUN (clear_ip_bgp_as_soft, DEFUN (clear_ip_bgp_as_soft,
clear_ip_bgp_as_soft_cmd, clear_ip_bgp_as_soft_cmd,
"clear ip bgp <1-65535> soft", "clear ip bgp CMD_AS_RANGE soft",
CLEAR_STR CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -6261,7 +6255,7 @@ DEFUN (clear_ip_bgp_as_soft,
DEFUN (clear_ip_bgp_as_ipv4_soft, DEFUN (clear_ip_bgp_as_ipv4_soft,
clear_ip_bgp_as_ipv4_soft_cmd, 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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -6281,7 +6275,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft,
DEFUN (clear_ip_bgp_as_vpnv4_soft, DEFUN (clear_ip_bgp_as_vpnv4_soft,
clear_ip_bgp_as_vpnv4_soft_cmd, 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 CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -6296,7 +6290,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft,
DEFUN (clear_bgp_as_soft, DEFUN (clear_bgp_as_soft,
clear_bgp_as_soft_cmd, clear_bgp_as_soft_cmd,
"clear bgp <1-65535> soft", "clear bgp CMD_AS_RANGE soft",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Clear peers with the AS number\n" "Clear peers with the AS number\n"
@ -6308,7 +6302,7 @@ DEFUN (clear_bgp_as_soft,
ALIAS (clear_bgp_as_soft, ALIAS (clear_bgp_as_soft,
clear_bgp_ipv6_as_soft_cmd, clear_bgp_ipv6_as_soft_cmd,
"clear bgp ipv6 <1-65535> soft", "clear bgp ipv6 CMD_AS_RANGE soft",
CLEAR_STR CLEAR_STR
BGP_STR BGP_STR
"Address family\n" "Address family\n"
@ -7271,6 +7265,18 @@ bgp_show_peer (struct vty *vty, struct peer *p)
{ {
vty_out (vty, " Neighbor capabilities:%s", VTY_NEWLINE); 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 */ /* Dynamic */
if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV) if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV)
|| CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)) || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV))
@ -7389,16 +7395,13 @@ bgp_show_peer (struct vty *vty, struct peer *p)
} }
if (p->t_gr_restart) if (p->t_gr_restart)
{
vty_out (vty, " The remaining time of restart timer is %ld%s", vty_out (vty, " The remaining time of restart timer is %ld%s",
thread_timer_remain_second (p->t_gr_restart), VTY_NEWLINE); thread_timer_remain_second (p->t_gr_restart), VTY_NEWLINE);
}
if (p->t_gr_stale) if (p->t_gr_stale)
{
vty_out (vty, " The remaining time of stalepath timer is %ld%s", vty_out (vty, " The remaining time of stalepath timer is %ld%s",
thread_timer_remain_second (p->t_gr_stale), VTY_NEWLINE); thread_timer_remain_second (p->t_gr_stale), VTY_NEWLINE);
} }
}
/* Packet counts. */ /* Packet counts. */
vty_out (vty, " Message statistics:%s", VTY_NEWLINE); vty_out (vty, " Message statistics:%s", VTY_NEWLINE);
@ -7907,7 +7910,7 @@ bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient,
vty_out (vty, "4 "); 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]); rmname = ROUTE_MAP_EXPORT_NAME(&rsclient->filter[afi][safi]);
if ( rmname && strlen (rmname) > 13 ) if ( rmname && strlen (rmname) > 13 )

View File

@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_VTY_H #ifndef _QUAGGA_BGP_VTY_H
#define _QUAGGA_BGP_VTY_H #define _QUAGGA_BGP_VTY_H
#define CMD_AS_RANGE "<1-4294967295>"
extern void bgp_vty_init (void); extern void bgp_vty_init (void);
extern const char *afi_safi_print (afi_t, safi_t); extern const char *afi_safi_print (afi_t, safi_t);

View File

@ -25,7 +25,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "sockunion.h" #include "sockunion.h"
/* Typedef BGP specific types. */ /* 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; typedef u_int16_t bgp_size_t;
/* BGP master for system wide configurations and variables. */ /* BGP master for system wide configurations and variables. */
@ -287,6 +288,9 @@ struct peer
int status; int status;
int ostatus; int ostatus;
/* Peer index, used for dumping TABLE_DUMP_V2 format */
uint16_t table_dump_index;
/* Peer information */ /* Peer information */
int fd; /* File descriptor */ int fd; /* File descriptor */
int ttl; /* TTL of TCP connection to the peer. */ int ttl; /* TTL of TCP connection to the peer. */
@ -316,7 +320,7 @@ struct peer
u_char afc_recv[AFI_MAX][SAFI_MAX]; u_char afc_recv[AFI_MAX][SAFI_MAX];
/* Capability flags (reset in bgp_stop) */ /* 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_ADV (1 << 0) /* refresh advertised */
#define PEER_CAP_REFRESH_OLD_RCV (1 << 1) /* refresh old received */ #define PEER_CAP_REFRESH_OLD_RCV (1 << 1) /* refresh old received */
#define PEER_CAP_REFRESH_NEW_RCV (1 << 2) /* refresh rfc 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_DYNAMIC_RCV (1 << 4) /* dynamic received */
#define PEER_CAP_RESTART_ADV (1 << 5) /* restart advertised */ #define PEER_CAP_RESTART_ADV (1 << 5) /* restart advertised */
#define PEER_CAP_RESTART_RCV (1 << 6) /* restart received */ #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) */ /* Capability flags (reset in bgp_stop) */
u_int16_t af_cap[AFI_MAX][SAFI_MAX]; 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_REACH_NLRI 14
#define BGP_ATTR_MP_UNREACH_NLRI 15 #define BGP_ATTR_MP_UNREACH_NLRI 15
#define BGP_ATTR_EXT_COMMUNITIES 16 #define BGP_ATTR_EXT_COMMUNITIES 16
#define BGP_ATTR_AS4_PATH 17
#define BGP_ATTR_AS4_AGGREGATOR 18
#define BGP_ATTR_AS_PATHLIMIT 21 #define BGP_ATTR_AS_PATHLIMIT 21
/* BGP update origin. */ /* BGP update origin. */

View File

@ -19,6 +19,8 @@
14 MP_REACH_NLRI [RFC 2283] 14 MP_REACH_NLRI [RFC 2283]
15 MP_UNREACH_NLRI [RFC 2283] 15 MP_UNREACH_NLRI [RFC 2283]
16 EXT_COMMUNITIES [draft-ramachandra-bgp-ext-communities-09.txt] 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] 254 RCID_PATH [RFC 1863]
255 ADVERTISER [RFC 1863] 255 ADVERTISER [RFC 1863]
========================================================================= =========================================================================

View 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> 2007-09-17 Paul Jakma <paul.jakma@sun.com>
* bgp_capability_test.c: Test that peer's adv_recv and adv_nego get * 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. * bgp_capability_test.c: new, capability parser unit tests.
* Makefile.am: add previous. * 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> 2006-08-26 Paul Jakma <paul.jakma@sun.com>
* heavy-wq.c: (slow_func_del,slow_func) update to match workqueue * heavy-wq.c: (slow_func_del,slow_func) update to match workqueue

View File

@ -2,7 +2,7 @@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\"
noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \
aspathtest testprivs teststream testbgpcap aspathtest testprivs teststream testbgpcap ecommtest
testsig_SOURCES = test-sig.c testsig_SOURCES = test-sig.c
testbuffer_SOURCES = test-buffer.c testbuffer_SOURCES = test-buffer.c
testmemory_SOURCES = test-memory.c testmemory_SOURCES = test-memory.c
@ -13,6 +13,7 @@ heavywq_SOURCES = heavy-wq.c main.c
heavythread_SOURCES = heavy-thread.c main.c heavythread_SOURCES = heavy-thread.c main.c
aspathtest_SOURCES = aspath_test.c aspathtest_SOURCES = aspath_test.c
testbgpcap_SOURCES = bgp_capability_test.c testbgpcap_SOURCES = bgp_capability_test.c
ecommtest_SOURCES = ecommunity_test.c
testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testsig_LDADD = ../lib/libzebra.la @LIBCAP@
testbuffer_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 heavythread_LDADD = ../lib/libzebra.la @LIBCAP@ -lm
aspathtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a aspathtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a
testbgpcap_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

View File

@ -7,6 +7,13 @@
#include "bgpd/bgpd.h" #include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.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 */ /* need these to link in libbgp */
struct zebra_privs_t *bgpd_privs = NULL; struct zebra_privs_t *bgpd_privs = NULL;
struct thread_master *master = NULL; struct thread_master *master = NULL;
@ -312,8 +319,87 @@ static struct test_segment {
/* We shouldn't ever /generate/ such paths. However, we should /* We shouldn't ever /generate/ such paths. However, we should
* cope with them fine. * cope with them fine.
*/ */
"8466 3 52737 4096 3456 {7099,8153,8153,8153}", "8466 3 52737 4096 3456 {7099,8153}",
"8466 3 52737 4096 3456 {7099,8153,8153,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 }, 6, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 },
}, },
{ NULL, NULL, {0}, 0, { NULL, 0, 0 } } { NULL, NULL, {0}, 0, { NULL, 0, 0 } }
@ -432,13 +518,43 @@ static struct tests {
{ NULL, NULL, { NULL, 0, 0, 0, 0, 0, 0, } }, { NULL, NULL, { NULL, 0, 0, 0, 0, 0, 0, } },
}; };
struct tests reconcile_tests[] =
{
{ &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[] = struct tests aggregate_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[0], &test_segments[2], { &test_segments[0], &test_segments[2],
{ "8466 3 52737 4096 {4,8722}", { "8466 3 52737 4096 {4,8722}",
"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}", "8466 {2,3,4,4096,8722,52737}",
2, 0, NOT_ALL_PRIVATE, 2, 20000, 8466 }, 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} }, { NULL, NULL, { NULL, 0, 0} },
}; };
@ -498,7 +621,7 @@ struct compare_tests
/* make an aspath from a data stream */ /* make an aspath from a data stream */
static struct aspath * 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 stream *s = NULL;
struct aspath *as; struct aspath *as;
@ -508,7 +631,7 @@ make_aspath (const u_char *data, size_t len)
s = stream_new (len); s = stream_new (len);
stream_put (s, data, len); stream_put (s, data, len);
} }
as = aspath_parse (s, len); as = aspath_parse (s, len, use32bit);
if (s) if (s)
stream_free (s); stream_free (s);
@ -535,18 +658,27 @@ printbytes (const u_char *bytes, int len)
static int static int
validate (struct aspath *as, const struct test_spec *sp) validate (struct aspath *as, const struct test_spec *sp)
{ {
size_t bytes; size_t bytes, bytes4;
int fails = 0; int fails = 0;
const u_char *out; 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); 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); asstr = aspath_str2aspath (sp->shouldbe);
asconfeddel = aspath_delete_confed_seq (aspath_dup (asinout)); asconfeddel = aspath_delete_confed_seq (aspath_dup (asinout));
printf ("got: %s\n", aspath_print(as));
/* the parsed path should match the specified 'shouldbe' string. /* the parsed path should match the specified 'shouldbe' string.
* We should pass the "eat our own dog food" test, be able to output * 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: * 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 * aspath_str2aspath() and shouldbe should match
* *
* We do the same for:
*
* aspath_parse(aspath_put(as,USE32BIT))
*
* Confederation related tests: * Confederation related tests:
* - aspath_delete_confed_seq(aspath) should match shouldbe_confed * - aspath_delete_confed_seq(aspath) should match shouldbe_confed
* - aspath_delete_confed_seq should be idempotent. * - 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)) || (aspath_key_make (as) != aspath_key_make (asinout))
/* by string */ /* by string */
|| strcmp(aspath_print (asinout), sp->shouldbe) || strcmp(aspath_print (asinout), sp->shouldbe)
/* By 4-byte parsing */
|| strcmp(aspath_print (as4), sp->shouldbe)
/* by various path counts */ /* by various path counts */
|| (aspath_count_hops (as) != sp->hops) || (aspath_count_hops (as) != sp->hops)
|| (aspath_count_confeds (as) != sp->confeds) || (aspath_count_confeds (as) != sp->confeds)
@ -580,7 +718,7 @@ validate (struct aspath *as, const struct test_spec *sp)
failed++; failed++;
fails++; fails++;
printf ("shouldbe:\n%s\n", sp->shouldbe); 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", printf ("hash keys: in: %d out->in: %d\n",
aspath_key_make (as), aspath_key_make (asinout)); aspath_key_make (as), aspath_key_make (asinout));
printf ("hops: %d, counted %d %d\n", sp->hops, 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_private_as_check (as));
} }
aspath_unintern (asinout); aspath_unintern (asinout);
aspath_unintern (as4);
aspath_free (asconfeddel); aspath_free (asconfeddel);
aspath_free (asstr); aspath_free (asstr);
stream_reset (s);
return fails; return fails;
} }
static void static void
@ -650,9 +790,9 @@ empty_get_test ()
printf ("empty_get_test, as: %s\n",aspath_print (as)); printf ("empty_get_test, as: %s\n",aspath_print (as));
if (!validate (as, &sp)) if (!validate (as, &sp))
printf ("OK\n"); printf ("%s\n", OK);
else else
printf ("failed!\n"); printf ("%s!\n", FAILED);
printf ("\n"); printf ("\n");
@ -667,14 +807,14 @@ parse_test (struct test_segment *t)
printf ("%s: %s\n", t->name, t->desc); 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)); printf ("aspath: %s\nvalidating...:\n", aspath_print (asp));
if (!validate (asp, &t->sp)) if (!validate (asp, &t->sp))
printf ("OK\n"); printf (OK "\n");
else else
printf ("failed\n"); printf (FAILED "\n");
printf ("\n"); printf ("\n");
aspath_unintern (asp); aspath_unintern (asp);
@ -689,8 +829,8 @@ prepend_test (struct tests *t)
printf ("prepend %s: %s\n", t->test1->name, t->test1->desc); printf ("prepend %s: %s\n", t->test1->name, t->test1->desc);
printf ("to %s: %s\n", t->test2->name, t->test2->desc); printf ("to %s: %s\n", t->test2->name, t->test2->desc);
asp1 = make_aspath (t->test1->asdata, t->test1->len); asp1 = make_aspath (t->test1->asdata, t->test1->len, 0);
asp2 = make_aspath (t->test2->asdata, t->test2->len); asp2 = make_aspath (t->test2->asdata, t->test2->len, 0);
ascratch = aspath_dup (asp2); ascratch = aspath_dup (asp2);
aspath_unintern (asp2); aspath_unintern (asp2);
@ -700,9 +840,9 @@ prepend_test (struct tests *t)
printf ("aspath: %s\n", aspath_print (asp2)); printf ("aspath: %s\n", aspath_print (asp2));
if (!validate (asp2, &t->sp)) if (!validate (asp2, &t->sp))
printf ("OK\n"); printf ("%s\n", OK);
else else
printf ("failed!\n"); printf ("%s!\n", FAILED);
printf ("\n"); printf ("\n");
aspath_unintern (asp1); aspath_unintern (asp1);
@ -717,7 +857,7 @@ empty_prepend_test (struct test_segment *t)
printf ("empty prepend %s: %s\n", t->name, t->desc); 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 (); asp2 = aspath_empty ();
ascratch = aspath_dup (asp2); ascratch = aspath_dup (asp2);
@ -728,15 +868,41 @@ empty_prepend_test (struct test_segment *t)
printf ("aspath: %s\n", aspath_print (asp2)); printf ("aspath: %s\n", aspath_print (asp2));
if (!validate (asp2, &t->sp)) if (!validate (asp2, &t->sp))
printf ("OK\n"); printf (OK "\n");
else else
printf ("failed!\n"); printf (FAILED "!\n");
printf ("\n"); printf ("\n");
aspath_unintern (asp1); aspath_unintern (asp1);
aspath_free (asp2); 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 */ /* aggregation testing */
static void static void
aggregate_test (struct tests *t) 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 ("aggregate %s: %s\n", t->test1->name, t->test1->desc);
printf ("with %s: %s\n", t->test2->name, t->test2->desc); printf ("with %s: %s\n", t->test2->name, t->test2->desc);
asp1 = make_aspath (t->test1->asdata, t->test1->len); asp1 = make_aspath (t->test1->asdata, t->test1->len, 0);
asp2 = make_aspath (t->test2->asdata, t->test2->len); asp2 = make_aspath (t->test2->asdata, t->test2->len, 0);
ascratch = aspath_aggregate (asp1, asp2); ascratch = aspath_aggregate (asp1, asp2);
printf ("aspath: %s\n", aspath_print (ascratch));
if (!validate (ascratch, &t->sp)) if (!validate (ascratch, &t->sp))
printf ("OK\n"); printf (OK "\n");
else else
printf ("failed!\n"); printf (FAILED "!\n");
printf ("\n"); printf ("\n");
aspath_unintern (asp1); aspath_unintern (asp1);
@ -782,8 +946,8 @@ cmp_test ()
printf ("left cmp %s: %s\n", t1->name, t1->desc); printf ("left cmp %s: %s\n", t1->name, t1->desc);
printf ("and %s: %s\n", t2->name, t2->desc); printf ("and %s: %s\n", t2->name, t2->desc);
asp1 = make_aspath (t1->asdata, t1->len); asp1 = make_aspath (t1->asdata, t1->len, 0);
asp2 = make_aspath (t2->asdata, t2->len); asp2 = make_aspath (t2->asdata, t2->len, 0);
if (aspath_cmp_left (asp1, asp2) != left_compare[i].shouldbe_cmp if (aspath_cmp_left (asp1, asp2) != left_compare[i].shouldbe_cmp
|| aspath_cmp_left (asp2, asp1) != 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) || aspath_cmp_left_confed (asp2, asp1)
!= left_compare[i].shouldbe_confed) != left_compare[i].shouldbe_confed)
{ {
printf ("failed\n"); failed++;
printf (FAILED "\n");
printf ("result should be: cmp: %d, confed: %d\n", printf ("result should be: cmp: %d, confed: %d\n",
left_compare[i].shouldbe_cmp, left_compare[i].shouldbe_cmp,
left_compare[i].shouldbe_confed); left_compare[i].shouldbe_confed);
@ -801,10 +966,9 @@ cmp_test ()
aspath_cmp_left_confed (asp1, asp2)); aspath_cmp_left_confed (asp1, asp2));
printf("path1: %s\npath2: %s\n", aspath_print (asp1), printf("path1: %s\npath2: %s\n", aspath_print (asp1),
aspath_print (asp2)); aspath_print (asp2));
failed++;
} }
else else
printf ("OK\n"); printf (OK "\n");
printf ("\n"); printf ("\n");
aspath_unintern (asp1); aspath_unintern (asp1);
@ -831,6 +995,13 @@ main (void)
while (aggregate_tests[i].test1) while (aggregate_tests[i].test1)
aggregate_test (&aggregate_tests[i++]); aggregate_test (&aggregate_tests[i++]);
i = 0;
while (reconcile_tests[i].test1)
as4_reconcile_test (&reconcile_tests[i++]);
i = 0;
cmp_test(); cmp_test();
i = 0; i = 0;

View File

@ -15,8 +15,9 @@
#define VT100_YELLOW "\x1b[33m" #define VT100_YELLOW "\x1b[33m"
#define OPEN 0 #define CAPABILITY 0
#define DYNCAP 1 #define DYNCAP 1
#define OPT_PARAM 2
/* need these to link in libbgp */ /* need these to link in libbgp */
struct zebra_privs_t *bgpd_privs = NULL; struct zebra_privs_t *bgpd_privs = NULL;
@ -34,6 +35,7 @@ static struct test_segment {
#define SHOULD_PARSE 0 #define SHOULD_PARSE 0
#define SHOULD_ERR -1 #define SHOULD_ERR -1
int parses; /* whether it should parse or not */ int parses; /* whether it should parse or not */
int peek_for; /* what peek_for_as4_capability should say */
/* AFI/SAFI validation */ /* AFI/SAFI validation */
int validate_afi; int validate_afi;
@ -76,54 +78,55 @@ static struct test_segment mp_segments[] =
{ "MP4", { "MP4",
"MP IP/Uni", "MP IP/Uni",
{ 0x1, 0x4, 0x0, 0x1, 0x0, 0x1 }, { 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", { "MPv6",
"MP IPv6/Uni", "MP IPv6/Uni",
{ 0x1, 0x4, 0x0, 0x2, 0x0, 0x1 }, { 0x1, 0x4, 0x0, 0x2, 0x0, 0x1 },
6, SHOULD_PARSE, 6, SHOULD_PARSE, 0,
1, AFI_IP6, SAFI_UNICAST, VALID_AFI, 1, AFI_IP6, SAFI_UNICAST, VALID_AFI,
}, },
/* 5 */ /* 5 */
{ "MP2", { "MP2",
"MP IP/Multicast", "MP IP/Multicast",
{ CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x2 }, { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x2 },
6, SHOULD_PARSE, 6, SHOULD_PARSE, 0,
1, AFI_IP, SAFI_MULTICAST, VALID_AFI, 1, AFI_IP, SAFI_MULTICAST, VALID_AFI,
}, },
/* 6 */ /* 6 */
{ "MP3", { "MP3",
"MP IP6/VPNv4", "MP IP6/VPNv4",
{ CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x80 }, { 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, 1, AFI_IP6, BGP_SAFI_VPNV4, INVALID_AFI,
}, },
/* 7 */ /* 7 */
{ "MP5", { "MP5",
"MP IP6/MPLS-VPN", "MP IP6/MPLS-VPN",
{ CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x4 }, { CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x4 },
6, SHOULD_PARSE, 6, SHOULD_PARSE, 0,
1, AFI_IP6, SAFI_MPLS_VPN, VALID_AFI, 1, AFI_IP6, SAFI_MPLS_VPN, VALID_AFI,
}, },
/* 8 */ /* 8 */
{ "MP6", { "MP6",
"MP IP4/VPNv4", "MP IP4/VPNv4",
{ CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80 }, { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80 },
6, SHOULD_PARSE, 6, SHOULD_PARSE, 0,
1, AFI_IP, BGP_SAFI_VPNV4, VALID_AFI, 1, AFI_IP, BGP_SAFI_VPNV4, VALID_AFI,
}, },
/* 9 */ /* 9 */
{ "MP7", { "MP7",
"MP IP4/VPNv6", "MP IP4/VPNv6",
{ CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x81 }, { 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, 1, AFI_IP, BGP_SAFI_VPNV6, INVALID_AFI,
}, },
/* 10 */ /* 10 */
{ "MP8", { "MP8",
"MP unknown AFI", "MP unknown AFI",
{ CAPABILITY_CODE_MP, 0x4, 0x0, 0xa, 0x0, 0x81 }, { CAPABILITY_CODE_MP, 0x4, 0x0, 0xa, 0x0, 0x81 },
6, SHOULD_PARSE, 6, SHOULD_PARSE, 0,
1, 0xa, 0x81, INVALID_AFI, /* parses, but unknown */ 1, 0xa, 0x81, INVALID_AFI, /* parses, but unknown */
}, },
/* 11 */ /* 11 */
@ -136,7 +139,7 @@ static struct test_segment mp_segments[] =
{ "MP-overflow", { "MP-overflow",
"MP IP4/Unicast, length too long", "MP IP4/Unicast, length too long",
{ CAPABILITY_CODE_MP, 0x6, 0x0, 0x1, 0x0, 0x1 }, { CAPABILITY_CODE_MP, 0x6, 0x0, 0x1, 0x0, 0x1 },
6, SHOULD_ERR, 6, SHOULD_ERR, 0,
1, AFI_IP, SAFI_UNICAST, VALID_AFI, 1, AFI_IP, SAFI_UNICAST, VALID_AFI,
}, },
{ NULL, NULL, {0}, 0, 0} { NULL, NULL, {0}, 0, 0}
@ -290,8 +293,8 @@ static struct test_segment misc_segments[] =
/* 19 */ /* 19 */
{ "AS4", { "AS4",
"AS4 capability", "AS4 capability",
{ 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12 }, { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12 }, /* AS: 2882400018 */
6, SHOULD_PARSE, 6, SHOULD_PARSE, 2882400018,
}, },
/* 20 */ /* 20 */
{ "GR", { "GR",
@ -367,7 +370,7 @@ static struct test_segment misc_segments[] =
{ NULL, NULL, {0}, 0, 0} { NULL, NULL, {0}, 0, 0}
}; };
/* DYNAMIC message */
struct test_segment dynamic_cap_msgs[] = struct test_segment dynamic_cap_msgs[] =
{ {
{ "DynCap", { "DynCap",
@ -397,18 +400,97 @@ struct test_segment dynamic_cap_msgs[] =
}, },
{ NULL, NULL, {0}, 0, 0} { 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 */ /* basic parsing test */
static void static void
parse_test (struct peer *peer, struct test_segment *t, int type) parse_test (struct peer *peer, struct test_segment *t, int type)
{ {
int ret; int ret;
int capability = 0; int capability = 0;
as_t as4 = 0;
int oldfailed = failed; int oldfailed = failed;
int len = t->len;
#define RANDOM_FUZZ 35
stream_reset (peer->ibuf); stream_reset (peer->ibuf);
stream_put (peer->ibuf, NULL, RANDOM_FUZZ);
stream_set_getp (peer->ibuf, RANDOM_FUZZ);
switch (type) switch (type)
{ {
case OPEN: case CAPABILITY:
stream_putc (peer->ibuf, BGP_OPEN_OPT_CAP); stream_putc (peer->ibuf, BGP_OPEN_OPT_CAP);
stream_putc (peer->ibuf, t->len); stream_putc (peer->ibuf, t->len);
break; break;
@ -425,8 +507,17 @@ parse_test (struct peer *peer, struct test_segment *t, int type)
switch (type) switch (type)
{ {
case OPEN: case CAPABILITY:
ret = bgp_open_option_parse (peer, t->len + 2, &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; break;
case DYNCAP: case DYNCAP:
ret = bgp_capability_receive (peer, t->len); 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"); printf ("parsed?: %s\n", ret ? "no" : "yes");
if (ret != t->parses) if (ret != t->parses)
failed++; failed++;
if (tty) 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); : VT100_GREEN "OK" VT100_RESET);
else else
printf ("%s\n", (failed > oldfailed) ? "failed!" : "OK" ); printf ("%s", (failed > oldfailed) ? "failed!" : "OK" );
printf ("\n"); if (failed)
printf (" (%u)", failed);
printf ("\n\n");
} }
static struct bgp *bgp; static struct bgp *bgp;
@ -485,10 +585,12 @@ main (void)
conf_bgp_debug_events = -1UL; conf_bgp_debug_events = -1UL;
conf_bgp_debug_packet = -1UL; conf_bgp_debug_packet = -1UL;
conf_bgp_debug_normal = -1UL; conf_bgp_debug_normal = -1UL;
conf_bgp_debug_as4 = -1UL;
term_bgp_debug_fsm = -1UL; term_bgp_debug_fsm = -1UL;
term_bgp_debug_events = -1UL; term_bgp_debug_events = -1UL;
term_bgp_debug_packet = -1UL; term_bgp_debug_packet = -1UL;
term_bgp_debug_normal = -1UL; term_bgp_debug_normal = -1UL;
term_bgp_debug_as4 = -1UL;
master = thread_master_create (); master = thread_master_create ();
bgp_master_init (); bgp_master_init ();
@ -500,6 +602,7 @@ main (void)
return -1; return -1;
peer = peer_create_accept (bgp); peer = peer_create_accept (bgp);
peer->host = "foo";
for (i = AFI_IP; i < AFI_MAX; i++) for (i = AFI_IP; i < AFI_MAX; i++)
for (j = SAFI_UNICAST; j < SAFI_MAX; j++) for (j = SAFI_UNICAST; j < SAFI_MAX; j++)
@ -510,18 +613,22 @@ main (void)
i = 0; i = 0;
while (mp_segments[i].name) 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 /* These tests assume mp_segments tests set at least
* one of the afc_nego's * one of the afc_nego's
*/ */
i = 0; i = 0;
while (test_segments[i].name) while (test_segments[i].name)
parse_test (peer, &test_segments[i++], OPEN); parse_test (peer, &test_segments[i++], CAPABILITY);
i = 0; i = 0;
while (misc_segments[i].name) 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); SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
peer->status = Established; peer->status = Established;

View File

@ -18,6 +18,11 @@
precision commands: send to all daemons. precision commands: send to all daemons.
(vtysh_init_vty) Install new log timestamp precision commands. (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> 2006-07-27 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* vtysh_main.c: (usage) Add new -d and -E options. And note that * vtysh_main.c: (usage) Add new -d and -E options. And note that

View File

@ -37,8 +37,8 @@ $ignore{'"router ripng"'} = "ignore";
$ignore{'"router ospf"'} = "ignore"; $ignore{'"router ospf"'} = "ignore";
$ignore{'"router ospf <0-65535>"'} = "ignore"; $ignore{'"router ospf <0-65535>"'} = "ignore";
$ignore{'"router ospf6"'} = "ignore"; $ignore{'"router ospf6"'} = "ignore";
$ignore{'"router bgp <1-65535>"'} = "ignore"; $ignore{'"router bgp CMD_AS_RANGE"'} = "ignore";
$ignore{'"router bgp <1-65535> view WORD"'} = "ignore"; $ignore{'"router bgp CMD_AS_RANGE view WORD"'} = "ignore";
$ignore{'"router isis WORD"'} = "ignore"; $ignore{'"router isis WORD"'} = "ignore";
$ignore{'"router zebra"'} = "ignore"; $ignore{'"router zebra"'} = "ignore";
$ignore{'"address-family ipv4"'} = "ignore"; $ignore{'"address-family ipv4"'} = "ignore";

View File

@ -838,7 +838,7 @@ DEFUNSH (VTYSH_ALL,
DEFUNSH (VTYSH_BGPD, DEFUNSH (VTYSH_BGPD,
router_bgp, router_bgp,
router_bgp_cmd, router_bgp_cmd,
"router bgp <1-65535>", "router bgp CMD_AS_RANGE",
ROUTER_STR ROUTER_STR
BGP_STR BGP_STR
AS_STR) AS_STR)