diff options
author | Juergen Kammer <j.kammer@eurodata.de> | 2007-04-09 14:03:25 -0500 |
---|---|---|
committer | Jeffrey C. Ollie <jeff@ocjtech.us> | 2007-04-09 14:03:25 -0500 |
commit | fc4dc72017e8208111866382782640117d03fb5f (patch) | |
tree | c3a8747eeb471098d0dfb4f2e9138d1ac0cfa2f7 | |
parent | 6502208c3217e52e693146e6b72e76fd76982a51 (diff) | |
download | quagga-fc4dc72017e8208111866382782640117d03fb5f.tar.bz2 quagga-fc4dc72017e8208111866382782640117d03fb5f.tar.xz |
Applying quagga-cvs20070307-as4-v05.patchquagga-cvs20070307-as4-v05.patch
-rw-r--r-- | bgpd/ChangeLog | 85 | ||||
-rw-r--r-- | bgpd/bgp_aspath.c | 457 | ||||
-rw-r--r-- | bgpd/bgp_aspath.h | 55 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 432 | ||||
-rw-r--r-- | bgpd/bgp_attr.h | 7 | ||||
-rw-r--r-- | bgpd/bgp_debug.c | 180 | ||||
-rw-r--r-- | bgpd/bgp_debug.h | 5 | ||||
-rw-r--r-- | bgpd/bgp_dump.c | 265 | ||||
-rw-r--r-- | bgpd/bgp_dump.h | 22 | ||||
-rw-r--r-- | bgpd/bgp_ecommunity.c | 103 | ||||
-rw-r--r-- | bgpd/bgp_ecommunity.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_mplsvpn.c | 5 | ||||
-rw-r--r-- | bgpd/bgp_open.c | 134 | ||||
-rw-r--r-- | bgpd/bgp_open.h | 4 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 87 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_routemap.c | 23 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 269 | ||||
-rw-r--r-- | bgpd/bgpd.c | 69 | ||||
-rw-r--r-- | bgpd/bgpd.h | 16 | ||||
-rw-r--r-- | doc/BGP-TypeCode | 2 | ||||
-rw-r--r-- | tests/ChangeLog | 4 | ||||
-rw-r--r-- | tests/aspath_test.c | 2 | ||||
-rw-r--r-- | vtysh/ChangeLog | 5 | ||||
-rwxr-xr-x | vtysh/extract.pl.in | 4 | ||||
-rw-r--r-- | vtysh/vtysh.c | 2 |
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) |