summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Kammer <j.kammer@eurodata.de>2007-04-09 14:03:25 -0500
committerJeffrey C. Ollie <jeff@ocjtech.us>2007-04-09 14:03:25 -0500
commitfc4dc72017e8208111866382782640117d03fb5f (patch)
treec3a8747eeb471098d0dfb4f2e9138d1ac0cfa2f7
parent6502208c3217e52e693146e6b72e76fd76982a51 (diff)
downloadquagga-fc4dc72017e8208111866382782640117d03fb5f.tar.bz2
quagga-fc4dc72017e8208111866382782640117d03fb5f.tar.xz
Applying quagga-cvs20070307-as4-v05.patchquagga-cvs20070307-as4-v05.patch
-rw-r--r--bgpd/ChangeLog85
-rw-r--r--bgpd/bgp_aspath.c457
-rw-r--r--bgpd/bgp_aspath.h55
-rw-r--r--bgpd/bgp_attr.c432
-rw-r--r--bgpd/bgp_attr.h7
-rw-r--r--bgpd/bgp_debug.c180
-rw-r--r--bgpd/bgp_debug.h5
-rw-r--r--bgpd/bgp_dump.c265
-rw-r--r--bgpd/bgp_dump.h22
-rw-r--r--bgpd/bgp_ecommunity.c103
-rw-r--r--bgpd/bgp_ecommunity.h1
-rw-r--r--bgpd/bgp_mplsvpn.c5
-rw-r--r--bgpd/bgp_open.c134
-rw-r--r--bgpd/bgp_open.h4
-rw-r--r--bgpd/bgp_packet.c87
-rw-r--r--bgpd/bgp_route.c2
-rw-r--r--bgpd/bgp_routemap.c23
-rw-r--r--bgpd/bgp_vty.c269
-rw-r--r--bgpd/bgpd.c69
-rw-r--r--bgpd/bgpd.h16
-rw-r--r--doc/BGP-TypeCode2
-rw-r--r--tests/ChangeLog4
-rw-r--r--tests/aspath_test.c2
-rw-r--r--vtysh/ChangeLog5
-rwxr-xr-xvtysh/extract.pl.in4
-rw-r--r--vtysh/vtysh.c2
26 files changed, 1937 insertions, 303 deletions
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
index 7e964c95..287d0906 100644
--- a/bgpd/ChangeLog
+++ b/bgpd/ChangeLog
@@ -1,5 +1,16 @@
-2007-02-22 Paul Jakma <paul.jakma@sun.com>
+2007-03-08 Juergen Kammer <j.kammer@eurodata.de>
+ * bgp_attr.c: some more code cleanup, rename new_aggregator to
+ as4_aggregator, and new_aspath to as4_aspath
+ * bgp_attr.h: some more code cleanup, rename new_aggregator to
+ as4_aggregator, and new_aspath to as4_aspath
+ * bgp_aspath.c: some more code cleanup, rename new_aggregator to
+ as4_aggregator, and new_aspath to as4_aspath
+
+2007-03-07 Juergen Kammer <j.kammer@eurodata.de>
+
+ * these changes are from Paul, as of 2007-02-22 Paul Jakma
+ <paul.jakma@sun.com> (rebase patch on cvs 20070307)
* bgp_fsm.c: (bgp_fsm_change_status) Handle state change into
clearing or greater here. Simpler.
(bgp_event) Clearing state change work moved to previous
@@ -15,6 +26,78 @@
that exist and how they need to be dealt with.
(bgp_clear_route) Update comment.
+2007-03-06 Juergen Kammer <j.kammer@eurodata.de>
+
+ * bgp_attr.c: import new mrt patch from Erik
+ * bgp_attr.h: import new mrt patch from Erik
+ * bgp_dump.c: import new mrt patch from Erik
+ * bgp_dump.h: import new mrt patch from Erik
+ * bgpd.h: import new mrt patch from Erik
+
+2007-03-05 Juergen Kammer <j.kammer@eurodata.de>
+
+ * bgp_ecommunity.c: Introduce a new syntax, if as4 ecommunity
+ is to be used, there must be a '+' in front of the
+ as number. Thus the as number itself may be in any
+ format (besides asip, but that is a joke anyway).
+
+2007-02-12 Juergen Kammer <j.kammer@eurodata.de>
+
+ * bgp_attr.c: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_aspath.c: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_vty.c: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_aspath.h: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_ecommunity.c: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_ecommunity.h: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_mplsvpn.c: Add missing include
+ * bgp_open.c: Change all asn32 to AS4, change NEW_* to AS4_*, add
+ missing include
+ * bgp_open.h: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_packet.c: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgpd.c: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_debug.c: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgpd.h: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_debug.h: Change all asn32 to AS4, change NEW_* to AS4_*
+ * bgp_dump.c: Change all asn32 to AS4, change NEW_* to AS4_*
+
+2007-01-17 Juergen Kammer <j.kammer@eurodata.de>
+
+ * bgp_ecommunity.c: string representation of asn32 must be asdot+ if
+ we use this systax.
+ * bgp_vty.c: ip extcommunity-list <1-99>|standard has no "ASN" at
+ the place of the AS number in the CLI prompt.
+ * bgpd.c, bgp_open.c: fixed one speling mistake each in comments
+
+2007-01-15 Juergen Kammer <j.kammer@eurodata.de>
+
+ * Several changes to bgp_dump.[ch] to support asn32 compatible mrt dumps
+ Thanks to Erik Romijn (RIPE NCC) for his help and testing efforts.
+
+2006-12-08 Juergen Kammer <j.kammer@eurodata.de>
+
+ * Many changes to support 4 byte asnumbers as defined in
+ draft-ietf-idr-as4bytes-12.txt and to support as4octet
+ extended communities as defined in
+ draft-rekhter-as4octet-ext-community-01.txt
+ * bgp_aspath.c: Support asn32
+ * bgp_aspath.h: Support asn32
+ * bgp_attr.c: Support asn32
+ * bgp_attr.h: Support asn32
+ * bgp_debug.c: Support asn32, add 'debug asn32' and
+ 'debug asn32 segment'
+ * bgp_debug.h: Support asn32
+ * bgp_ecommunity.c: Support asn32, support ENCODE_AS4BYTE in extended
+ communities
+ * bgp_mplsvpn.c: Support asn32
+ * bgp_open.c: Support asn32
+ * bgp_open.h: Support asn32
+ * bgp_packet.c: Support asn32
+ * bgp_route.c: Support asn32
+ * bgp_routemap.c: Support asn32
+ * bgp_vty.c: Support asn32
+ * bgpd.c: Support asn32
+ * bgpd.h: Support asn32
+
2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_nexthop.c: (bgp_connected_add, bgp_connected_delete)
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 327406fa..2113f281 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -31,12 +31,16 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_attr.h"
/* Attr. Flags and Attr. Type Code. */
#define AS_HEADER_SIZE 2
-/* Two octet is used for AS value. */
+/* Now FOUR octets are used for AS value. */
#define AS_VALUE_SIZE sizeof (as_t)
+/* This is the old one */
+#define AS16_VALUE_SIZE sizeof (as16_t)
/* Maximum protocol segment length value */
#define AS_SEGMENT_MAX 255
@@ -46,16 +50,28 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* sizes and lengths. At present (200508) they sort of match, however
* the ONLY functions which should now about the on-wire syntax are
* aspath_put, assegment_put and assegment_parse.
+ *
+ * JK: Warning. It is really a sort of match.
+ * In bgp_attr.c, where
+ * aspath_put is being called, the amount of bytes needed on the
+ * wire is calculated *by these macros* (through calling aspath_size)
+ * and put onto the stream before aspath_put is called.
+ * Because the amount of segments may be changed in aspath_put by merging
+ * or splitting the internel aspath_segments, we currently have a problem
+ * here.
*/
/* Calculated size in bytes of ASN segment data to hold N ASN's */
#define ASSEGMENT_DATA_SIZE(N) ((N) * AS_VALUE_SIZE)
+#define ASSEGMENT16_DATA_SIZE(N) ((N) * AS16_VALUE_SIZE)
/* Calculated size of segment struct to hold N ASN's */
#define ASSEGMENT_SIZE(N) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N))
+#define ASSEGMENT16_SIZE(N) (AS_HEADER_SIZE + ASSEGMENT16_DATA_SIZE (N))
/* AS segment octet length. */
#define ASSEGMENT_LEN(X) ASSEGMENT_SIZE((X)->length)
+#define ASSEGMENT16_LEN(X) ASSEGMENT16_SIZE((X)->length)
/* AS_SEQUENCE segments can be packed together */
/* Can the types of X and Y be considered for packing? */
@@ -82,6 +98,132 @@ struct hash *ashash;
/* Stream for SNMP. See aspath_snmp_pathseg */
static struct stream *snmp_stream;
+/* as4 related asnumber format things */
+
+static
+int bgp_asnumber_format = BGP_ASNUMBER_FORMAT_DEFAULT;
+
+void
+setasnumber_format ( int chosenformat )
+{
+ if ( chosenformat >= 0 && chosenformat < BGP_ASNUMBER_FORMAT_NOTUSED )
+ {
+ bgp_asnumber_format = chosenformat;
+ }
+}
+
+int
+get_asnumber_format ( )
+{
+ return bgp_asnumber_format;
+}
+
+/* provide asnumber->string conversion */
+char *
+as2str ( as_t as)
+{
+ /*
+ * there are max. 2 asnumbers in one print
+ * so if we use static memory, we can do it
+ * by using two static places
+ * space -- asdot has 5+1+5+1 +1 = 13Bytes ,
+ * asip has 3+1+3+1+3+1+3+1 = 16 Bytes
+ * asplain has 10+1 = 11 Bytes
+ * so we are stuck with 16
+ * Could also have done this with dynamic memory, but then the
+ * caller would have to free it again which is a nuisance to
+ * keep track of. Or the caller could provide the buffer,
+ * but that is also a headache. (JK)
+ */
+
+ static char asstring1[16]; /* 16 for asip, which is max */
+ static char asstring2[16]; /* 16 for asip, which is max */
+ static int which = 0;
+ char *usethis;
+
+ which = 1 - which;
+ usethis = (which) ? asstring1 : asstring2;
+
+ switch ( bgp_asnumber_format )
+ {
+ case BGP_ASNUMBER_FORMAT_ASDOT:
+ if ( as < 65536 )
+ sprintf( usethis, "%u", as );
+ else
+ sprintf( usethis, "%u.%u", (as >> 16) & 0xffff, as & 0xffff );
+ break;
+ case BGP_ASNUMBER_FORMAT_ASDOTPLUS:
+ sprintf( usethis, "%u.%u", (as >> 16) & 0xffff, as & 0xffff );
+ break;
+ case BGP_ASNUMBER_FORMAT_ASPLAIN:
+ sprintf( usethis, "%u", as );
+ break;
+ case BGP_ASNUMBER_FORMAT_ASIP:
+ sprintf( usethis, "%u.%u.%u.%u",
+ ((as >> 24) & 0xff),
+ ((as >> 16) & 0xff),
+ ((as >> 8) & 0xff),
+ (as & 0xff)
+ );
+ break;
+ }
+ return usethis;
+}
+
+/* return as number from string */
+as_t str2asnum ( const char *p, const char **q )
+{
+ unsigned int dottedints[4]; /* max 4 ints */
+ int numints; /* how many ints we saw */
+
+ /* Eat AS4 regardless of syntax - eat asplain, asdot, asdot+, and asip,
+ * while we're here
+ */
+ /* return current value of p in q if q is there. Needed when
+ * parsing a whole line of things
+ */
+
+ numints = 0;
+ while (numints < 4 && p && isdigit ((int) *p))
+ {
+ dottedints[numints] = (*p - '0');
+ p++;
+ while (isdigit ((int) *p))
+ {
+ dottedints[numints] *= 10;
+ dottedints[numints] += (*p - '0');
+ p++;
+ }
+
+ if ( *p == '.' )
+ {
+ p++;
+ if ( ! isdigit ((int) *p) )
+ {
+ /* syntax error, ends with a dot */
+ if ( q != NULL )
+ *q = p;
+ return (as_t) 0;
+ }
+ }
+ numints++;
+ }
+ if ( q != NULL )
+ *q = p;
+ switch ( numints )
+ {
+ case 0 : return (as_t) 0;
+ case 1 : return dottedints[0];
+ case 2 : return (dottedints[0] << 16) + dottedints[1]; /* asdot */
+ case 3 : return (as_t) 0; /* syntax error - 3 numbers */
+ case 4 : return (dottedints[0] << 24) + (dottedints[1] << 16)
+ + (dottedints[2] << 8) + dottedints[3]; /* asip */
+ }
+ return (as_t) 0;
+
+}
+
+
static inline as_t *
assegment_data_new (int num)
{
@@ -454,6 +596,40 @@ aspath_highest (struct aspath *aspath)
return highest;
}
+/* Return number of 32bit as numbers in in path */
+unsigned int
+aspath_count_num32as (struct aspath *aspath)
+{
+ struct assegment *seg = aspath->segments;
+ unsigned int i, num;
+
+ num=0;
+ while (seg)
+ {
+ for (i = 0; i < seg->length; i++)
+ if (seg->as[i] > BGP_AS_MAX)
+ num++;
+ seg = seg->next;
+ }
+ return num;
+}
+
+/* Return number of as numbers in in path */
+unsigned int
+aspath_count_numas (struct aspath *aspath)
+{
+ struct assegment *seg = aspath->segments;
+ unsigned int num;
+
+ num=0;
+ while (seg)
+ {
+ num += seg->length;
+ seg = seg->next;
+ }
+ return num;
+}
+
/* Convert aspath structure to string expression. */
static char *
aspath_make_str_count (struct aspath *as)
@@ -479,8 +655,14 @@ aspath_make_str_count (struct aspath *as)
* Hopefully this is large enough to avoid hitting the realloc
* code below for most common sequences.
*/
+ /* What will be common in the future? As soon as a 32 Bit AS number shows
+ * up, such an ASN takes again 5+1 chars - if the whole number range will
+ * be used. But usage of AS4 will be the exception for some time now.
+ * ah, what the heck, we put this into this now.
+ */
#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
+ + aspath_count_num32as( as) * ASN_STR_LEN,
ASPATH_STR_DEFAULT_LEN);
str_buf = XMALLOC (MTYPE_AS_STR, str_size);
@@ -510,8 +692,9 @@ aspath_make_str_count (struct aspath *as)
* have been wrong. need 5 chars for ASN, a seperator each and
* potentially two segment delimiters, plus a space between each
* segment and trailing zero.
+ * ... and we need twice ASN_STR_LEN because all ASNUMs may be 32bit
*/
-#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
+#define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN)*2 + 2 + 1 + 1)
if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
{
str_size = len + SEGMENT_STR_LEN(seg);
@@ -528,8 +711,7 @@ aspath_make_str_count (struct aspath *as)
/* write out the ASNs, with their seperators, bar the last one*/
for (i = 0; i < seg->length; i++)
{
- len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
-
+ len += snprintf( str_buf + len, str_size - len, "%s", as2str(seg->as[i]));
if (i < (seg->length - 1))
len += snprintf (str_buf + len, str_size - len, "%c", seperator);
}
@@ -605,7 +787,7 @@ aspath_hash_alloc (void *arg)
{
struct aspath *aspath;
- /* New aspath strucutre is needed. */
+ /* New aspath structure is needed. */
aspath = aspath_dup (arg);
/* Malformed AS path value. */
@@ -620,7 +802,7 @@ aspath_hash_alloc (void *arg)
/* parse as-segment byte stream in struct assegment */
static struct assegment *
-assegments_parse (struct stream *s, size_t length)
+assegments_parse (struct stream *s, size_t length, int use32bit)
{
struct assegment_header segh;
struct assegment *seg, *prev = NULL, *head = NULL;
@@ -630,10 +812,12 @@ assegments_parse (struct stream *s, size_t length)
if (length == 0)
return NULL;
+ if (BGP_DEBUG (as4, AS4_SEGMENT))
+ zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %d",length);
/* basic checks */
if ( (STREAM_READABLE(s) < length)
|| (STREAM_READABLE(s) < AS_HEADER_SIZE)
- || (length % AS_VALUE_SIZE))
+ || (length % AS16_VALUE_SIZE ))
return NULL;
while ( (STREAM_READABLE(s) > AS_HEADER_SIZE)
@@ -644,9 +828,16 @@ assegments_parse (struct stream *s, size_t length)
/* softly softly, get the header first on its own */
segh.type = stream_getc (s);
segh.length = stream_getc (s);
+
+ if (BGP_DEBUG (as4, AS4_SEGMENT))
+ zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",segh.type, segh.length);
/* check it.. */
- if ( ((bytes + ASSEGMENT_SIZE(segh.length)) > length)
+ /*
+ * If we get 16 Bit values, lengths are accordingly smaller
+ * but we will always use 32 Bit for putting segments into memory
+ */
+ if ( ((bytes + ( (use32bit) ? ASSEGMENT_SIZE(segh.length) : ASSEGMENT16_SIZE(segh.length) )) > length)
/* 1771bis 4.3b: seg length contains one or more */
|| (segh.length == 0)
/* Paranoia in case someone changes type of segment length */
@@ -666,9 +857,15 @@ assegments_parse (struct stream *s, size_t length)
head = prev = seg;
for (i = 0; i < segh.length; i++)
- seg->as[i] = stream_getw (s);
+ {
+ seg->as[i] = (use32bit)? (stream_getl(s)) : (stream_getw (s));
+ if (BGP_DEBUG (as4, AS4_SEGMENT))
+ zlog_debug ("[AS4SEG] Parse aspath segment: Read %s into this segment",as2str(seg->as[i]));
+ }
- bytes += ASSEGMENT_SIZE(segh.length);
+ bytes += (use32bit) ? ASSEGMENT_SIZE(segh.length) : ASSEGMENT16_SIZE(segh.length);
+ if (BGP_DEBUG (as4, AS4_SEGMENT))
+ zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %d",bytes);
prev = seg;
}
@@ -680,16 +877,21 @@ assegments_parse (struct stream *s, size_t length)
is length of byte stream. If there is same AS path in the the AS
path hash then return it else make new AS path structure. */
struct aspath *
-aspath_parse (struct stream *s, size_t length)
+aspath_parse (struct stream *s, size_t length, int use32bit)
{
struct aspath as;
struct aspath *find;
/* If length is odd it's malformed AS path. */
- if (length % AS_VALUE_SIZE)
+ /* Nit-picking: if (use32bit == 0) it is malformed if odd,
+ * otherwise its malformed when length is larger than 2 and (length-2)
+ * is not dividable by 4.
+ * But... this time we're lazy
+ */
+ if (length % AS16_VALUE_SIZE )
return NULL;
- as.segments = assegments_parse (s, length);
+ as.segments = assegments_parse (s, length, use32bit);
/* If already same aspath exist then return it. */
find = hash_get (ashash, &as, aspath_hash_alloc);
@@ -707,13 +909,21 @@ aspath_parse (struct stream *s, size_t length)
}
static inline void
-assegment_data_put (struct stream *s, as_t *as, int num)
+assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
{
int i;
assert (num <= AS_SEGMENT_MAX);
for (i = 0; i < num; i++)
- stream_putw (s, as[i]);
+ if ( use32bit )
+ stream_putl (s, as[i]);
+ else
+ {
+ if ( as[i] <= BGP_AS_MAX )
+ stream_putw(s, (unsigned short) as[i]);
+ else
+ stream_putw(s, (unsigned short) BGP_AS_TRANS);
+ }
}
static inline size_t
@@ -729,7 +939,7 @@ assegment_header_put (struct stream *s, u_char type, int length)
/* write aspath data to stream */
void
-aspath_put (struct stream *s, struct aspath *as)
+aspath_put (struct stream *s, struct aspath *as, int use32bit )
{
struct assegment *seg = as->segments;
@@ -738,7 +948,14 @@ aspath_put (struct stream *s, struct aspath *as)
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 && (((use32bit)?ASSEGMENT_LEN (seg):ASSEGMENT16_LEN(seg)) <= STREAM_WRITEABLE(s)))
{
int written = 0;
size_t lenp;
@@ -747,13 +964,15 @@ aspath_put (struct stream *s, struct aspath *as)
while ( (seg->length - written) > AS_SEGMENT_MAX)
{
assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
- assegment_data_put (s, seg->as, AS_SEGMENT_MAX);
+ assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
written += AS_SEGMENT_MAX;
+ /* This is buggy, analogous to further down! */
+ zlog_err ("aspath_put: BUGGY splitting of an assegment! The peer will complain!");
}
/* write the final segment, probably is also the first */
lenp = assegment_header_put (s, seg->type, seg->length - written);
- assegment_data_put (s, (seg->as + written), seg->length - written);
+ assegment_data_put (s, (seg->as + written), seg->length - written, use32bit);
/* Sequence-type segments can be 'packed' together
* Case of a segment which was overlength and split up
@@ -771,12 +990,22 @@ aspath_put (struct stream *s, struct aspath *as)
*/
/* Next segment's data can fit in this one */
- assegment_data_put (s, seg->next->as, seg->next->length);
+ assegment_data_put (s, seg->next->as, seg->next->length, use32bit);
/* update the length of the segment header */
stream_putc_at (s, lenp,
seg->length - written + seg->next->length);
seg = seg->next->next; /* skip to past next */
+ /** ERROR HERE!
+ * We had set the size of the whole thing as a char or a
+ * short in front of the aspath in the stream.
+ * the aspath_size is calculated by adding up aspath_segments
+ * lengths, each with header.
+ * now we have joined two segments, thus have one aspath_
+ * segment header *less*, so we do *not* have put the right
+ * length into the stream.
+ */
+ zlog_err ("aspath_put: BUGGY merging of two assegments! The peer will complain!");
}
else
seg = seg->next;
@@ -803,7 +1032,7 @@ aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
*varlen = 0;
return NULL;
}
- aspath_put (snmp_stream, as);
+ aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
*varlen = stream_get_endp (snmp_stream);
return stream_pnt(snmp_stream);
@@ -1174,6 +1403,107 @@ aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
return 0;
}
+/* Truncate an aspath after a number of hops, and put the hops remaining
+ * at the front of another aspath. Needed for AS4 compat. */
+void
+aspath_truncateathopsandjoin( struct aspath **aspath, struct aspath **as4_aspath,int hops )
+{
+ struct assegment *startseg, *seg;
+ struct assegment *prevseg = NULL;
+ struct aspath *newfront, *newlybuild;
+
+ if (!*aspath)
+ return;
+
+ startseg = seg = assegment_dup_all( (*aspath)->segments );
+
+ while (seg && hops > 0)
+ {
+ if (seg->type == AS_SEQUENCE || seg->type == AS_CONFED_SEQUENCE )
+ {
+ if ( hops < seg->length )
+ {
+ if ( seg->type == AS_CONFED_SEQUENCE )
+ {
+ /* Now, this can not be legal, can it?
+ * We are supposed to take only *some* ases out of
+ * a CONFED_SEQUENCE. and the path then continues
+ * with the contents of AS4_PATH? you are
+ * kidding, this can not be right.
+ *
+ * Now, what is the fallback in this case?
+ * General fallback is always "use AS_PATH" iff we
+ * can not join aspath and newaspath in a
+ * reasonable way. Tugging only a part of an
+ * AS_CONFED_SEQUENCE at the front of a constructed
+ * path is not reasonable, we loose information.
+ * So, we do nothing at all and take AS_PATH here.
+ *
+ * But burp out a warning, this is suspicious!
+ * Guess someone runs an AS confederation with only
+ * some routers as4 capable... something which is
+ * not supposed to be done...
+ */
+ assegment_free( seg );
+ if (BGP_DEBUG (as4, AS4))
+ zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE would have been cut in two, taking AS_PATH instead of mangling");
+ aspath_unintern(*as4_aspath);
+ *as4_aspath = NULL;
+ return;
+ }
+ /* take only hops */
+ seg->length = hops;
+ /* We have dangling ASes in memory here,
+ * but nobody uses them.
+ * When we free the thing (some lines down), they'll go away too
+ */
+ hops = 0;
+ }
+ else
+ {
+ hops -= seg->length; /* take the sequence and continue */
+ }
+ }
+ else if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
+ {
+ hops--; /* take this, it is one hop */
+ }
+
+ prevseg = seg;
+ seg = seg->next;
+ }
+ /* we should now have hops == 0 and either seg or !seg */
+ /* and prevseg points to the last thing which contains data we need */
+ if ( prevseg )
+ prevseg->next = NULL;
+
+ assegment_free( seg ); /* that one is NULL-resistent */
+
+ /* We have the startseg, and have to put that in front of
+ * as4_aspath->seg
+ * Maybe this could be done easier, but this
+ * way it works without leaving holes
+ */
+ newfront = aspath_new();
+ newfront->segments = startseg;
+
+ newlybuild = aspath_dup(*as4_aspath);
+
+ aspath_merge( newfront, newlybuild );
+ aspath_free(newfront);
+
+ aspath_unintern(*aspath);
+ aspath_unintern(*as4_aspath);
+ *as4_aspath = NULL;
+ /* 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.
+ */
+ newlybuild->segments = assegment_normalise(newlybuild->segments);
+
+ *aspath = aspath_intern(newlybuild);
+}
+
/* Compare leftmost AS value for MED check. If as1's leftmost AS and
as2's leftmost AS is same return 1. (confederation as-path
only). */
@@ -1229,6 +1559,61 @@ aspath_delete_confed_seq (struct aspath *aspath)
return aspath;
}
+/* get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET path segments
+ * in an aspath
+ */
+void
+aspath_cleanoutall_asconfeds( struct aspath **aspath,
+ unsigned int *aspath_data_size )
+{
+ struct assegment *seg, **ptto;
+ struct aspath *cleanedout;
+ int didsomething = 0;
+
+ if (!(*aspath && (*aspath)->segments))
+ return;
+
+ cleanedout = aspath_dup( *aspath );
+ ptto = &cleanedout->segments;
+ seg = *ptto;
+
+ while (seg)
+ {
+ if (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET)
+ {
+ /* ignore this path segment */
+ struct assegment *ignorethis;
+ ignorethis = seg;
+
+ seg = ignorethis->next;
+ *ptto = seg;
+
+ assegment_free (ignorethis);
+ didsomething = 1;
+ }
+ else
+ {
+ ptto = &seg->next;
+ seg = *ptto;
+ }
+ }
+ if ( didsomething )
+ {
+ /* update necessary things */
+ /* sigh, have to normalise - otherwise we can not advertise
+ * the result due to aspath_put merging of segments
+ */
+ cleanedout->segments = assegment_normalise(cleanedout->segments);
+ aspath_str_update (cleanedout);
+ *aspath = cleanedout;
+ *aspath_data_size = aspath_size(*aspath);
+ }
+ else
+ {
+ aspath_free( cleanedout );
+ }
+}
+
/* Add new AS number to the leftmost part of the aspath as
AS_CONFED_SEQUENCE. */
struct aspath*
@@ -1272,7 +1657,7 @@ aspath_segment_add (struct aspath *as, int type)
struct aspath *
aspath_empty (void)
{
- return aspath_parse (NULL, 0);
+ return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
}
struct aspath *
@@ -1315,7 +1700,7 @@ enum as_token
/* Return next token and point for string parse. */
static const char *
-aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
+aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
{
const char *p = buf;
@@ -1356,21 +1741,17 @@ aspath_gettoken (const char *buf, enum as_token *token, u_short *asno)
}
/* Check actual AS value. */
+ /* Is now [<16bitnumber>.]<16bitnumber> for asdot(+),
+ * <32bitnumber> for asplain,
+ * or even <ipaddress> */
+
if (isdigit ((int) *p))
{
- u_short asval;
-
- *token = as_token_asval;
- asval = (*p - '0');
- p++;
- while (isdigit ((int) *p))
- {
- asval *= 10;
- asval += (*p - '0');
- p++;
- }
- *asno = asval;
- return p;
+ /* consolidate, have only one place to interpret strings as asnums */
+ const char *q;
+ *asno = str2asnum( p, &q );
+ *token = (*asno) ? as_token_asval : as_token_unknown;
+ return q;
}
/* There is no match then return unknown token. */
@@ -1383,7 +1764,7 @@ aspath_str2aspath (const char *str)
{
enum as_token token = as_token_unknown;
u_short as_type;
- u_short asno = 0;
+ u_long asno = 0;
struct aspath *aspath;
int needtype;
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 5400c57c..538bada8 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -31,7 +31,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define BGP_PRIVATE_AS_MIN 64512U
#define BGP_PRIVATE_AS_MAX 65535U
+/* we leave BGP_AS_MAX as the 16bit AS MAX number. */
#define BGP_AS_MAX 65535U
+/* Transition 16Bit AS as defined by IANA */
+#define BGP_AS_TRANS 23456U
/* AS_PATH segment data in abstracted form, no limit is placed on length */
struct assegment
@@ -58,10 +61,47 @@ struct aspath
#define ASPATH_STR_DEFAULT_LEN 32
+/* stuffed this here, with as4 we have different asnumber formats */
+enum bgp_asnumber_format
+{
+ BGP_ASNUMBER_FORMAT_ASDOT,
+ BGP_ASNUMBER_FORMAT_ASDOTPLUS,
+ BGP_ASNUMBER_FORMAT_ASPLAIN,
+ BGP_ASNUMBER_FORMAT_ASIP,
+
+ BGP_ASNUMBER_FORMAT_NOTUSED
+};
+
+/* This is the default definition for asnumber output
+ * It is used whenever an asnumber is turned into a string
+ * so it changes the string representation og aspaths as well as
+ * all configuration and command outputs.
+ * As of now, it is ASDOT. It may well become ASPLAIN in the future
+ * if the net community should reach consensus for that.
+ * Aeh, ASIP is more like a joke, nobody wants this - lets say it is
+ * for testing purposes ;-)
+ *
+ * As of now, the RIRs and Cisco already use ASDOT so we use that as
+ * default.
+ * For everybody, the summary (all <...> are given out as decimal value):
+ *
+ * asdot [<higher16bits>.]<lower16bits>
+ * higher16bits ONLY given out if not 0.
+ * asdot+ <higher16bits>.<lower16bits>
+ * higher16bits ALWAYS given out.
+ * asplain <32bits>
+ * asip <8highestbits><8bitsbelowthem><8bitsfurtherdown><lowest8bits>
+ *
+ * BTW, quagga automagically munges all of these formats as inputs, no
+ * change needed there. -JK 20061114
+ */
+
+#define BGP_ASNUMBER_FORMAT_DEFAULT BGP_ASNUMBER_FORMAT_ASDOT
+
/* Prototypes. */
extern void aspath_init (void);
extern void aspath_finish (void);
-extern struct aspath *aspath_parse (struct stream *, size_t);
+extern struct aspath *aspath_parse (struct stream *, size_t, int);
extern struct aspath *aspath_dup (struct aspath *);
extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *);
extern struct aspath *aspath_prepend (struct aspath *, struct aspath *);
@@ -88,9 +128,20 @@ extern unsigned int aspath_count_hops (struct aspath *);
extern unsigned int aspath_count_confeds (struct aspath *);
extern unsigned int aspath_size (struct aspath *);
extern as_t aspath_highest (struct aspath *);
-extern void aspath_put (struct stream *, struct aspath *);
+extern void aspath_put (struct stream *, struct aspath *, int);
+
+extern void aspath_truncateathopsandjoin (struct aspath **, struct aspath **, int);
+extern unsigned int aspath_count_num32as (struct aspath *);
+extern unsigned int aspath_count_numas (struct aspath *);
+extern void aspath_cleanoutall_asconfeds( struct aspath **, unsigned int *);
/* For SNMP BGP4PATHATTRASPATHSEGMENT, might be useful for debug */
extern u_char *aspath_snmp_pathseg (struct aspath *, size_t *);
+/* asnumber format things */
+extern void setasnumber_format (int);
+extern int get_asnumber_format (void);
+extern char *as2str(as_t);
+extern as_t str2asnum (const char *, const char **);
+
#endif /* _QUAGGA_BGP_ASPATH_H */
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 4c72d80a..8a6d542e 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -56,6 +56,8 @@ struct message attr_str [] =
{ BGP_ATTR_RCID_PATH, "RCID_PATH" },
{ BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
{ BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
+ { BGP_ATTR_AS4_PATH, "AS4_PATH" },
+ { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
{ 0, NULL }
};
@@ -655,8 +657,6 @@ static int
bgp_attr_aspath (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag, u_char *startp)
{
- struct bgp *bgp;
- struct aspath *aspath;
bgp_size_t total;
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
@@ -674,8 +674,16 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
return -1;
}
+ /*
+ * peer with AS4 => will get 4Byte ASnums
+ * otherwise, will get 16 Bit
+ */
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
+ attr->aspath = aspath_parse (peer->ibuf, length, 1);
+ else
+ attr->aspath = aspath_parse (peer->ibuf, length, 0);
+
/* In case of IBGP, length will be zero. */
- attr->aspath = aspath_parse (peer->ibuf, length);
if (! attr->aspath)
{
zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
@@ -685,6 +693,28 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
return -1;
}
+ /* Forward pointer. */
+/* stream_forward_getp (peer->ibuf, length);*/
+
+ /* Set aspath attribute flag. */
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
+
+ return 0;
+}
+
+static int bgp_attr_aspath_check( struct peer *peer,
+ struct attr *attr)
+{
+ /* These checks were part of bgp_attr_aspath, but with
+ * as4 we should to check aspath things when
+ * aspath synthesizing with as4_aspath has already taken place.
+ * Otherwise we check ASPATH and use the synthesized thing, and that is
+ * not right.
+ * So do the checks later, i.e. here
+ */
+ struct bgp *bgp = peer->bgp;
+ struct aspath *aspath;
+
bgp = peer->bgp;
/* First AS check for EBGP. */
@@ -712,11 +742,20 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
attr->aspath = aspath_intern (aspath);
}
- /* Forward pointer. */
-/* stream_forward_getp (peer->ibuf, length);*/
+ return 0;
+
+}
+
+/* Parse AS4 path information. This function is another wrapper of
+ aspath_parse. */
+static int
+bgp_attr_as4_aspath (struct peer *peer, bgp_size_t length,
+ struct attr *attr, u_char flag, u_char *startp)
+{
+ attr->as4_aspath = aspath_parse (peer->ibuf, length, 1);
/* Set aspath attribute flag. */
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
return 0;
}
@@ -842,16 +881,31 @@ static int
bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag)
{
- if (length != 6)
+ int wantedlen;
+
+ /*
+ * 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;
+ else
+ wantedlen = 6;
+
+ if (length != wantedlen)
{
- zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
+ zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
bgp_notify_send (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
- attr->aggregator_as = stream_getw (peer->ibuf);
+
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
+ attr->aggregator_as = stream_getl (peer->ibuf);
+ else
+ attr->aggregator_as = stream_getw (peer->ibuf);
+
attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
/* Set atomic aggregate flag. */
@@ -860,6 +914,34 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
return 0;
}
+/* New Aggregator attribute */
+static int
+bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
+ struct attr *attr, u_char flag)
+{
+ as_t as4_aggregator_as;
+ u_int32_t as4_aggregator_address;
+
+ 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_address = stream_get_ipv4 (peer->ibuf);
+ /* Set atomic aggregate flag. */
+ attr->as4_aggregator_as = as4_aggregator_as;
+ attr->as4_aggregator_addr.s_addr = as4_aggregator_address;
+
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
+
+ return 0;
+}
+
/* Community attribute. */
static int
bgp_attr_community (struct peer *peer, bgp_size_t length,
@@ -1238,6 +1320,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
case BGP_ATTR_AS_PATH:
ret = bgp_attr_aspath (peer, length, attr, flag, startp);
break;
+ case BGP_ATTR_AS4_PATH:
+ ret = bgp_attr_as4_aspath (peer, length, attr, flag, startp);
+ break;
case BGP_ATTR_NEXT_HOP:
ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
break;
@@ -1253,6 +1338,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
case BGP_ATTR_AGGREGATOR:
ret = bgp_attr_aggregator (peer, length, attr, flag);
break;
+ case BGP_ATTR_AS4_AGGREGATOR:
+ ret = bgp_attr_as4_aggregator (peer, length, attr, flag);
+ break;
case BGP_ATTR_COMMUNITIES:
ret = bgp_attr_community (peer, length, attr, flag);
break;
@@ -1303,6 +1391,169 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
return -1;
}
+ /*
+ * At this place we can see whether we got AS4_PATH and/or
+ * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
+ * We can not do this before we've read all attributes because
+ * the as4 handling does not say whether AS4_PATH has to be sent
+ * after AS_PATH or not - and when AS4_AGGREGATOR will be send
+ * in relationship to AGGREGATOR.
+ * So, to be defensive, we are not relying on any order and read
+ * all attributes first, including these 32bit ones, and now,
+ * afterwards, we look what and if something is to be done for as4.
+ */
+
+ if ( 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 ( CHECK_BITMAP (seen, BGP_ATTR_AS4_PATH) )
+ {
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug ( "[AS4] %s BGP AS4 capable peer send AS4_PATH", peer->host);
+ }
+ if ( CHECK_BITMAP (seen, BGP_ATTR_AS4_AGGREGATOR) )
+ {
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug ( "[AS4] %s BGP AS4 capable peer send AS4_AGGREGATOR", peer->host);
+ }
+ }
+ else
+ {
+ /* We have a asn16 peer. First, look for AS4_AGGREGATOR
+ * because that may override AS4_PATH
+ */
+ int ignore_as4_aspath = 0;
+ if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
+ {
+ 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 ( attr->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_aspath = 1;
+ }
+ else
+ {
+ /* "New_aggregator shall be taken as aggregator" */
+ attr->aggregator_as = attr->as4_aggregator_as;
+ attr->aggregator_addr.s_addr = attr->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);
+ attr->aggregator_as = attr->as4_aggregator_as;
+ /* sweep it under the carpet and simulate a "good" AGGREGATOR */
+ SET_BITMAP (seen, BGP_ATTR_AGGREGATOR);
+ attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
+ }
+ }
+ if ( !ignore_as4_aspath && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
+ {
+ if ( ! (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
+ {
+ /* Hu? This is not supposed to happen at all!
+ * got as4_aspath 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 AS4_PATH AND AS_PATH
+ * Calculate the number of as numbers in both attributes!
+ * What is meant is the number of "hops"!
+ * if numas_in_aspath < numas_in_as4_aspath =>
+ * ignore AS4_PATH, take AS_PATH.
+ * else
+ * take as many as_numbers and path segments from AS_PATH
+ * and prepend them to AS4_PATH so that
+ * num_new = numas_in_aspath
+ * the resulting thing is our AS_PATH
+ * An AS_SET or AS_CONFED_SET is one hop
+ * every other thing has as many hops as asnums
+ */
+ int hopnumdiff = aspath_count_hops( attr->aspath ) - aspath_count_hops( attr->as4_aspath );
+
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug (
+ "[AS4] %s fiddling with aspath and newaspath, hopnumdifference is %d",
+ peer->host, hopnumdiff);
+ if ( hopnumdiff >= 0 )
+ {
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug(
+ "[AS4] %s got AS_PATH %s and AS4_PATH %s synthesizing now", peer->host, attr->aspath->str, attr->as4_aspath->str);
+ aspath_truncateathopsandjoin( &attr->aspath, &attr->as4_aspath, hopnumdiff );
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug(
+ "[AS4] %s result of synthesizing is %s", peer->host, attr->aspath->str);
+ }
+ }
+ }
+
+ /* 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_aspath alltogether in
+ * order to save memory
+ */
+ if ( attr->as4_aspath )
+ {
+ aspath_unintern( attr->as4_aspath ); /* unintern - it is in the hash */
+ attr->as4_aspath = NULL;
+ /* The flag that we got this is still there, but that does not
+ * do any trouble
+ */
+ }
+ /*
+ * The "rest" of the code does nothing with as4_aggregator.
+ * there is no memory attached specifically which is not part
+ * of the attr.
+ * so ignoring just means do nothing.
+ */
+ /*
+ * Finally do the checks on the aspath we did not do yet
+ * because we waited for a potentially synthesized aspath.
+ */
+ if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
+ {
+ ret = bgp_attr_aspath_check( peer, attr );
+ if ( ret < 0 )
+ return ret;
+ }
+
/* Finally intern unknown attribute. */
if (attr->transit)
attr->transit = transit_intern (attr->transit);
@@ -1354,6 +1605,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
{
size_t cp;
unsigned int aspath_data_size;
+ unsigned int numas;
struct aspath *aspath;
if (! bgp)
@@ -1401,21 +1653,92 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
else
aspath = attr->aspath;
+ /* If peer is not AS4 capable, then:
+ * - send the created AS_PATH out as AS4_PATH (optional, transitive),
+ * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
+ * types are in it (i.e. exclude them if they are there)
+ * AND do this only if there is at least one asnum > 65535 in the path!
+ * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
+ * all ASnums > 65535 to BGP_AS_TRANS
+ *
+ * Beware: aspath_data_size is ONLY correct if there is no aspath segment
+ * longer 255, and no two segments which are able to be merged
+ * That thing is in the code for a looonng time and nobody bothers.
+ */
+
/* AS path attribute extended length bit check. */
aspath_data_size = aspath_size (aspath);
- if (aspath_data_size > 255)
+ numas = aspath_count_numas( aspath );
+
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
{
- stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_AS_PATH);
- stream_putw (s, aspath_data_size);
+ /* this is the easy part, peer is as4 capable, send 4 byte aspath */
+ if (aspath_data_size > 255)
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_AS_PATH);
+ stream_putw (s, aspath_data_size);
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AS_PATH);
+ stream_putc (s, aspath_data_size);
+ }
+ aspath_put (s, aspath, 1);
}
else
{
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_AS_PATH);
- stream_putc (s, aspath_data_size);
+ /*
+ * size of 16bit aspath is smaller by number of asnums * 2Bytes
+ * actually, number os asnums * (sizeof(as_t) - sizeof(as16_t)),
+ * but that is nit-picking.
+ */
+ if (aspath_data_size - 2*numas > 255)
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_AS_PATH);
+ stream_putw (s, aspath_data_size - 2*numas );
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AS_PATH);
+ stream_putc (s, aspath_data_size - 2*numas );
+ }
+ aspath_put (s, aspath, 0);
+
+ if ( aspath_count_num32as( aspath ) > 0 )
+ {
+ /* put out AS4_PATH (only if there are ASnums > 65535 in 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!?
+ */
+ if ( aspath_count_confeds(aspath) > 0 ) {
+ aspath_cleanoutall_asconfeds( &aspath, &aspath_data_size );
+ }
+
+ if (aspath_data_size > 255)
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_AS4_PATH);
+ stream_putw (s, aspath_data_size);
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc (s, BGP_ATTR_AS4_PATH);
+ stream_putc (s, aspath_data_size);
+ }
+ aspath_put (s, aspath, 1);
+ }
}
- aspath_put (s, aspath);
if (aspath != attr->aspath)
aspath_free (aspath);
@@ -1467,11 +1790,50 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
/* Aggregator. */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
{
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_AGGREGATOR);
- stream_putc (s, 6);
- stream_putw (s, attr->aggregator_as);
- stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ /* If peer is AS4 capable,
+ * then
+ * send BGP_ATTR_AGGREGATOR with 32 bit AS value
+ * else
+ * if attr->aggregator_as > 65535
+ * change the aggregator_as in the AGGREGATOR to AS_TRANS
+ * and send out a AS4_AGGREGATOR (opt, transitional)
+ * with the correct 4 Bytes thingy.
+ * else
+ * proceed as you always did
+ */
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AGGREGATOR);
+ stream_putc (s, 8);
+ stream_putl (s, attr->aggregator_as);
+ stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ }
+ else
+ {
+ if ( attr->aggregator_as > 65535 )
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AGGREGATOR);
+ stream_putc (s, 6);
+ stream_putw (s, BGP_AS_TRANS);
+ stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+
+ 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->aggregator_as);
+ stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AGGREGATOR);
+ stream_putc (s, 6);
+ stream_putw (s, (u_int16_t) attr->aggregator_as);
+ stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ }
+ }
}
/* Community attribute. */
@@ -1758,7 +2120,7 @@ bgp_attr_init (void)
/* Make attribute packet. */
void
bgp_dump_routes_attr (struct stream *s, struct attr *attr,
- struct prefix *prefix)
+ struct prefix *prefix, int dump_small_mp_nlri)
{
unsigned long cp;
unsigned long len;
@@ -1791,7 +2153,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
stream_putc (s, BGP_ATTR_AS_PATH);
stream_putc (s, aspathlen);
}
- aspath_put (s, aspath);
+ aspath_put (s, aspath, 1); /* always 32bit. aspath_put size remarks apply */
/* Nexthop attribute. */
/* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
@@ -1838,8 +2200,8 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
{
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_AGGREGATOR);
- stream_putc (s, 6);
- stream_putw (s, attr->aggregator_as);
+ stream_putc (s, 8);
+ stream_putl (s, attr->aggregator_as);
stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
}
@@ -1874,8 +2236,11 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
/* MP header */
stream_putc (s, 0); /* Length of this attribute. */
- stream_putw(s, AFI_IP6); /* AFI */
- stream_putc(s, SAFI_UNICAST); /* SAFI */
+ if(!dump_small_mp_nlri)
+ {
+ stream_putw(s, AFI_IP6); /* AFI */
+ stream_putc(s, SAFI_UNICAST); /* SAFI */
+ }
/* Next hop */
stream_putc(s, attr->mp_nexthop_len);
@@ -1883,11 +2248,14 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
if(attr->mp_nexthop_len == 32)
stream_put(s, &attr->mp_nexthop_local, 16);
- /* SNPA */
- stream_putc(s, 0);
+ if(!dump_small_mp_nlri)
+ {
+ /* SNPA */
+ stream_putc(s, 0);
- /* Prefix */
- stream_put_prefix(s, prefix);
+ /* Prefix */
+ stream_put_prefix(s, prefix);
+ }
/* Set MP attribute length. */
stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 777869ce..1c91dd89 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -57,6 +57,9 @@ struct attr
/* AS Path structure */
struct aspath *aspath;
+ /* New AS Path structure */
+ struct aspath *as4_aspath;
+
/* Community structure */
struct community *community;
@@ -80,11 +83,13 @@ struct attr
u_int32_t med;
u_int32_t local_pref;
struct in_addr aggregator_addr;
+ struct in_addr as4_aggregator_addr;
struct in_addr originator_id;
struct in_addr mp_nexthop_global_in;
struct in_addr mp_nexthop_local_in;
u_int32_t weight;
as_t aggregator_as;
+ as_t as4_aggregator_as;
u_char origin;
u_char mp_nexthop_len;
};
@@ -128,7 +133,7 @@ extern bgp_size_t bgp_packet_withdraw (struct peer *peer, struct stream *s,
struct prefix *p, afi_t, safi_t,
struct prefix_rd *, u_char *);
extern void bgp_dump_routes_attr (struct stream *, struct attr *,
- struct prefix *);
+ struct prefix *, int dump_small_mp_nlri);
extern unsigned int attrhash_key_make (struct attr *);
extern int attrhash_cmp (struct attr *, struct attr *);
extern void attr_show_all (struct vty *);
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 1986b35b..e2b27a74 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_community.h"
+unsigned long conf_bgp_debug_as4;
unsigned long conf_bgp_debug_fsm;
unsigned long conf_bgp_debug_events;
unsigned long conf_bgp_debug_packet;
@@ -45,6 +46,7 @@ unsigned long conf_bgp_debug_update;
unsigned long conf_bgp_debug_normal;
unsigned long conf_bgp_debug_zebra;
+unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_fsm;
unsigned long term_bgp_debug_events;
unsigned long term_bgp_debug_packet;
@@ -208,8 +210,8 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
snprintf (buf + strlen (buf), size - strlen (buf), ", atomic-aggregate");
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)))
- snprintf (buf + strlen (buf), size - strlen (buf), ", aggregated by %d %s",
- attr->aggregator_as, inet_ntoa (attr->aggregator_addr));
+ snprintf (buf + strlen (buf), size - strlen (buf), ", aggregated by %s %s",
+ as2str(attr->aggregator_as), inet_ntoa (attr->aggregator_addr));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)))
snprintf (buf + strlen (buf), size - strlen (buf), ", originator %s",
@@ -294,6 +296,138 @@ debug (unsigned int option)
return bgp_debug_option & option;
}
+DEFUN (debug_bgp_as4,
+ debug_bgp_as4_cmd,
+ "debug bgp as4",
+ DEBUG_STR
+ BGP_STR
+ "BGP AS4 actions\n")
+{
+ if (vty->node == CONFIG_NODE)
+ DEBUG_ON (as4, AS4);
+ else
+ {
+ TERM_DEBUG_ON (as4, AS4);
+ vty_out (vty, "BGP as4 debugging is on%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS_DEPRECATED (debug_bgp_as4,
+ debug_bgp_asn32_cmd,
+ "debug bgp asn32",
+ DEBUG_STR
+ BGP_STR
+ "BGP AS4 actions (old syntax, deprecated)\n")
+
+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_DEPRECATED (no_debug_bgp_as4,
+ no_debug_bgp_asn32_cmd,
+ "no debug bgp asn32",
+ NO_STR
+ DEBUG_STR
+ BGP_STR
+ "BGP AS4 actions (old syntax, deprecated)\n")
+
+ALIAS (no_debug_bgp_as4,
+ undebug_bgp_as4_cmd,
+ "undebug bgp as4",
+ UNDEBUG_STR
+ DEBUG_STR
+ BGP_STR
+ "BGP AS4 actions\n")
+
+ALIAS_DEPRECATED (no_debug_bgp_as4,
+ undebug_bgp_asn32_cmd,
+ "undebug bgp asn32",
+ UNDEBUG_STR
+ DEBUG_STR
+ BGP_STR
+ "BGP AS4 actions (old syntax, deprecated)\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;
+}
+
+ALIAS_DEPRECATED (debug_bgp_as4_segment,
+ debug_bgp_asn32_segment_cmd,
+ "debug bgp asn32 segment",
+ DEBUG_STR
+ BGP_STR
+ "BGP AS4 aspath segment handling (old syntax, deprecated)\n")
+
+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_DEPRECATED (no_debug_bgp_as4_segment,
+ no_debug_bgp_asn32_segment_cmd,
+ "no debug bgp asn32 segment",
+ NO_STR
+ DEBUG_STR
+ BGP_STR
+ "BGP AS4 aspath segment handling (old syntax, deprecated)\n")
+
+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")
+
+ALIAS_DEPRECATED (no_debug_bgp_as4_segment,
+ undebug_bgp_asn32_segment_cmd,
+ "undebug bgp asn32 segment",
+ UNDEBUG_STR
+ DEBUG_STR
+ BGP_STR
+ "BGP AS4 aspath segment handling (old syntax, deprecated)\n")
+
DEFUN (debug_bgp_fsm,
debug_bgp_fsm_cmd,
"debug bgp fsm",
@@ -648,6 +782,8 @@ DEFUN (no_debug_bgp_all,
TERM_DEBUG_OFF (keepalive, KEEPALIVE);
TERM_DEBUG_OFF (update, UPDATE_IN);
TERM_DEBUG_OFF (update, UPDATE_OUT);
+ TERM_DEBUG_OFF (as4, AS4);
+ TERM_DEBUG_OFF (as4, AS4_SEGMENT);
TERM_DEBUG_OFF (fsm, FSM);
TERM_DEBUG_OFF (filter, FILTER);
TERM_DEBUG_OFF (zebra, ZEBRA);
@@ -690,6 +826,10 @@ DEFUN (show_debugging_bgp,
vty_out (vty, " BGP filter debugging is on%s", VTY_NEWLINE);
if (BGP_DEBUG (zebra, ZEBRA))
vty_out (vty, " BGP zebra debugging is on%s", VTY_NEWLINE);
+ if (BGP_DEBUG (as4, AS4))
+ vty_out (vty, " BGP as4 debugging is on%s", VTY_NEWLINE);
+ if (BGP_DEBUG (as4, AS4_SEGMENT))
+ vty_out (vty, " BGP as4 aspath segment debugging is on%s", VTY_NEWLINE);
vty_out (vty, "%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -705,6 +845,18 @@ bgp_config_write_debug (struct vty *vty)
write++;
}
+ if (CONF_BGP_DEBUG (as4, AS4))
+ {
+ vty_out (vty, "debug bgp as4%s", VTY_NEWLINE);
+ write++;
+ }
+
+ if (CONF_BGP_DEBUG (as4, AS4_SEGMENT))
+ {
+ vty_out (vty, "debug bgp as4 segment%s", VTY_NEWLINE);
+ write++;
+ }
+
if (CONF_BGP_DEBUG (events, EVENTS))
{
vty_out (vty, "debug bgp events%s", VTY_NEWLINE);
@@ -768,6 +920,16 @@ bgp_debug_init (void)
install_element (ENABLE_NODE, &show_debugging_bgp_cmd);
+ install_element (ENABLE_NODE, &debug_bgp_as4_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_as4_cmd);
+ install_element (ENABLE_NODE, &debug_bgp_as4_segment_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_as4_segment_cmd);
+ /* compat for former AS4 patch */
+ install_element (ENABLE_NODE, &debug_bgp_asn32_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_asn32_cmd);
+ install_element (ENABLE_NODE, &debug_bgp_asn32_segment_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_asn32_segment_cmd);
+
install_element (ENABLE_NODE, &debug_bgp_fsm_cmd);
install_element (CONFIG_NODE, &debug_bgp_fsm_cmd);
install_element (ENABLE_NODE, &debug_bgp_events_cmd);
@@ -785,6 +947,20 @@ bgp_debug_init (void)
install_element (ENABLE_NODE, &debug_bgp_zebra_cmd);
install_element (CONFIG_NODE, &debug_bgp_zebra_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_as4_cmd);
+ install_element (ENABLE_NODE, &undebug_bgp_as4_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_as4_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_as4_segment_cmd);
+ install_element (ENABLE_NODE, &undebug_bgp_as4_segment_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_as4_segment_cmd);
+ /* compat for former AS4 patch */
+ install_element (ENABLE_NODE, &no_debug_bgp_asn32_cmd);
+ install_element (ENABLE_NODE, &undebug_bgp_asn32_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_asn32_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_asn32_segment_cmd);
+ install_element (ENABLE_NODE, &undebug_bgp_asn32_segment_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_asn32_segment_cmd);
+
install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd);
install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd);
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index eab95d09..9e7c1f39 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -56,6 +56,7 @@ extern void bgp_packet_dump (struct stream *);
extern int debug (unsigned int option);
+extern unsigned long conf_bgp_debug_as4;
extern unsigned long conf_bgp_debug_fsm;
extern unsigned long conf_bgp_debug_events;
extern unsigned long conf_bgp_debug_packet;
@@ -65,6 +66,7 @@ extern unsigned long conf_bgp_debug_update;
extern unsigned long conf_bgp_debug_normal;
extern unsigned long conf_bgp_debug_zebra;
+extern unsigned long term_bgp_debug_as4;
extern unsigned long term_bgp_debug_fsm;
extern unsigned long term_bgp_debug_events;
extern unsigned long term_bgp_debug_packet;
@@ -74,6 +76,9 @@ extern unsigned long term_bgp_debug_update;
extern unsigned long term_bgp_debug_normal;
extern unsigned long term_bgp_debug_zebra;
+#define BGP_DEBUG_AS4 0x01
+#define BGP_DEBUG_AS4_SEGMENT 0x02
+
#define BGP_DEBUG_FSM 0x01
#define BGP_DEBUG_EVENTS 0x01
#define BGP_DEBUG_PACKET 0x01
diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c
index c350e83a..c425d571 100644
--- a/bgpd/bgp_dump.c
+++ b/bgpd/bgp_dump.c
@@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "command.h"
#include "prefix.h"
#include "thread.h"
+#include "linklist.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgpd.h"
@@ -53,7 +54,8 @@ enum MRT_MSG_TYPES {
MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */
MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */
MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */
- MSG_TABLE_DUMP /* routing table dump */
+ MSG_TABLE_DUMP, /* routing table dump */
+ MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */
};
static int bgp_dump_interval_func (struct thread *);
@@ -190,137 +192,189 @@ bgp_dump_set_size (struct stream *s, int type)
}
static void
-bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi,
- int type, unsigned int seq)
+bgp_dump_routes_index_table(struct bgp *bgp)
{
- struct stream *obuf;
- struct attr *attr;
struct peer *peer;
- int plen;
- int safi = 0;
+ struct listnode *node;
+ uint16_t peerno = 0;
+ struct stream *obuf;
- /* Make dump stream. */
obuf = bgp_dump_obuf;
stream_reset (obuf);
- attr = info->attr;
- peer = info->peer;
+ /* MRT header */
+ bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE);
- /* We support MRT's old format. */
- if (type == MSG_TABLE_DUMP)
+ /* Collector BGP ID */
+ stream_put_in_addr (obuf, &bgp->router_id);
+
+ /* View name */
+ if(bgp->name)
{
- bgp_dump_header (obuf, MSG_TABLE_DUMP, afi);
- stream_putw (obuf, 0); /* View # */
- stream_putw (obuf, seq); /* Sequence number. */
+ stream_putw (obuf, strlen(bgp->name));
+ stream_put(obuf, bgp->name, strlen(bgp->name));
}
else
{
- bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY);
-
- stream_putl (obuf, info->uptime); /* Time Last Change */
- stream_putw (obuf, afi); /* Address Family */
- stream_putc (obuf, safi); /* SAFI */
+ stream_putw(obuf, 0);
}
- if (afi == AFI_IP)
- {
- if (type == MSG_TABLE_DUMP)
- {
- /* Prefix */
- stream_put_in_addr (obuf, &p->u.prefix4);
- stream_putc (obuf, p->prefixlen);
-
- /* Status */
- stream_putc (obuf, 1);
-
- /* Originated */
- stream_putl (obuf, info->uptime);
-
- /* Peer's IP address */
- stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
+ /* Peer count */
+ stream_putw (obuf, listcount(bgp->peer));
- /* Peer's AS number. */
- stream_putw (obuf, peer->as);
-
- /* Dump attribute. */
- bgp_dump_routes_attr (obuf, attr, p);
- }
- else
- {
- /* Next-Hop-Len */
- stream_putc (obuf, IPV4_MAX_BYTELEN);
- stream_put_in_addr (obuf, &attr->nexthop);
- stream_putc (obuf, p->prefixlen);
- plen = PSIZE (p->prefixlen);
- stream_put (obuf, &p->u.prefix4, plen);
- bgp_dump_routes_attr (obuf, attr, p);
- }
- }
-#ifdef HAVE_IPV6
- else if (afi == AFI_IP6)
+ /* Walk down all peers */
+ for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
{
- if (type == MSG_TABLE_DUMP)
- {
- /* Prefix */
- stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN);
- stream_putc (obuf, p->prefixlen);
- /* Status */
- stream_putc (obuf, 1);
+ /* Peer's type */
+ if (sockunion_family(&peer->su) == AF_INET)
+ {
+ stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
+ }
+#ifdef HAVE_IPV6
+ else if (sockunion_family(&peer->su) == AF_INET6)
+ {
+ stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
+ }
+#endif /* HAVE_IPV6 */
- /* Originated */
- stream_putl (obuf, info->uptime);
+ /* Peer's BGP ID */
+ stream_put_in_addr (obuf, &peer->remote_id);
- /* Peer's IP address */
- stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
- IPV6_MAX_BYTELEN);
+ /* Peer's IP address */
+ if (sockunion_family(&peer->su) == AF_INET)
+ {
+ stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
+ }
+#ifdef HAVE_IPV6
+ else if (sockunion_family(&peer->su) == AF_INET6)
+ {
+ stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
+ IPV6_MAX_BYTELEN);
+ }
+#endif /* HAVE_IPV6 */
- /* Peer's AS number. */
- stream_putw (obuf, peer->as);
+ /* Peer's AS number. */
+ /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
+ stream_putl (obuf, peer->as);
- /* Dump attribute. */
- bgp_dump_routes_attr (obuf, attr, p);
- }
- else
- {
- ;
- }
+ /* Store the peer number for this peer */
+ peer->table_dump_index = peerno;
+ peerno++;
}
-#endif /* HAVE_IPV6 */
- /* Set length. */
- bgp_dump_set_size (obuf, type);
+ bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
fflush (bgp_dump_routes.fp);
}
+
/* Runs under child process. */
-static void
-bgp_dump_routes_func (int afi)
+static unsigned int
+bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
{
struct stream *obuf;
- struct bgp_node *rn;
struct bgp_info *info;
+ struct bgp_node *rn;
struct bgp *bgp;
struct bgp_table *table;
- unsigned int seq = 0;
-
- obuf = bgp_dump_obuf;
bgp = bgp_get_default ();
if (!bgp)
- return;
+ return seq;
if (bgp_dump_routes.fp == NULL)
- return;
+ return seq;
+
+ /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
+ so this should only be done on the first call to bgp_dump_routes_func.
+ ( this function will be called once for ipv4 and once for ipv6 ) */
+ if(first_run)
+ bgp_dump_routes_index_table(bgp);
+
+ obuf = bgp_dump_obuf;
+ stream_reset(obuf);
/* Walk down each BGP route. */
table = bgp->rib[afi][SAFI_UNICAST];
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- for (info = rn->info; info; info = info->next)
- bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++);
+ {
+ if(!rn->info)
+ continue;
+
+ stream_reset(obuf);
+
+ /* MRT header */
+ if (afi == AFI_IP)
+ {
+ bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
+ }
+#ifdef HAVE_IPV6
+ else if (afi == AFI_IP6)
+ {
+ bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
+ }
+#endif /* HAVE_IPV6 */
+
+ /* Sequence number */
+ stream_putl(obuf, seq);
+
+ /* Prefix length */
+ stream_putc (obuf, rn->p.prefixlen);
+
+ /* Prefix */
+ if (afi == AFI_IP)
+ {
+ /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
+ stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
+ }
+#ifdef HAVE_IPV6
+ else if (afi == AFI_IP6)
+ {
+ /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
+ stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
+ }
+#endif /* HAVE_IPV6 */
+
+ /* Save where we are now, so we can overwride the entry count later */
+ int sizep = stream_get_endp(obuf);
+
+ /* Entry count */
+ uint16_t entry_count = 0;
+
+ /* Entry count, note that this is overwritten later */
+ stream_putw(obuf, 0);
+
+ for (info = rn->info; info; info = info->next)
+ {
+ entry_count++;
+
+ /* Peer index */
+ stream_putw(obuf, info->peer->table_dump_index);
+
+ /* Originated */
+ stream_putl (obuf, info->uptime);
+
+ /* Dump attribute. */
+ /* Skip prefix & AFI/SAFI for MP_NLRI */
+ bgp_dump_routes_attr (obuf, info->attr, &rn->p, 1);
+ }
+
+ /* 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
@@ -336,9 +390,9 @@ bgp_dump_interval_func (struct thread *t)
/* In case of bgp_dump_routes, we need special route dump function. */
if (bgp_dump->type == BGP_DUMP_ROUTES)
{
- bgp_dump_routes_func (AFI_IP);
+ unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
#ifdef HAVE_IPV6
- bgp_dump_routes_func (AFI_IP6);
+ bgp_dump_routes_func (AFI_IP6, 0, seq);
#endif /* HAVE_IPV6 */
/* Close the file now. For a RIB dump there's no point in leaving
* it open until the next scheduled dump starts. */
@@ -355,13 +409,21 @@ bgp_dump_interval_func (struct thread *t)
/* Dump common information. */
static void
-bgp_dump_common (struct stream *obuf, struct peer *peer)
+bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
{
char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/* Source AS number and Destination AS number. */
- stream_putw (obuf, peer->as);
- stream_putw (obuf, peer->local_as);
+ if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
+ {
+ stream_putl (obuf, peer->as);
+ stream_putl (obuf, peer->local_as);
+ }
+ else
+ {
+ stream_putw (obuf, peer->as);
+ stream_putw (obuf, peer->local_as);
+ }
if (peer->su.sa.sa_family == AF_INET)
{
@@ -407,8 +469,8 @@ bgp_dump_state (struct peer *peer, int status_old, int status_new)
obuf = bgp_dump_obuf;
stream_reset (obuf);
- bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE);
- bgp_dump_common (obuf, peer);
+ bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4);
+ bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
stream_putw (obuf, status_old);
stream_putw (obuf, status_new);
@@ -436,8 +498,15 @@ bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
stream_reset (obuf);
/* Dump header and common part. */
- bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
- bgp_dump_common (obuf, peer);
+ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
+ {
+ bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4);
+ }
+ else
+ {
+ bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
+ }
+ bgp_dump_common (obuf, peer, 0);
/* Packet contents. */
stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h
index 36447e93..6bb1197b 100644
--- a/bgpd/bgp_dump.h
+++ b/bgpd/bgp_dump.h
@@ -25,14 +25,28 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* type value */
#define MSG_PROTOCOL_BGP4MP 16
/* subtype value */
-#define BGP4MP_STATE_CHANGE 0
-#define BGP4MP_MESSAGE 1
-#define BGP4MP_ENTRY 2
-#define BGP4MP_SNAPSHOT 3
+#define BGP4MP_STATE_CHANGE 0
+#define BGP4MP_MESSAGE 1
+#define BGP4MP_ENTRY 2
+#define BGP4MP_SNAPSHOT 3
+#define BGP4MP_MESSAGE_AS4 4
+#define BGP4MP_STATE_CHANGE_AS4 5
#define BGP_DUMP_HEADER_SIZE 12
#define BGP_DUMP_MSG_HEADER 40
+#define TABLE_DUMP_V2_PEER_INDEX_TABLE 1
+#define TABLE_DUMP_V2_RIB_IPV4_UNICAST 2
+#define TABLE_DUMP_V2_RIB_IPV4_MULTICAST 3
+#define TABLE_DUMP_V2_RIB_IPV6_UNICAST 4
+#define TABLE_DUMP_V2_RIB_IPV6_MULTICAST 5
+#define TABLE_DUMP_V2_RIB_GENERIC 6
+
+#define TABLE_DUMP_V2_PEER_INDEX_TABLE_IP 0
+#define TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6 1
+#define TABLE_DUMP_V2_PEER_INDEX_TABLE_AS2 0
+#define TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4 2
+
extern void bgp_dump_init (void);
extern void bgp_dump_state (struct peer *, int, int);
extern void bgp_dump_packet (struct peer *, int, struct stream *);
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 64f4438f..3e62496d 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_aspath.h"
/* Hash of community attribute. */
struct hash *ecomhash;
@@ -283,7 +284,9 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
u_int32_t val_high = 0;
const char *p = str;
struct in_addr ip;
- char ipstr[INET_ADDRSTRLEN + 1];
+ as_t as4;
+ int wantas4;
+ char helpstr[INET_ADDRSTRLEN + 1];
/* Skip white space. */
while (isspace ((int) *p))
@@ -297,7 +300,7 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
return NULL;
/* "rt" and "soo" keyword parse. */
- if (! isdigit ((int) *p))
+ if (! isdigit ((int) *p) && *p != '+')
{
/* "rt" match check. */
if (tolower ((int) *p) == 'r')
@@ -346,9 +349,23 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
goto error;
}
- while (isdigit ((int) *p) || *p == ':' || *p == '.')
+ as4 = (as_t) 0; wantas4 = 0;
+ while (isdigit ((int) *p) || *p == ':' || *p == '.' || *p == '+' )
{
- if (*p == ':')
+ if ( *p == '+' )
+ {
+ /* '+' indicates an AS number which should be encoded
+ * into a ECOMMUNITY_ENCODE_AS4
+ * The actual *value* of the as number is independent
+ * of the line representation of the extended community
+ */
+ /* test: seen a '+' before? that is an error */
+ if ( as4 || wantas4 || val_low || val_high )
+ goto error;
+
+ wantas4 = 1;
+ }
+ else if (*p == ':')
{
if (separator)
goto error;
@@ -361,12 +378,30 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
if ((p - str) > INET_ADDRSTRLEN)
goto error;
- memset (ipstr, 0, INET_ADDRSTRLEN + 1);
- memcpy (ipstr, str, p - str);
+ memset (helpstr, 0, INET_ADDRSTRLEN + 1);
+ memcpy (helpstr, str, p - str);
- ret = inet_aton (ipstr, &ip);
- if (ret == 0)
- goto error;
+ if ( dot == 1 )
+ {
+ /* ONE dot => 4 Byte AS number */
+ if ( wantas4 )
+ {
+ /* wantas4: skip the '+' at the start */
+ as4 = str2asnum( helpstr+1, NULL);
+ }
+ else
+ {
+ as4 = str2asnum( helpstr, NULL);
+ }
+ if ( !as4 )
+ goto error;
+ }
+ else
+ {
+ ret = inet_aton (helpstr, &ip);
+ if (ret == 0)
+ goto error;
+ }
}
else
val_high = val_low;
@@ -394,8 +429,24 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
if (! digit || ! separator)
goto error;
+ /* move asnumber to as4, even if it is < 65536 */
+ if ( !as4 && dot != 1 )
+ {
+ as4 = val_high;
+ }
/* Encode result into routing distinguisher. */
- if (dot)
+ if (wantas4)
+ {
+ eval->val[0] = ECOMMUNITY_ENCODE_AS4;
+ eval->val[1] = 0;
+ eval->val[2] = (as4 >>24) & 0xff;
+ eval->val[3] = (as4 >>16) & 0xff;
+ eval->val[4] = (as4 >>8) & 0xff;
+ eval->val[5] = as4 & 0xff;
+ eval->val[6] = (val_low >> 8) & 0xff;
+ eval->val[7] = val_low & 0xff;
+ }
+ else if (dot && dot != 1)
{
eval->val[0] = ECOMMUNITY_ENCODE_IP;
eval->val[1] = 0;
@@ -407,6 +458,14 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
{
eval->val[0] = ECOMMUNITY_ENCODE_AS;
eval->val[1] = 0;
+ if ( as4 > 65535 )
+ {
+ /* ENCODE_AS can only code with < 65536.
+ * use BGP_AS_TRANS if we have a too big as number
+ */
+
+ val_high = BGP_AS_TRANS;
+ }
eval->val[2] = (val_high >>8) & 0xff;
eval->val[3] = val_high & 0xff;
eval->val[4] = (val_low >>24) & 0xff;
@@ -533,7 +592,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
u_int8_t *pnt;
int encode = 0;
int type = 0;
-#define ECOMMUNITY_STR_DEFAULT_LEN 26
+#define ECOMMUNITY_STR_DEFAULT_LEN 27
int str_size;
int str_pnt;
char *str_buf;
@@ -576,7 +635,8 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
/* High-order octet of type. */
encode = *pnt++;
- if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP)
+ if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP
+ && encode != ECOMMUNITY_ENCODE_AS4)
{
len = sprintf (str_buf + str_pnt, "?");
str_pnt += len;
@@ -618,6 +678,21 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
}
/* Put string into buffer. */
+ if (encode == ECOMMUNITY_ENCODE_AS4)
+ {
+ eas.as = (*pnt++ << 24);
+ eas.as |= (*pnt++ << 16);
+ eas.as |= (*pnt++ << 8);
+ eas.as |= (*pnt++);
+
+ eas.val = (*pnt++ << 8);
+ eas.val |= (*pnt++);
+
+ len = sprintf( str_buf + str_pnt, "%s+%s:%d", prefix,
+ as2str(eas.as), eas.val );
+ str_pnt += len;
+ first = 0;
+ }
if (encode == ECOMMUNITY_ENCODE_AS)
{
eas.as = (*pnt++ << 8);
@@ -628,8 +703,8 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
eas.val |= (*pnt++ << 8);
eas.val |= (*pnt++);
- len = sprintf (str_buf + str_pnt, "%s%d:%d", prefix,
- eas.as, eas.val);
+ len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix,
+ as2str(eas.as), eas.val);
str_pnt += len;
first = 0;
}
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 7b2564ad..107c399f 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* High-order octet of the Extended Communities type field. */
#define ECOMMUNITY_ENCODE_AS 0x00
#define ECOMMUNITY_ENCODE_IP 0x01
+#define ECOMMUNITY_ENCODE_AS4 0x02
/* Low-order octet of the Extended Communityes type field. */
#define ECOMMUNITY_ROUTE_TARGET 0x02
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index ac90f3c5..3b4f9c99 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_mplsvpn.h"
static u_int16_t
@@ -371,7 +372,7 @@ show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd)
vty_out (vty, "Route Distinguisher: ");
if (type == RD_TYPE_AS)
- vty_out (vty, "%d:%d", rd_as.as, rd_as.val);
+ vty_out (vty, "%s:%s", as2str(rd_as.as), as2str(rd_as.val));
else if (type == RD_TYPE_IP)
vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
@@ -478,7 +479,7 @@ bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type ty
vty_out (vty, "Route Distinguisher: ");
if (type == RD_TYPE_AS)
- vty_out (vty, "%d:%d", rd_as.as, rd_as.val);
+ vty_out (vty, "%s:%s", as2str(rd_as.as), as2str(rd_as.val));
else if (type == RD_TYPE_IP)
vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index e44bd2a0..841dcef8 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -33,6 +33,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_open.h"
+#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_vty.h"
/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
@@ -483,6 +484,40 @@ bgp_capability_parse (struct peer *peer, u_char *pnt, u_char length,
SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
}
+ else if (cap.code == CAPABILITY_CODE_AS4)
+ {
+ /* Check length */
+ if (cap.length != CAPABILITY_CODE_AS4_LEN)
+ {
+ zlog_info ("%s AS4 Capability length error %d",
+ peer->host, cap.length);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ return -1;
+ }
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s OPEN has AS4 capability", peer->host);
+
+ {
+ /*
+ * We did not make a "stream_getl" but read into
+ * the struct.
+ * Do the byte swivveling now
+ */
+ u_char *gotthis = (char *) &cap.mpc;
+ peer->as4cap = ((u_char) *gotthis++) << 24;
+ peer->as4cap |= ((u_char) *gotthis++) << 16;
+ peer->as4cap |= ((u_char) *gotthis++) << 8;
+ peer->as4cap |= ((u_char) *gotthis);
+ }
+
+ if (BGP_DEBUG (as4, AS4))
+ zlog_debug ("[AS4] %s about to set cap PEER_CAP_AS4_RCV at address %08x, value now %d, as4cap is %s", peer->host, &peer->cap, peer->cap,as2str(peer->as4cap));
+
+ SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
+
+ if (BGP_DEBUG (as4, AS4))
+ zlog_debug ("[AS4] %s set cap PEER_CAP_AS4_RCV at address %08x, value now %d", peer->host, &peer->cap, peer->cap);
+ }
else if (cap.code > 128)
{
@@ -525,6 +560,92 @@ strict_capability_same (struct peer *peer)
return 1;
}
+/* peek into option, set as4 value if it is there */
+void peek_for_as4_capability( struct peer *peer, u_char length )
+{
+ u_char *pnt;
+ u_char *end;
+ u_char opt_type;
+ u_char opt_length;
+ struct capability cap;
+
+ pnt = stream_pnt (peer->ibuf);
+ end = pnt + length;
+
+ if (BGP_DEBUG (as4, AS4))
+ zlog_debug ("[AS4] %s 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 (pnt < end)
+ {
+
+ /* Check the length. */
+ if (pnt + 2 > end)
+ return;
+
+ /* Fetch option type and length. */
+ opt_type = *pnt++;
+ opt_length = *pnt++;
+
+ /* Option length check. */
+ if (pnt + opt_length > end)
+ return;
+
+ if ( opt_type == BGP_OPEN_OPT_CAP )
+ {
+ u_char *mypnt = pnt;
+ u_char mylength = opt_length;
+ u_char *myend ;
+
+ myend = mypnt + mylength;
+ while (mypnt < myend)
+ {
+ afi_t afi;
+ safi_t safi;
+
+ /* Fetch structure to the byte stream. */
+ memcpy (&cap, mypnt, sizeof (struct capability));
+
+ afi = ntohs(cap.mpc.afi);
+ safi = cap.mpc.safi;
+
+ if (mypnt + 2 > myend)
+ return;
+ if (mypnt + (cap.length + 2) > myend)
+ return;
+
+ if (cap.code == CAPABILITY_CODE_AS4)
+ {
+ if (cap.length != CAPABILITY_CODE_AS4_LEN)
+ return;
+ if (BGP_DEBUG (as4, AS4))
+ zlog_debug ("[AS4] %s OPEN peeking found AS4 capability", peer->host);
+
+ {
+ /*
+ * We did not make a "stream_getl"
+ * Do the byte swivveling now
+ */
+ u_char *gotthis = (char *) &cap.mpc;
+ peer->as4cap = ((u_char) *gotthis++) << 24;
+ peer->as4cap |= ((u_char) *gotthis++) << 16;
+ peer->as4cap |= ((u_char) *gotthis++) << 8;
+ peer->as4cap |= ((u_char) *gotthis);
+
+ }
+ SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
+
+ }
+ mypnt += cap.length + 2;
+ }
+ }
+ pnt += opt_length;
+ }
+}
+
/* Parse open option */
int
bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
@@ -733,6 +854,7 @@ bgp_open_capability (struct stream *s, struct peer *peer)
unsigned long cp;
afi_t afi;
safi_t safi;
+ as_t local_as;
/* Remember current pointer for Opt Parm Len. */
cp = stream_get_endp (s);
@@ -819,6 +941,18 @@ bgp_open_capability (struct stream *s, struct peer *peer)
stream_putc (s, CAPABILITY_CODE_REFRESH);
stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
+ /* AS4 */
+ SET_FLAG (peer->cap, PEER_CAP_AS4_ADV);
+ stream_putc (s, BGP_OPEN_OPT_CAP);
+ stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2);
+ stream_putc (s, CAPABILITY_CODE_AS4);
+ stream_putc (s, CAPABILITY_CODE_AS4_LEN);
+ if ( peer->change_local_as )
+ local_as = peer->change_local_as;
+ else
+ local_as = peer->local_as;
+ stream_putl (s, local_as );
+
/* ORF capability. */
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index 7515d3f4..d30b676b 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -49,7 +49,7 @@ struct graceful_restart_af
#define CAPABILITY_CODE_REFRESH 2 /* Route Refresh Capability */
#define CAPABILITY_CODE_ORF 3 /* Cooperative Route Filtering Capability */
#define CAPABILITY_CODE_RESTART 64 /* Graceful Restart Capability */
-#define CAPABILITY_CODE_4BYTE_AS 65 /* 4-octet AS number Capability */
+#define CAPABILITY_CODE_AS4 65 /* 4-octet AS number Capability */
#define CAPABILITY_CODE_DYNAMIC 66 /* Dynamic Capability */
#define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */
#define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */
@@ -59,6 +59,7 @@ struct graceful_restart_af
#define CAPABILITY_CODE_REFRESH_LEN 0
#define CAPABILITY_CODE_DYNAMIC_LEN 0
#define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */
+#define CAPABILITY_CODE_AS4_LEN 4
/* Cooperative Route Filtering Capability. */
@@ -82,5 +83,6 @@ struct graceful_restart_af
extern int bgp_open_option_parse (struct peer *, u_char, int *);
extern void bgp_open_capability (struct stream *, struct peer *);
extern void bgp_capability_vty_out (struct vty *, struct peer *);
+extern void peek_for_as4_capability (struct peer *, u_char);
#endif /* _QUAGGA_BGP_OPEN_H */
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 9859e50b..e422af7a 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -804,7 +804,15 @@ bgp_open_send (struct peer *peer)
/* Set open packet values. */
stream_putc (s, BGP_VERSION_4); /* BGP version */
- stream_putw (s, local_as); /* My Autonomous System*/
+ if ( local_as <= BGP_AS_MAX )
+ /* fits in 16 bit, so send real as number in 16 bit */
+ stream_putw (s, (u_int16_t) local_as); /* My Autonomous System*/
+ else
+ /* does not fit in 16 bit, so as per */
+ /* draft_ietf_idr_as4bytes-13: */
+ /* AS_TRANS is put in the My Autonomous System field */
+ /* of the open message of a NEW BGP speaker */
+ stream_putw (s, BGP_AS_TRANS); /* My Autonomous System*/
stream_putw (s, send_holdtime); /* Hold Time */
stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */
@@ -815,8 +823,8 @@ bgp_open_send (struct peer *peer)
length = bgp_packet_set_size (s);
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s sending OPEN, version %d, my as %d, holdtime %d, id %s",
- peer->host, BGP_VERSION_4, local_as,
+ zlog_debug ("%s sending OPEN, version %d, my as %s, holdtime %d, id %s",
+ peer->host, BGP_VERSION_4, as2str(local_as),
send_holdtime, inet_ntoa (peer->local_id));
if (BGP_DEBUG (normal, NORMAL))
@@ -1184,12 +1192,73 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4);
remote_id.s_addr = stream_get_ipv4 (peer->ibuf);
+ /* BEGIN to read the capability here, but dont do it yet */
+ capability = 0;
+ optlen = stream_getc (peer->ibuf);
+ if (optlen != 0)
+ {
+ /* We got capabilities. Now, for simplicity, we always read
+ * them when we were through the basic things, i.e. at the end
+ * of this function.
+ * But 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.
+ *
+ * So, keep everything safe, and peek into the capabilites,
+ * and look just for as4!
+ */
+ peek_for_as4_capability( peer, optlen );
+ }
+
/* Receive OPEN message log */
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,
inet_ntoa (remote_id));
+ if ( remote_as == BGP_AS_TRANS )
+ {
+ if ( peer->as4cap > BGP_AS_MAX )
+ {
+ /* Take the AS4 from the capability.
+ * We must have received the capability now!
+ * Otherwise we have a asn16 peer who uses BGP_AS_TRANS,
+ * which we will not tolerate
+ */
+
+ if ( !CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
+ {
+ /* raise error, log this, close session */
+ zlog_err ("%s bad OPEN, got AS_TRANS but no AS4 capability address peer->cap is %08x, value %d",
+ peer->host, (u_int32_t) &peer->cap, peer->cap);
+ /* which error to notify? well, use something generic,
+ * our log has the right reason
+ */
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONNECT_REJECT);
+ return -1;
+ }
+ else
+ remote_as = peer->as4cap;
+ }
+ } 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) &&
+ peer->as4cap != 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, peer->as4cap, remote_as);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONNECT_REJECT);
+ /* which error to notify? well, use something generic,
+ * our log has the right reason
+ */
+ return -1;
+ }
+ }
+
/* Lookup peer from Open packet. */
if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
{
@@ -1214,8 +1283,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
else
{
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, remote AS is %d, expected %d",
- peer->host, remote_as, peer->as);
+ zlog_debug ("%s bad OPEN, remote AS is %s, expected %s",
+ peer->host, as2str(remote_as), as2str(peer->as));
bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_PEER_AS,
notify_data_remote_as, 2);
@@ -1322,8 +1391,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
if (remote_as != peer->as)
{
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, remote AS is %d, expected %d",
- peer->host, remote_as, peer->as);
+ zlog_debug ("%s bad OPEN, remote AS is %s, expected %s",
+ peer->host, as2str(remote_as), as2str(peer->as));
bgp_notify_send_with_data (peer,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_PEER_AS,
@@ -1364,8 +1433,6 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
peer->v_keepalive = peer->v_holdtime / 3;
/* Open option part parse. */
- capability = 0;
- optlen = stream_getc (peer->ibuf);
if (optlen != 0)
{
ret = bgp_open_option_parse (peer, optlen, &capability);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index c464cd04..041abd87 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -5499,7 +5499,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE))
vty_out (vty, ", (stale)");
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)))
- vty_out (vty, ", (aggregated by %d %s)", attr->aggregator_as,
+ vty_out (vty, ", (aggregated by %s %s)", as2str(attr->aggregator_as),
inet_ntoa (attr->aggregator_addr));
if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
vty_out (vty, ", (Received from a RR-client)");
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 806a5072..a0f8eff4 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1636,7 +1636,7 @@ route_set_aggregator_as_compile (const char *arg)
sscanf (arg, "%s %s", as, address);
- aggregator->as = strtoul (as, NULL, 10);
+ aggregator->as = str2asnum (as, NULL);
inet_aton (address, &aggregator->address);
return aggregator;
@@ -3234,7 +3234,7 @@ DEFUN (no_set_atomic_aggregate,
DEFUN (set_aggregator_as,
set_aggregator_as_cmd,
- "set aggregator as <1-65535> A.B.C.D",
+ "set aggregator as ASNUMBER A.B.C.D",
SET_STR
"BGP aggregator attribute\n"
"AS number of aggregator\n"
@@ -3246,7 +3246,14 @@ DEFUN (set_aggregator_as,
struct in_addr address;
char *argstr;
- VTY_GET_INTEGER_RANGE ("AS Path", as, argv[0], 1, BGP_AS_MAX);
+ as = str2asnum( argv[0], NULL );
+ if ( !as )
+ {
+ vty_out (vty, "%s is not a valid as number.%s",
+ argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
ret = inet_aton (argv[1], &address);
if (ret == 0)
@@ -3283,7 +3290,13 @@ DEFUN (no_set_aggregator_as,
if (argv == 0)
return bgp_route_set_delete (vty, vty->index, "aggregator as", NULL);
- VTY_GET_INTEGER_RANGE ("AS Path", as, argv[0], 1, BGP_AS_MAX);
+ as = str2asnum( argv[0], NULL );
+ if ( !as ) {
+ vty_out (vty, "%s is not a valid as number.%s",
+ argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
ret = inet_aton (argv[1], &address);
if (ret == 0)
@@ -3306,7 +3319,7 @@ DEFUN (no_set_aggregator_as,
ALIAS (no_set_aggregator_as,
no_set_aggregator_as_val_cmd,
- "no set aggregator as <1-65535> A.B.C.D",
+ "no set aggregator as ASNUMBER A.B.C.D",
NO_STR
SET_STR
"BGP aggregator attribute\n"
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index b108164f..e8f1fcdf 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -265,6 +265,56 @@ DEFUN (bgp_config_type,
return CMD_SUCCESS;
}
+DEFUN (bgp_asnum_output_format,
+ bgp_asnum_output_format_cmd,
+ "bgp asnum format (asdot|asdot+|asip|asplain)",
+ BGP_STR
+ "ASnumber format\n"
+ "Set ASnumber output format\n"
+ "[<16bitdecimal>.]<16bitdecimal>\n"
+ "<16bitdecimal>.<16bitdecimal>\n"
+ "<8bitdecimal>.<8bitdecimal>.<8bitdecimal>.<8bitdecimal>\n"
+ "<32bitdecimal>\n"
+ )
+{
+ int lastasnumberformat, newasnumberformat;
+
+ lastasnumberformat = get_asnumber_format();
+
+ if (strcmp (argv[0], "asdot+") == 0)
+ newasnumberformat = BGP_ASNUMBER_FORMAT_ASDOTPLUS;
+ else if (strcmp (argv[0], "asdot") == 0)
+ newasnumberformat = BGP_ASNUMBER_FORMAT_ASDOT;
+ else if (strcmp (argv[0], "asplain") == 0)
+ newasnumberformat = BGP_ASNUMBER_FORMAT_ASPLAIN;
+ else if (strcmp (argv[0], "asip") == 0)
+ newasnumberformat = BGP_ASNUMBER_FORMAT_ASIP;
+ else
+ {
+ vty_out (vty, "%% %s is no valid asnumber format%s", argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ setasnumber_format( newasnumberformat );
+ if ( lastasnumberformat != newasnumberformat )
+ {
+ /*
+ * This is new. Maybe I annoy people by this, but maybe I also
+ * save someone from doing something foolish or having no clue about
+ * what happens. JK
+ */
+ vty_out (vty, "%% WARNING: Change of asnumber format.%s", VTY_NEWLINE );
+ vty_out (vty, "%% Newly learned aspaths will now be formatted in %s%s", argv[0], VTY_NEWLINE);
+ vty_out (vty, "%% You have to *hard-reset* your bgp sessions to get a consistent aspath format%s", VTY_NEWLINE);
+ vty_out (vty, "%% on this system. Only that way you ensure re-evaluation of all bgp%s", VTY_NEWLINE );
+ vty_out( vty, "%% aspath access-lists you may have in use.%s", VTY_NEWLINE);
+ vty_out( vty, "%% Remember that aspath access-lists depend on the asnumber format!%s", VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (no_bgp_config_type,
no_bgp_config_type_cmd,
"no bgp config-type",
@@ -308,17 +358,24 @@ DEFUN_DEPRECATED (neighbor_version,
/* "router bgp" commands. */
DEFUN (router_bgp,
router_bgp_cmd,
- "router bgp <1-65535>",
+ "router bgp ASNUMBER",
ROUTER_STR
BGP_STR
- AS_STR)
+ AS_STR
+ )
{
int ret;
as_t as;
struct bgp *bgp;
const char *name = NULL;
- VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535);
+ as = str2asnum( argv[0], NULL );
+ if ( !as ) {
+ vty_out (vty, "%s is not a valid as number.%s",
+ argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
if (argc == 2)
name = argv[1];
@@ -331,12 +388,12 @@ DEFUN (router_bgp,
VTY_NEWLINE);
return CMD_WARNING;
case BGP_ERR_AS_MISMATCH:
- vty_out (vty, "BGP is already running; AS is %d%s", as, VTY_NEWLINE);
+ vty_out (vty, "BGP is already running; AS is %s%s", as2str(as), VTY_NEWLINE);
return CMD_WARNING;
case BGP_ERR_INSTANCE_MISMATCH:
vty_out (vty, "BGP view name and AS number mismatch%s", VTY_NEWLINE);
- vty_out (vty, "BGP instance is already running; AS is %d%s",
- as, VTY_NEWLINE);
+ vty_out (vty, "BGP instance is already running; AS is %s%s",
+ as2str(as), VTY_NEWLINE);
return CMD_WARNING;
}
@@ -348,7 +405,7 @@ DEFUN (router_bgp,
ALIAS (router_bgp,
router_bgp_view_cmd,
- "router bgp <1-65535> view WORD",
+ "router bgp ASNUMBER view WORD",
ROUTER_STR
BGP_STR
AS_STR
@@ -358,7 +415,7 @@ ALIAS (router_bgp,
/* "no router bgp" commands. */
DEFUN (no_router_bgp,
no_router_bgp_cmd,
- "no router bgp <1-65535>",
+ "no router bgp ASNUMBER",
NO_STR
ROUTER_STR
BGP_STR
@@ -368,7 +425,13 @@ DEFUN (no_router_bgp,
struct bgp *bgp;
const char *name = NULL;
- VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535);
+ as = str2asnum( argv[0], NULL );
+ if ( !as ) {
+ vty_out (vty, "%s is not a valid as number.%s",
+ argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
if (argc == 2)
name = argv[1];
@@ -388,7 +451,7 @@ DEFUN (no_router_bgp,
ALIAS (no_router_bgp,
no_router_bgp_view_cmd,
- "no router bgp <1-65535> view WORD",
+ "no router bgp ASNUMBER view WORD",
NO_STR
ROUTER_STR
BGP_STR
@@ -539,7 +602,7 @@ ALIAS (no_bgp_cluster_id,
DEFUN (bgp_confederation_identifier,
bgp_confederation_identifier_cmd,
- "bgp confederation identifier <1-65535>",
+ "bgp confederation identifier ASNUMBER",
"BGP specific commands\n"
"AS confederation parameters\n"
"AS number\n"
@@ -550,7 +613,13 @@ DEFUN (bgp_confederation_identifier,
bgp = vty->index;
- VTY_GET_INTEGER ("AS", as, argv[0]);
+ as = str2asnum( argv[0], NULL );
+ if ( !as ) {
+ vty_out (vty, "%s is not a valid as number.%s",
+ argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
bgp_confederation_id_set (bgp, as);
@@ -570,8 +639,13 @@ DEFUN (no_bgp_confederation_identifier,
bgp = vty->index;
- if (argc == 1)
- VTY_GET_INTEGER ("AS", as, argv[0]);
+ as = str2asnum( argv[0], NULL );
+ if ( !as ) {
+ vty_out (vty, "%s is not a valid as number.%s",
+ argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
bgp_confederation_id_unset (bgp);
@@ -580,7 +654,7 @@ DEFUN (no_bgp_confederation_identifier,
ALIAS (no_bgp_confederation_identifier,
no_bgp_confederation_identifier_arg_cmd,
- "no bgp confederation identifier <1-65535>",
+ "no bgp confederation identifier ASNUMBER",
NO_STR
"BGP specific commands\n"
"AS confederation parameters\n"
@@ -589,7 +663,7 @@ ALIAS (no_bgp_confederation_identifier,
DEFUN (bgp_confederation_peers,
bgp_confederation_peers_cmd,
- "bgp confederation peers .<1-65535>",
+ "bgp confederation peers . ASNUMBER",
"BGP specific commands\n"
"AS confederation parameters\n"
"Peer ASs in BGP confederation\n"
@@ -603,7 +677,13 @@ DEFUN (bgp_confederation_peers,
for (i = 0; i < argc; i++)
{
- VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535);
+ as = str2asnum( argv[i], NULL );
+ if ( !as ) {
+ vty_out (vty, "%s is not a valid as number.%s",
+ argv[i],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
if (bgp->as == as)
{
@@ -619,7 +699,7 @@ DEFUN (bgp_confederation_peers,
DEFUN (no_bgp_confederation_peers,
no_bgp_confederation_peers_cmd,
- "no bgp confederation peers .<1-65535>",
+ "no bgp confederation peers . ASNUMBER",
NO_STR
"BGP specific commands\n"
"AS confederation parameters\n"
@@ -634,7 +714,13 @@ DEFUN (no_bgp_confederation_peers,
for (i = 0; i < argc; i++)
{
- VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535);
+ as = str2asnum( argv[i], NULL );
+ if ( !as ) {
+ vty_out (vty, "%s is not a valid as number.%s",
+ argv[i],
+ VTY_NEWLINE);
+ continue;
+ }
bgp_confederation_peers_remove (bgp, as);
}
@@ -1249,7 +1335,13 @@ peer_remote_as_vty (struct vty *vty, const char *peer_str,
bgp = vty->index;
/* Get AS number. */
- VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, 65535);
+ as = str2asnum( as_str, NULL );
+ if ( !as ) {
+ vty_out (vty, "%s is not a valid as number.%s",
+ as_str,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
/* If peer is peer group, call proper function. */
ret = str2sockunion (peer_str, &su);
@@ -1277,10 +1369,10 @@ peer_remote_as_vty (struct vty *vty, const char *peer_str,
switch (ret)
{
case BGP_ERR_PEER_GROUP_MEMBER:
- vty_out (vty, "%% Peer-group AS %d. Cannot configure remote-as for member%s", as, VTY_NEWLINE);
+ vty_out (vty, "%% Peer-group AS %s. Cannot configure remote-as for member%s", as2str(as), VTY_NEWLINE);
return CMD_WARNING;
case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT:
- vty_out (vty, "%% The AS# can not be changed from %d to %s, peer-group members must be all internal or all external%s", as, as_str, VTY_NEWLINE);
+ vty_out (vty, "%% The AS# can not be changed from %s to %s, peer-group members must be all internal or all external%s", as2str(as), as_str, VTY_NEWLINE);
return CMD_WARNING;
}
return bgp_vty_return (vty, ret);
@@ -1288,7 +1380,7 @@ peer_remote_as_vty (struct vty *vty, const char *peer_str,
DEFUN (neighbor_remote_as,
neighbor_remote_as_cmd,
- NEIGHBOR_CMD2 "remote-as <1-65535>",
+ NEIGHBOR_CMD2 "remote-as ASNUMBER",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a BGP neighbor\n"
@@ -1352,7 +1444,7 @@ DEFUN (no_neighbor,
ALIAS (no_neighbor,
no_neighbor_remote_as_cmd,
- NO_NEIGHBOR_CMD "remote-as <1-65535>",
+ NO_NEIGHBOR_CMD "remote-as ASNUMBER",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR
@@ -1382,7 +1474,7 @@ DEFUN (no_neighbor_peer_group,
DEFUN (no_neighbor_peer_group_remote_as,
no_neighbor_peer_group_remote_as_cmd,
- "no neighbor WORD remote-as <1-65535>",
+ "no neighbor WORD remote-as ASNUMBER",
NO_STR
NEIGHBOR_STR
"Neighbor tag\n"
@@ -1404,7 +1496,7 @@ DEFUN (no_neighbor_peer_group_remote_as,
DEFUN (neighbor_local_as,
neighbor_local_as_cmd,
- NEIGHBOR_CMD2 "local-as <1-65535>",
+ NEIGHBOR_CMD2 "local-as ASNUMBER",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
@@ -1417,13 +1509,13 @@ DEFUN (neighbor_local_as,
if (! peer)
return CMD_WARNING;
- ret = peer_local_as_set (peer, atoi (argv[1]), 0);
+ ret = peer_local_as_set (peer, str2asnum(argv[1], NULL), 0);
return bgp_vty_return (vty, ret);
}
DEFUN (neighbor_local_as_no_prepend,
neighbor_local_as_no_prepend_cmd,
- NEIGHBOR_CMD2 "local-as <1-65535> no-prepend",
+ NEIGHBOR_CMD2 "local-as ASNUMBER no-prepend",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
@@ -1437,7 +1529,7 @@ DEFUN (neighbor_local_as_no_prepend,
if (! peer)
return CMD_WARNING;
- ret = peer_local_as_set (peer, atoi (argv[1]), 1);
+ ret = peer_local_as_set (peer, str2asnum (argv[1], NULL), 1);
return bgp_vty_return (vty, ret);
}
@@ -1462,7 +1554,7 @@ DEFUN (no_neighbor_local_as,
ALIAS (no_neighbor_local_as,
no_neighbor_local_as_val_cmd,
- NO_NEIGHBOR_CMD2 "local-as <1-65535>",
+ NO_NEIGHBOR_CMD2 "local-as ASNUMBER",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
@@ -1471,7 +1563,7 @@ ALIAS (no_neighbor_local_as,
ALIAS (no_neighbor_local_as,
no_neighbor_local_as_val2_cmd,
- NO_NEIGHBOR_CMD2 "local-as <1-65535> no-prepend",
+ NO_NEIGHBOR_CMD2 "local-as ASNUMBER no-prepend",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
@@ -4124,12 +4216,11 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
{
as_t as;
unsigned long as_ul;
- char *endptr = NULL;
int find = 0;
- as_ul = strtoul(arg, &endptr, 10);
+ as_ul = str2asnum(arg, NULL);
- if ((as_ul == ULONG_MAX) || (*endptr != '\0') || (as_ul > USHRT_MAX))
+ if (!as_ul)
{
vty_out (vty, "Invalid AS number%s", VTY_NEWLINE);
return -1;
@@ -4328,7 +4419,7 @@ ALIAS (clear_ip_bgp_external,
DEFUN (clear_ip_bgp_as,
clear_ip_bgp_as_cmd,
- "clear ip bgp <1-65535>",
+ "clear ip bgp ASNUMBER",
CLEAR_STR
IP_STR
BGP_STR
@@ -4339,14 +4430,14 @@ DEFUN (clear_ip_bgp_as,
ALIAS (clear_ip_bgp_as,
clear_bgp_as_cmd,
- "clear bgp <1-65535>",
+ "clear bgp ASNUMBER",
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n")
ALIAS (clear_ip_bgp_as,
clear_bgp_ipv6_as_cmd,
- "clear bgp ipv6 <1-65535>",
+ "clear bgp ipv6 ASNUMBER",
CLEAR_STR
BGP_STR
"Address family\n"
@@ -4858,7 +4949,7 @@ ALIAS (clear_bgp_external_soft_out,
DEFUN (clear_ip_bgp_as_soft_out,
clear_ip_bgp_as_soft_out_cmd,
- "clear ip bgp <1-65535> soft out",
+ "clear ip bgp ASNUMBER soft out",
CLEAR_STR
IP_STR
BGP_STR
@@ -4872,7 +4963,7 @@ DEFUN (clear_ip_bgp_as_soft_out,
ALIAS (clear_ip_bgp_as_soft_out,
clear_ip_bgp_as_out_cmd,
- "clear ip bgp <1-65535> out",
+ "clear ip bgp ASNUMBER out",
CLEAR_STR
IP_STR
BGP_STR
@@ -4881,7 +4972,7 @@ ALIAS (clear_ip_bgp_as_soft_out,
DEFUN (clear_ip_bgp_as_ipv4_soft_out,
clear_ip_bgp_as_ipv4_soft_out_cmd,
- "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft out",
+ "clear ip bgp ASNUMBER ipv4 (unicast|multicast) soft out",
CLEAR_STR
IP_STR
BGP_STR
@@ -4902,7 +4993,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_out,
ALIAS (clear_ip_bgp_as_ipv4_soft_out,
clear_ip_bgp_as_ipv4_out_cmd,
- "clear ip bgp <1-65535> ipv4 (unicast|multicast) out",
+ "clear ip bgp ASNUMBER ipv4 (unicast|multicast) out",
CLEAR_STR
IP_STR
BGP_STR
@@ -4914,7 +5005,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_out,
DEFUN (clear_ip_bgp_as_vpnv4_soft_out,
clear_ip_bgp_as_vpnv4_soft_out_cmd,
- "clear ip bgp <1-65535> vpnv4 unicast soft out",
+ "clear ip bgp ASNUMBER vpnv4 unicast soft out",
CLEAR_STR
IP_STR
BGP_STR
@@ -4930,7 +5021,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_out,
ALIAS (clear_ip_bgp_as_vpnv4_soft_out,
clear_ip_bgp_as_vpnv4_out_cmd,
- "clear ip bgp <1-65535> vpnv4 unicast out",
+ "clear ip bgp ASNUMBER vpnv4 unicast out",
CLEAR_STR
IP_STR
BGP_STR
@@ -4941,7 +5032,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_out,
DEFUN (clear_bgp_as_soft_out,
clear_bgp_as_soft_out_cmd,
- "clear bgp <1-65535> soft out",
+ "clear bgp ASNUMBER soft out",
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
@@ -4954,7 +5045,7 @@ DEFUN (clear_bgp_as_soft_out,
ALIAS (clear_bgp_as_soft_out,
clear_bgp_ipv6_as_soft_out_cmd,
- "clear bgp ipv6 <1-65535> soft out",
+ "clear bgp ipv6 ASNUMBER soft out",
CLEAR_STR
BGP_STR
"Address family\n"
@@ -4964,7 +5055,7 @@ ALIAS (clear_bgp_as_soft_out,
ALIAS (clear_bgp_as_soft_out,
clear_bgp_as_out_cmd,
- "clear bgp <1-65535> out",
+ "clear bgp ASNUMBER out",
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
@@ -4972,7 +5063,7 @@ ALIAS (clear_bgp_as_soft_out,
ALIAS (clear_bgp_as_soft_out,
clear_bgp_ipv6_as_out_cmd,
- "clear bgp ipv6 <1-65535> out",
+ "clear bgp ipv6 ASNUMBER out",
CLEAR_STR
BGP_STR
"Address family\n"
@@ -5762,7 +5853,7 @@ ALIAS (clear_bgp_external_in_prefix_filter,
DEFUN (clear_ip_bgp_as_soft_in,
clear_ip_bgp_as_soft_in_cmd,
- "clear ip bgp <1-65535> soft in",
+ "clear ip bgp ASNUMBER soft in",
CLEAR_STR
IP_STR
BGP_STR
@@ -5776,7 +5867,7 @@ DEFUN (clear_ip_bgp_as_soft_in,
ALIAS (clear_ip_bgp_as_soft_in,
clear_ip_bgp_as_in_cmd,
- "clear ip bgp <1-65535> in",
+ "clear ip bgp ASNUMBER in",
CLEAR_STR
IP_STR
BGP_STR
@@ -5785,7 +5876,7 @@ ALIAS (clear_ip_bgp_as_soft_in,
DEFUN (clear_ip_bgp_as_in_prefix_filter,
clear_ip_bgp_as_in_prefix_filter_cmd,
- "clear ip bgp <1-65535> in prefix-filter",
+ "clear ip bgp ASNUMBER in prefix-filter",
CLEAR_STR
IP_STR
BGP_STR
@@ -5799,7 +5890,7 @@ DEFUN (clear_ip_bgp_as_in_prefix_filter,
DEFUN (clear_ip_bgp_as_ipv4_soft_in,
clear_ip_bgp_as_ipv4_soft_in_cmd,
- "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft in",
+ "clear ip bgp ASNUMBER ipv4 (unicast|multicast) soft in",
CLEAR_STR
IP_STR
BGP_STR
@@ -5820,7 +5911,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_in,
ALIAS (clear_ip_bgp_as_ipv4_soft_in,
clear_ip_bgp_as_ipv4_in_cmd,
- "clear ip bgp <1-65535> ipv4 (unicast|multicast) in",
+ "clear ip bgp ASNUMBER ipv4 (unicast|multicast) in",
CLEAR_STR
IP_STR
BGP_STR
@@ -5832,7 +5923,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_in,
DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter,
clear_ip_bgp_as_ipv4_in_prefix_filter_cmd,
- "clear ip bgp <1-65535> ipv4 (unicast|multicast) in prefix-filter",
+ "clear ip bgp ASNUMBER ipv4 (unicast|multicast) in prefix-filter",
CLEAR_STR
IP_STR
BGP_STR
@@ -5853,7 +5944,7 @@ DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter,
DEFUN (clear_ip_bgp_as_vpnv4_soft_in,
clear_ip_bgp_as_vpnv4_soft_in_cmd,
- "clear ip bgp <1-65535> vpnv4 unicast soft in",
+ "clear ip bgp ASNUMBER vpnv4 unicast soft in",
CLEAR_STR
IP_STR
BGP_STR
@@ -5869,7 +5960,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_in,
ALIAS (clear_ip_bgp_as_vpnv4_soft_in,
clear_ip_bgp_as_vpnv4_in_cmd,
- "clear ip bgp <1-65535> vpnv4 unicast in",
+ "clear ip bgp ASNUMBER vpnv4 unicast in",
CLEAR_STR
IP_STR
BGP_STR
@@ -5880,7 +5971,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_in,
DEFUN (clear_bgp_as_soft_in,
clear_bgp_as_soft_in_cmd,
- "clear bgp <1-65535> soft in",
+ "clear bgp ASNUMBER soft in",
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
@@ -5893,7 +5984,7 @@ DEFUN (clear_bgp_as_soft_in,
ALIAS (clear_bgp_as_soft_in,
clear_bgp_ipv6_as_soft_in_cmd,
- "clear bgp ipv6 <1-65535> soft in",
+ "clear bgp ipv6 ASNUMBER soft in",
CLEAR_STR
BGP_STR
"Address family\n"
@@ -5903,7 +5994,7 @@ ALIAS (clear_bgp_as_soft_in,
ALIAS (clear_bgp_as_soft_in,
clear_bgp_as_in_cmd,
- "clear bgp <1-65535> in",
+ "clear bgp ASNUMBER in",
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
@@ -5911,7 +6002,7 @@ ALIAS (clear_bgp_as_soft_in,
ALIAS (clear_bgp_as_soft_in,
clear_bgp_ipv6_as_in_cmd,
- "clear bgp ipv6 <1-65535> in",
+ "clear bgp ipv6 ASNUMBER in",
CLEAR_STR
BGP_STR
"Address family\n"
@@ -5920,7 +6011,7 @@ ALIAS (clear_bgp_as_soft_in,
DEFUN (clear_bgp_as_in_prefix_filter,
clear_bgp_as_in_prefix_filter_cmd,
- "clear bgp <1-65535> in prefix-filter",
+ "clear bgp ASNUMBER in prefix-filter",
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
@@ -5933,7 +6024,7 @@ DEFUN (clear_bgp_as_in_prefix_filter,
ALIAS (clear_bgp_as_in_prefix_filter,
clear_bgp_ipv6_as_in_prefix_filter_cmd,
- "clear bgp ipv6 <1-65535> in prefix-filter",
+ "clear bgp ipv6 ASNUMBER in prefix-filter",
CLEAR_STR
BGP_STR
"Address family\n"
@@ -6248,7 +6339,7 @@ ALIAS (clear_bgp_external_soft,
DEFUN (clear_ip_bgp_as_soft,
clear_ip_bgp_as_soft_cmd,
- "clear ip bgp <1-65535> soft",
+ "clear ip bgp ASNUMBER soft",
CLEAR_STR
IP_STR
BGP_STR
@@ -6261,7 +6352,7 @@ DEFUN (clear_ip_bgp_as_soft,
DEFUN (clear_ip_bgp_as_ipv4_soft,
clear_ip_bgp_as_ipv4_soft_cmd,
- "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft",
+ "clear ip bgp ASNUMBER ipv4 (unicast|multicast) soft",
CLEAR_STR
IP_STR
BGP_STR
@@ -6281,7 +6372,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft,
DEFUN (clear_ip_bgp_as_vpnv4_soft,
clear_ip_bgp_as_vpnv4_soft_cmd,
- "clear ip bgp <1-65535> vpnv4 unicast soft",
+ "clear ip bgp ASNUMBER vpnv4 unicast soft",
CLEAR_STR
IP_STR
BGP_STR
@@ -6296,7 +6387,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft,
DEFUN (clear_bgp_as_soft,
clear_bgp_as_soft_cmd,
- "clear bgp <1-65535> soft",
+ "clear bgp ASNUMBER soft",
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
@@ -6308,7 +6399,7 @@ DEFUN (clear_bgp_as_soft,
ALIAS (clear_bgp_as_soft,
clear_bgp_ipv6_as_soft_cmd,
- "clear bgp ipv6 <1-65535> soft",
+ "clear bgp ipv6 ASNUMBER soft",
CLEAR_STR
BGP_STR
"Address family\n"
@@ -6609,6 +6700,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
unsigned int count = 0;
char timebuf[BGP_UPTIME_LEN];
int len;
+ char *asstring;
/* Header string for each address family. */
static char header[] = "Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd";
@@ -6624,8 +6716,8 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
/* Usage summary and header */
vty_out (vty,
- "BGP router identifier %s, local AS number %d%s",
- inet_ntoa (bgp->router_id), bgp->as, VTY_NEWLINE);
+ "BGP router identifier %s, local AS number %s%s",
+ inet_ntoa (bgp->router_id), as2str(bgp->as), VTY_NEWLINE);
ents = bgp_table_count (bgp->rib[afi][safi]);
vty_out (vty, "RIB entries %ld, using %s of memory%s", ents,
@@ -6671,8 +6763,20 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
vty_out (vty, "4 ");
- vty_out (vty, "%5d %7d %7d %8d %4d %4ld ",
- peer->as,
+ asstring = as2str(peer->as);
+ if ( strlen(asstring) <= 5 )
+ vty_out (vty, "%5s %7d %7d %8d %4d %4ld ",
+ asstring,
+ peer->open_in + peer->update_in + peer->keepalive_in
+ + peer->notify_in + peer->refresh_in + peer->dynamic_cap_in,
+ peer->open_out + peer->update_out + peer->keepalive_out
+ + peer->notify_out + peer->refresh_out
+ + peer->dynamic_cap_out,
+ 0, 0, peer->obuf->count);
+ else
+ vty_out (vty, "%s%*s%11s %7d %7d %8d %4d %4ld ",
+ VTY_NEWLINE, 12, " ",
+ asstring,
peer->open_in + peer->update_in + peer->keepalive_in
+ peer->notify_in + peer->refresh_in + peer->dynamic_cap_in,
peer->open_out + peer->update_out + peer->keepalive_out
@@ -7181,9 +7285,9 @@ bgp_show_peer (struct vty *vty, struct peer *p)
/* Configured IP address. */
vty_out (vty, "BGP neighbor is %s, ", p->host);
- vty_out (vty, "remote AS %d, ", p->as);
- vty_out (vty, "local AS %d%s, ",
- p->change_local_as ? p->change_local_as : p->local_as,
+ vty_out (vty, "remote AS %s, ", as2str(p->as));
+ vty_out (vty, "local AS %s%s, ",
+ as2str(p->change_local_as ? p->change_local_as : p->local_as),
CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ?
" no-prepend" : "");
vty_out (vty, "%s link%s",
@@ -7261,6 +7365,18 @@ bgp_show_peer (struct vty *vty, struct peer *p)
{
vty_out (vty, " Neighbor capabilities:%s", VTY_NEWLINE);
+ /* AS4 */
+ if (CHECK_FLAG (p->cap, PEER_CAP_AS4_RCV)
+ || CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV))
+ {
+ vty_out (vty, " 4 Byte AS:");
+ if (CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV))
+ vty_out (vty, " advertised");
+ if (CHECK_FLAG (p->cap, PEER_CAP_AS4_RCV))
+ vty_out (vty, " %sreceived",
+ CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV) ? "and " : "");
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
/* Dynamic */
if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV)
|| CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV))
@@ -7897,7 +8013,7 @@ bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient,
vty_out (vty, "4 ");
- vty_out (vty, "%5d ", rsclient->as);
+ vty_out (vty, "%11s ", as2str(rsclient->as));
rmname = ROUTE_MAP_EXPORT_NAME(&rsclient->filter[afi][safi]);
if ( rmname && strlen (rmname) > 13 )
@@ -8766,6 +8882,9 @@ bgp_vty_init (void)
install_element (CONFIG_NODE, &bgp_config_type_cmd);
install_element (CONFIG_NODE, &no_bgp_config_type_cmd);
+ /* asnumber output format */
+ install_element (CONFIG_NODE, &bgp_asnum_output_format_cmd);
+
/* Dummy commands (Currently not supported) */
install_element (BGP_NODE, &no_synchronization_cmd);
install_element (BGP_NODE, &no_auto_summary_cmd);
@@ -10283,7 +10402,7 @@ extcommunity_list_unset_vty (struct vty *vty, int argc, const char **argv,
/* "extcommunity-list" keyword help string. */
#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"
-#define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n"
+#define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt \\+?ASN_or_IPaddr:nn' OR 'soo \\+?ASN_or_IPaddr:nn' format\n"
DEFUN (ip_extcommunity_list_standard,
ip_extcommunity_list_standard_cmd,
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 3f841078..4b6df2dd 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2104,10 +2104,20 @@ peer_lookup_with_open (union sockunion *su, as_t remote_as,
if (sockunion_same (&peer->su, su)
&& ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
{
- if (peer->as == remote_as
+ if ( (peer->as == remote_as
+ || (peer->as == BGP_AS_TRANS &&
+ peer->as4cap == remote_as &&
+ CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
+ )
&& peer->remote_id.s_addr == remote_id->s_addr)
return peer;
- if (peer->as == remote_as)
+ if ( (peer->as == remote_as
+ || (peer->as == BGP_AS_TRANS &&
+ peer->as4cap == remote_as &&
+ CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
+
+ )
+ )
*as = 1;
}
}
@@ -2116,10 +2126,18 @@ peer_lookup_with_open (union sockunion *su, as_t remote_as,
if (sockunion_same (&peer->su, su)
&& ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
{
- if (peer->as == remote_as
+ if ( ( peer->as == remote_as
+ || (peer->as == BGP_AS_TRANS &&
+ peer->as4cap == remote_as &&
+ CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
+ )
&& peer->remote_id.s_addr == 0)
return peer;
- if (peer->as == remote_as)
+ if ( peer->as == remote_as
+ || (peer->as == BGP_AS_TRANS &&
+ peer->as4cap == remote_as &&
+ CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
+ )
*as = 1;
}
}
@@ -4384,13 +4402,13 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
vty_out (vty, " neighbor %s peer-group%s", addr,
VTY_NEWLINE);
if (peer->as)
- vty_out (vty, " neighbor %s remote-as %d%s", addr, peer->as,
+ vty_out (vty, " neighbor %s remote-as %s%s", addr, as2str(peer->as),
VTY_NEWLINE);
}
else
{
if (! g_peer->as)
- vty_out (vty, " neighbor %s remote-as %d%s", addr, peer->as,
+ vty_out (vty, " neighbor %s remote-as %s%s", addr, as2str(peer->as),
VTY_NEWLINE);
if (peer->af_group[AFI_IP][SAFI_UNICAST])
vty_out (vty, " neighbor %s peer-group %s%s", addr,
@@ -4400,8 +4418,8 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
/* local-as. */
if (peer->change_local_as)
if (! peer_group_active (peer))
- vty_out (vty, " neighbor %s local-as %d%s%s", addr,
- peer->change_local_as,
+ vty_out (vty, " neighbor %s local-as %s%s%s", addr,
+ as2str(peer->change_local_as),
CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ?
" no-prepend" : "", VTY_NEWLINE);
@@ -4769,6 +4787,34 @@ bgp_config_write (struct vty *vty)
write++;
}
+ {
+ /* Sigh. Wish we would not have had to do this....
+ */
+ int asnumber_format = get_asnumber_format();
+ if (asnumber_format != BGP_ASNUMBER_FORMAT_DEFAULT)
+ {
+ switch ( asnumber_format )
+ {
+ case BGP_ASNUMBER_FORMAT_ASDOT:
+ vty_out (vty, "bgp asnumber format asdot%s", VTY_NEWLINE);
+ write++;
+ break;
+ case BGP_ASNUMBER_FORMAT_ASDOTPLUS:
+ vty_out (vty, "bgp asnumber format asdot+%s", VTY_NEWLINE);
+ write++;
+ break;
+ case BGP_ASNUMBER_FORMAT_ASPLAIN:
+ vty_out (vty, "bgp asnumber format asplain%s", VTY_NEWLINE);
+ write++;
+ break;
+ case BGP_ASNUMBER_FORMAT_ASIP:
+ vty_out (vty, "bgp asnumber format asip%s", VTY_NEWLINE);
+ write++;
+ break;
+ }
+ }
+ }
+
/* BGP configuration. */
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
{
@@ -4776,7 +4822,7 @@ bgp_config_write (struct vty *vty)
vty_out (vty, "!%s", VTY_NEWLINE);
/* Router bgp ASN */
- vty_out (vty, "router bgp %d", bgp->as);
+ vty_out (vty, "router bgp %s", as2str(bgp->as) );
if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE))
{
@@ -4826,7 +4872,8 @@ bgp_config_write (struct vty *vty)
/* Confederation identifier*/
if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
- vty_out (vty, " bgp confederation identifier %i%s", bgp->confed_id,
+ vty_out (vty, " bgp confederation identifier %s%s",
+ as2str(bgp->confed_id),
VTY_NEWLINE);
/* Confederation peer */
@@ -4837,7 +4884,7 @@ bgp_config_write (struct vty *vty)
vty_out (vty, " bgp confederation peers");
for (i = 0; i < bgp->confed_peers_cnt; i++)
- vty_out(vty, " %d", bgp->confed_peers[i]);
+ vty_out(vty, " %s", as2str(bgp->confed_peers[i]));
vty_out (vty, "%s", VTY_NEWLINE);
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 8b180a43..85e7dc25 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -25,7 +25,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "sockunion.h"
/* Typedef BGP specific types. */
-typedef u_int16_t as_t;
+typedef u_int32_t as_t;
+typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
typedef u_int16_t bgp_size_t;
/* BGP master for system wide configurations and variables. */
@@ -269,6 +270,9 @@ struct peer
/* Peer's Change local AS number. */
as_t change_local_as;
+ /* Peer's AS number as received with AS4Capability */
+ as_t as4cap;
+
/* Remote router ID. */
struct in_addr remote_id;
@@ -287,6 +291,9 @@ struct peer
int status;
int ostatus;
+ /* Peer index, used for dumping TABLE_DUMP_V2 format */
+ uint16_t table_dump_index;
+
/* Peer information */
int fd; /* File descriptor */
int ttl; /* TTL of TCP connection to the peer. */
@@ -316,7 +323,8 @@ struct peer
u_char afc_recv[AFI_MAX][SAFI_MAX];
/* Capability flags (reset in bgp_stop) */
- u_char cap;
+ /* grrr. 2 hours lost, can not use u_char anymore, have 1 bit too much */
+ u_int16_t cap;
#define PEER_CAP_REFRESH_ADV (1 << 0) /* refresh advertised */
#define PEER_CAP_REFRESH_OLD_RCV (1 << 1) /* refresh old received */
#define PEER_CAP_REFRESH_NEW_RCV (1 << 2) /* refresh rfc received */
@@ -324,6 +332,8 @@ struct peer
#define PEER_CAP_DYNAMIC_RCV (1 << 4) /* dynamic received */
#define PEER_CAP_RESTART_ADV (1 << 5) /* restart advertised */
#define PEER_CAP_RESTART_RCV (1 << 6) /* restart received */
+#define PEER_CAP_AS4_ADV (1 << 7) /* as4 advertised */
+#define PEER_CAP_AS4_RCV (1 << 8) /* as4 received */
/* Capability flags (reset in bgp_stop) */
u_int16_t af_cap[AFI_MAX][SAFI_MAX];
@@ -591,6 +601,8 @@ struct bgp_nlri
#define BGP_ATTR_MP_REACH_NLRI 14
#define BGP_ATTR_MP_UNREACH_NLRI 15
#define BGP_ATTR_EXT_COMMUNITIES 16
+#define BGP_ATTR_AS4_PATH 17
+#define BGP_ATTR_AS4_AGGREGATOR 18
/* BGP update origin. */
#define BGP_ORIGIN_IGP 0
diff --git a/doc/BGP-TypeCode b/doc/BGP-TypeCode
index 0904e19f..92343e49 100644
--- a/doc/BGP-TypeCode
+++ b/doc/BGP-TypeCode
@@ -19,6 +19,8 @@
14 MP_REACH_NLRI [RFC 2283]
15 MP_UNREACH_NLRI [RFC 2283]
16 EXT_COMMUNITIES [draft-ramachandra-bgp-ext-communities-09.txt]
+ 17 AS4_PATH [draft-ietf-idr-as4bytes-13.txt]
+ 18 AS4_AGGREGATOR [draft-ietf-idr-as4bytes-13.txt]
254 RCID_PATH [RFC 1863]
255 ADVERTISER [RFC 1863]
=========================================================================
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 850fd54d..32c95709 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,7 @@
+2006-12-01 Juergen Kammer <j.kammer@eurodata.de>
+
+ * aspath_test.c: Support asn32 changes, call aspath_parse with 16 bit.
+
2006-08-26 Paul Jakma <paul.jakma@sun.com>
* heavy-wq.c: (slow_func_del,slow_func) update to match workqueue
diff --git a/tests/aspath_test.c b/tests/aspath_test.c
index 1d28dbed..bf0262c2 100644
--- a/tests/aspath_test.c
+++ b/tests/aspath_test.c
@@ -508,7 +508,7 @@ make_aspath (const u_char *data, size_t len)
s = stream_new (len);
stream_put (s, data, len);
}
- as = aspath_parse (s, len);
+ as = aspath_parse (s, len, 0); /* jk: these are 16bit aspaths! */
if (s)
stream_free (s);
diff --git a/vtysh/ChangeLog b/vtysh/ChangeLog
index b9b78f5e..b69e065f 100644
--- a/vtysh/ChangeLog
+++ b/vtysh/ChangeLog
@@ -1,3 +1,8 @@
+2007-02-12 Juergen Kammer <j.kammer@eurodata.de>
+ * extract.pl: AS4 compatibility for router bgp ASNUMBER
+ * extract.pl.in: AS4 compatibility for router bgp ASNUMBER
+ * vtysh.c: AS4 compatibility for router bgp ASNUMBER
+
2006-07-27 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* vtysh_main.c: (usage) Add new -d and -E options. And note that
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index 98a9ddde..426a7bdd 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -37,8 +37,8 @@ $ignore{'"router ripng"'} = "ignore";
$ignore{'"router ospf"'} = "ignore";
$ignore{'"router ospf <0-65535>"'} = "ignore";
$ignore{'"router ospf6"'} = "ignore";
-$ignore{'"router bgp <1-65535>"'} = "ignore";
-$ignore{'"router bgp <1-65535> view WORD"'} = "ignore";
+$ignore{'"router bgp ASNUMBER"'} = "ignore";
+$ignore{'"router bgp ASNUMBER view WORD"'} = "ignore";
$ignore{'"router isis WORD"'} = "ignore";
$ignore{'"router zebra"'} = "ignore";
$ignore{'"address-family ipv4"'} = "ignore";
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 9b7d300f..4e71b018 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -838,7 +838,7 @@ DEFUNSH (VTYSH_ALL,
DEFUNSH (VTYSH_BGPD,
router_bgp,
router_bgp_cmd,
- "router bgp <1-65535>",
+ "router bgp ASNUMBER",
ROUTER_STR
BGP_STR
AS_STR)