Index: tests/aspath_test.c =================================================================== --- tests/aspath_test.c (.../trunk) (revision 8372) +++ tests/aspath_test.c (.../branches/as32) (revision 8372) @@ -509,7 +509,7 @@ 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); Index: tests/ChangeLog =================================================================== --- tests/ChangeLog (.../trunk) (revision 8372) +++ tests/ChangeLog (.../branches/as32) (revision 8372) @@ -1,3 +1,7 @@ +2006-12-01 Juergen Kammer + + * aspath_test.c: Support asn32 changes, call aspath_parse with 16 bit. + 2006-08-26 Paul Jakma * heavy-wq.c: (slow_func_del,slow_func) update to match workqueue Index: doc/BGP-TypeCode =================================================================== --- doc/BGP-TypeCode (.../trunk) (revision 8372) +++ doc/BGP-TypeCode (.../branches/as32) (revision 8372) @@ -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 NEW_AS_PATH [draft-ietf-idr-as4bytes-12.txt] + 18 NEW_AGGREGATOR [draft-ietf-idr-as4bytes-12.txt] 254 RCID_PATH [RFC 1863] 255 ADVERTISER [RFC 1863] ========================================================================= Index: bgpd/bgp_attr.c =================================================================== --- bgpd/bgp_attr.c (.../trunk) (revision 8372) +++ bgpd/bgp_attr.c (.../branches/as32) (revision 8372) @@ -56,6 +56,8 @@ { BGP_ATTR_RCID_PATH, "RCID_PATH" }, { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, + { BGP_ATTR_NEW_AS_PATH, "NEW_AS_PATH" }, + { BGP_ATTR_NEW_AGGREGATOR, "NEW_AGGREGATOR" }, { 0, NULL } }; @@ -655,8 +657,6 @@ 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 @@ return -1; } + /* + * peer with 4BYTE_AS => will get 4Byte ASnums + * otherwise, will get 16 Bit + */ + if ( CHECK_FLAG (peer->cap, PEER_CAP_4BYTE_AS_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 @@ 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 + * asn32 we should to check aspath things when + * aspath synthesizing with new_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 @@ attr->aspath = aspath_intern (aspath); } - /* Forward pointer. */ -/* stream_forward_getp (peer->ibuf, length);*/ + return 0; +} + +/* Parse new AS path information. This function is another wrapper of + aspath_parse. */ +static int +bgp_attr_new_aspath (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp) +{ + attr->new_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_NEW_AS_PATH); return 0; } @@ -842,16 +881,31 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag) { - if (length != 6) + int wantedlen; + + /* + * peer with 4BYTE_AS will send 4 Byte AS, peer without will send 2 Byte + */ + if ( CHECK_FLAG (peer->cap, PEER_CAP_4BYTE_AS_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_4BYTE_AS_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 @@ return 0; } +/* New Aggregator attribute */ +static int +bgp_attr_new_aggregator (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag) +{ + as_t new_aggregator_as; + u_int32_t new_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; + } + new_aggregator_as = stream_getl (peer->ibuf); + new_aggregator_address = stream_get_ipv4 (peer->ibuf); + /* Set atomic aggregate flag. */ + attr->new_aggregator_as = new_aggregator_as; + attr->new_aggregator_addr.s_addr = new_aggregator_address; + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEW_AGGREGATOR); + + return 0; +} + /* Community attribute. */ static int bgp_attr_community (struct peer *peer, bgp_size_t length, @@ -1238,6 +1320,9 @@ case BGP_ATTR_AS_PATH: ret = bgp_attr_aspath (peer, length, attr, flag, startp); break; + case BGP_ATTR_NEW_AS_PATH: + ret = bgp_attr_new_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 @@ case BGP_ATTR_AGGREGATOR: ret = bgp_attr_aggregator (peer, length, attr, flag); break; + case BGP_ATTR_NEW_AGGREGATOR: + ret = bgp_attr_new_aggregator (peer, length, attr, flag); + break; case BGP_ATTR_COMMUNITIES: ret = bgp_attr_community (peer, length, attr, flag); break; @@ -1303,6 +1391,169 @@ return -1; } + /* + * At this place we can see whether we got NEW_ASPATH and/or + * NEW_AGGREGATOR from a 16Bit peer and act accordingly. + * We can not do this before we've read all attributes because + * the asn32 handling does not say whether NEW_AS_PATH has to be sent + * after AS_PATH or not - and when NEW_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 asn32. + */ + + if ( CHECK_FLAG (peer->cap, PEER_CAP_4BYTE_AS_RCV ) ) + { + /* peer can do 4BYTE, so we ignore NEW_AS_PATH and NEW_AGGREGATOR + * if given. + * It is worth a warning though, because the peer really + * should not send them + */ + if ( CHECK_BITMAP (seen, BGP_ATTR_NEW_AS_PATH) ) + { + if ( BGP_DEBUG(asn32, ASN32)) + zlog_debug ( "[ASN32] %s BGP 4BYTE AS capable peer send NEW_AS_PATH", peer->host); + } + if ( CHECK_BITMAP (seen, BGP_ATTR_NEW_AGGREGATOR) ) + { + if ( BGP_DEBUG(asn32, ASN32)) + zlog_debug ( "[ASN32] %s BGP 4BYTE AS capable peer send NEW_AGGREGATOR", peer->host); + } + } + else + { + /* We have a asn16 peer. First, look for NEW_AGGREGATOR + * because that may override NEW_ASPATH + */ + int ignore_new_aspath = 0; + if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_NEW_AGGREGATOR) ) ) + { + if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) + { + /* received both. + * if the as_number in aggregator is not AS_TRANS, + * then NEW_Aggregator and NEW_ASPATH 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 + * NEW_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(asn32, ASN32)) + zlog_debug ( + "[ASN32] %s BGP not 4BYTE AS capable peer send AGGREGATOR != AS_TRANS and NEW_AGGREGATOR, so ignore NEW_AGGREGATOR and NEW_ASPATH", peer->host); + ignore_new_aspath = 1; + } + else + { + /* "New_aggregator shall be taken as aggregator" */ + attr->aggregator_as = attr->new_aggregator_as; + attr->aggregator_addr.s_addr = attr->new_aggregator_addr.s_addr; + } + } + else + { + /* We received a NEW_AGGREGATOR but no AGGREGATOR. + * That is bogus - but reading the conditions + * we have to handle NEW_AGGREGATOR as if it were + * AGGREGATOR in that case + */ + if ( BGP_DEBUG(asn32, ASN32)) + zlog_debug ( + "[ASN32] %s BGP not 4BYTE AS capable peer send NEW_AGGREGATOR but no AGGREGATOR, will take it as if AGGREGATOR with AS_TRANS had been there", peer->host); + attr->aggregator_as = attr->new_aggregator_as; + /* sweep it under the carpet and simulate a "good" AGGRGATOR */ + SET_BITMAP (seen, BGP_ATTR_AGGREGATOR); + attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)); + } + } + if ( !ignore_new_aspath && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_NEW_AS_PATH))) ) + { + if ( ! (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))) + { + /* Hu? This is not supposed to happen at all! + * got new_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 4BYTE AS capable peer sent NEW_ASPATH 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 NEW_AS_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_new_aspath => + * ignore NEW_AS_PATH, take AS_PATH. + * else + * take as many as_numbers and path segments from AS_PATH + * and prepend them to NEW_AS_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->new_aspath ); + + if ( BGP_DEBUG(asn32, ASN32)) + zlog_debug ( + "[ASN32] %s fiddling with aspath and newaspath, hopnumdifference is %d", + peer->host, hopnumdiff); + if ( hopnumdiff >= 0 ) + { + if ( BGP_DEBUG(asn32, ASN32)) + zlog_debug( + "[ASN32] %s got AS_PATH %s and NEW_AS_PATH %s synthesizing now", peer->host, attr->aspath->str, attr->new_aspath->str); + aspath_truncateathopsandjoin( &attr->aspath, &attr->new_aspath, hopnumdiff ); + if ( BGP_DEBUG(asn32, ASN32)) + zlog_debug( + "[ASN32] %s result of synthesizing is %s", peer->host, attr->aspath->str); + } + } + } + + /* At this stage, we have done all fiddling with asn32, and the + * resulting info is in attr->aggregator resp. attr->aspath + * so we can chuck new_aggregator and new_aspath alltogether in + * order to save memory + */ + if ( attr->new_aspath ) + { + aspath_unintern( attr->new_aspath ); /* unintern - it is in the hash */ + attr->new_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 new_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 @@ { size_t cp; unsigned int aspath_data_size; + unsigned int numas; struct aspath *aspath; if (! bgp) @@ -1401,21 +1653,92 @@ else aspath = attr->aspath; + /* If peer is not AS32 capable, then: + * - send the created ASPATH out as NEW_ASPATH (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 ASPATH 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_4BYTE_AS_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 asn32 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 NEW_AS_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_NEW_AS_PATH); + stream_putw (s, aspath_data_size); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_NEW_AS_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 @@ /* 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 AS32 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 NEW_AGGREGATOR (opt, transitional) + * with the correct 4 Bytes thingy. + * else + * proceed as you always did + */ + if ( CHECK_FLAG (peer->cap, PEER_CAP_4BYTE_AS_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_NEW_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. */ @@ -1791,7 +2153,7 @@ 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 */ Index: bgpd/bgp_attr.h =================================================================== --- bgpd/bgp_attr.h (.../trunk) (revision 8372) +++ bgpd/bgp_attr.h (.../branches/as32) (revision 8372) @@ -57,6 +57,9 @@ /* AS Path structure */ struct aspath *aspath; + /* New AS Path structure */ + struct aspath *new_aspath; + /* Community structure */ struct community *community; @@ -80,11 +83,13 @@ u_int32_t med; u_int32_t local_pref; struct in_addr aggregator_addr; + struct in_addr new_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 new_aggregator_as; u_char origin; u_char mp_nexthop_len; }; Index: bgpd/bgp_aspath.c =================================================================== --- bgpd/bgp_aspath.c (.../trunk) (revision 8372) +++ bgpd/bgp_aspath.c (.../branches/as32) (revision 8372) @@ -31,12 +31,16 @@ #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 @@ * 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 @@ /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; +/* asn32 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 ASN32 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 @@ 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 @@ * 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 AS32 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 @@ * 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 @@ /* 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 @@ { 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 @@ /* 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 @@ if (length == 0) return NULL; + if (BGP_DEBUG (asn32, ASN32_SEGMENT)) + zlog_debug ("[ASN32SEG] 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 @@ /* softly softly, get the header first on its own */ segh.type = stream_getc (s); segh.length = stream_getc (s); + + if (BGP_DEBUG (asn32, ASN32_SEGMENT)) + zlog_debug ("[ASN32SEG] 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 @@ 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 (asn32, ASN32_SEGMENT)) + zlog_debug ("[ASN32SEG] 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 (asn32, ASN32_SEGMENT)) + zlog_debug ("[ASN32SEG] Parse aspath segment: Bytes now: %d",bytes); prev = seg; } @@ -680,16 +877,21 @@ 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 @@ } 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 @@ /* 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 @@ 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 @@ 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 @@ */ /* 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 @@ *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 @@ return 0; } +/* Truncate an aspath after a number of hops, and put the hops remaining + * at the front of another aspath. Needed for ASN32 compat. */ +void +aspath_truncateathopsandjoin( struct aspath **aspath, struct aspath **new_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 NEW_ASPATH? 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 asn32 capable... something which is + * not supposed to be done... + */ + assegment_free( seg ); + if (BGP_DEBUG (asn32, ASN32)) + zlog_debug ("[ASN32] ASPATH32mangle: AS_CONFED_SEQUENCE would have been cut in two, taking AS_PATH instead of mangling"); + aspath_unintern(*new_aspath); + *new_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 + * new_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(*new_aspath); + + aspath_merge( newfront, newlybuild ); + aspath_free(newfront); + + aspath_unintern(*aspath); + aspath_unintern(*new_aspath); + *new_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 @@ 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 @@ struct aspath * aspath_empty (void) { - return aspath_parse (NULL, 0); + return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */ } struct aspath * @@ -1315,7 +1700,7 @@ /* 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 @@ } /* Check actual AS value. */ + /* Is now [<16bitnumber>.]<16bitnumber> for asdot(+), + * <32bitnumber> for asplain, + * or even */ + 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 @@ { enum as_token token = as_token_unknown; u_short as_type; - u_short asno = 0; + u_long asno = 0; struct aspath *aspath; int needtype; Index: bgpd/bgp_vty.c =================================================================== --- bgpd/bgp_vty.c (.../trunk) (revision 8372) +++ bgpd/bgp_vty.c (.../branches/as32) (revision 8372) @@ -265,6 +265,51 @@ return CMD_SUCCESS; } +DEFUN (bgp_asnum_output_format, + bgp_asnum_output_format_cmd, + "bgp asnum format (asdot|asdot+|asplain|asip)", + "BGP_STR" + "ASnumber format" + ) +{ + 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 +353,24 @@ /* "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 +383,12 @@ 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 +400,7 @@ 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 +410,7 @@ /* "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 +420,13 @@ 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 +446,7 @@ 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 +597,7 @@ 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 +608,13 @@ 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 +634,13 @@ 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 +649,7 @@ 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 +658,7 @@ 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 +672,13 @@ 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 +694,7 @@ 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 +709,13 @@ 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 +1330,13 @@ 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 +1364,10 @@ 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 +1375,7 @@ 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 +1439,7 @@ 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 +1469,7 @@ 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 +1491,7 @@ 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 +1504,13 @@ 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 +1524,7 @@ 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 +1549,7 @@ 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 +1558,7 @@ 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 +4211,11 @@ { 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 +4414,7 @@ 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 +4425,14 @@ 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 +4944,7 @@ 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 +4958,7 @@ 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 +4967,7 @@ 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 +4988,7 @@ 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 +5000,7 @@ 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 +5016,7 @@ 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 +5027,7 @@ 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 +5040,7 @@ 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 +5050,7 @@ 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 +5058,7 @@ 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 +5848,7 @@ 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 +5862,7 @@ 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 +5871,7 @@ 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 +5885,7 @@ 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 +5906,7 @@ 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 +5918,7 @@ 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 +5939,7 @@ 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 +5955,7 @@ 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 +5966,7 @@ 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 +5979,7 @@ 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 +5989,7 @@ 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 +5997,7 @@ 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 +6006,7 @@ 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 +6019,7 @@ 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 +6334,7 @@ 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 +6347,7 @@ 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 +6367,7 @@ 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 +6382,7 @@ 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 +6394,7 @@ 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 +6695,7 @@ 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 +6711,8 @@ /* 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,14 +6758,26 @@ 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 + + peer->notify_out + peer->refresh_out + + peer->dynamic_cap_out, + 0, 0, peer->obuf->count); vty_out (vty, "%8s", peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN)); @@ -7181,9 +7280,9 @@ /* 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 +7360,18 @@ { vty_out (vty, " Neighbor capabilities:%s", VTY_NEWLINE); + /* 4BYTEAS */ + if (CHECK_FLAG (p->cap, PEER_CAP_4BYTE_AS_RCV) + || CHECK_FLAG (p->cap, PEER_CAP_4BYTE_AS_ADV)) + { + vty_out (vty, " 4 Byte AS:"); + if (CHECK_FLAG (p->cap, PEER_CAP_4BYTE_AS_ADV)) + vty_out (vty, " advertised"); + if (CHECK_FLAG (p->cap, PEER_CAP_4BYTE_AS_RCV)) + vty_out (vty, " %sreceived", + CHECK_FLAG (p->cap, PEER_CAP_4BYTE_AS_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 +8008,7 @@ 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 +8877,9 @@ 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); Index: bgpd/bgp_aspath.h =================================================================== --- bgpd/bgp_aspath.h (.../trunk) (revision 8372) +++ bgpd/bgp_aspath.h (.../branches/as32) (revision 8372) @@ -31,7 +31,10 @@ #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 @@ #define ASPATH_STR_DEFAULT_LEN 32 +/* stuffed this here, with asn32 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 ASPLAIN so we use that as + * default. + * For everybody, the summary (all <...> are given out as decimal value): + * + * asdot [.] + * higher16bits ONLY given out if not 0. + * asdot+ . + * higher16bits ALWAYS given out. + * asplain <32bits> + * asip <8highestbits><8bitsbelowthem><8bitsfurtherdown> + * + * 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_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 */ Index: bgpd/bgp_ecommunity.c =================================================================== --- bgpd/bgp_ecommunity.c (.../trunk) (revision 8372) +++ bgpd/bgp_ecommunity.c (.../branches/as32) (revision 8372) @@ -27,6 +27,7 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_aspath.h" /* Hash of community attribute. */ struct hash *ecomhash; @@ -283,7 +284,8 @@ u_int32_t val_high = 0; const char *p = str; struct in_addr ip; - char ipstr[INET_ADDRSTRLEN + 1]; + as_t asn32; + char helpstr[INET_ADDRSTRLEN + 1]; /* Skip white space. */ while (isspace ((int) *p)) @@ -346,6 +348,7 @@ goto error; } + asn32 = (as_t) 0; while (isdigit ((int) *p) || *p == ':' || *p == '.') { if (*p == ':') @@ -361,12 +364,22 @@ 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 */ + asn32 = str2asnum( helpstr, NULL); + if ( !asn32 ) + goto error; + } + else + { + ret = inet_aton (helpstr, &ip); + if (ret == 0) + goto error; + } } else val_high = val_low; @@ -394,9 +407,28 @@ if (! digit || ! separator) goto error; + if ( !asn32 && !dot && val_high > 65535 ) + { + /* Ha. someone using asplain for input + * Automagically switch to 4 byte as! + * Got it! + */ + asn32 = val_high; + } /* Encode result into routing distinguisher. */ - if (dot) + if (asn32) { + eval->val[0] = ECOMMUNITY_ENCODE_AS4BYTE; + eval->val[1] = 0; + eval->val[2] = (asn32 >>24) & 0xff; + eval->val[3] = (asn32 >>16) & 0xff; + eval->val[4] = (asn32 >>8) & 0xff; + eval->val[5] = asn32 & 0xff; + eval->val[6] = (val_low >> 8) & 0xff; + eval->val[7] = val_low & 0xff; + } + else if (dot) + { eval->val[0] = ECOMMUNITY_ENCODE_IP; eval->val[1] = 0; memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); @@ -576,7 +608,8 @@ /* 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_AS4BYTE) { len = sprintf (str_buf + str_pnt, "?"); str_pnt += len; @@ -618,6 +651,21 @@ } /* Put string into buffer. */ + if (encode == ECOMMUNITY_ENCODE_AS4BYTE) + { + 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); Index: bgpd/bgp_ecommunity.h =================================================================== --- bgpd/bgp_ecommunity.h (.../trunk) (revision 8372) +++ bgpd/bgp_ecommunity.h (.../branches/as32) (revision 8372) @@ -24,6 +24,7 @@ /* High-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ENCODE_AS 0x00 #define ECOMMUNITY_ENCODE_IP 0x01 +#define ECOMMUNITY_ENCODE_AS4BYTE 0x02 /* Low-order octet of the Extended Communityes type field. */ #define ECOMMUNITY_ROUTE_TARGET 0x02 Index: bgpd/bgp_mplsvpn.c =================================================================== --- bgpd/bgp_mplsvpn.c (.../trunk) (revision 8372) +++ bgpd/bgp_mplsvpn.c (.../branches/as32) (revision 8372) @@ -371,7 +371,7 @@ 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 +478,7 @@ 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); Index: bgpd/bgp_open.c =================================================================== --- bgpd/bgp_open.c (.../trunk) (revision 8372) +++ bgpd/bgp_open.c (.../branches/as32) (revision 8372) @@ -483,6 +483,40 @@ SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); } + else if (cap.code == CAPABILITY_CODE_4BYTE_AS) + { + /* Check length */ + if (cap.length != CAPABILITY_CODE_4BYTE_AS_LEN) + { + zlog_info ("%s 4Byte-AS 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 4BYTEAS 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->as32cap = ((u_char) *gotthis++) << 24; + peer->as32cap |= ((u_char) *gotthis++) << 16; + peer->as32cap |= ((u_char) *gotthis++) << 8; + peer->as32cap |= ((u_char) *gotthis); + } + + if (BGP_DEBUG (asn32, ASN32)) + zlog_debug ("[ASN32] %s about to set cap PEER_CAP_4BYTE_AS_RCV at address %08x, value now %d, as32cap is %s", peer->host, &peer->cap, peer->cap,as2str(peer->as32cap)); + + SET_FLAG (peer->cap, PEER_CAP_4BYTE_AS_RCV); + + if (BGP_DEBUG (asn32, ASN32)) + zlog_debug ("[ASN32] %s set cap PEER_CAP_4BYTE_AS_RCV at address %08x, value now %d", peer->host, &peer->cap, peer->cap); + } else if (cap.code > 128) { @@ -525,6 +559,92 @@ return 1; } +/* peek into option, set as32 value if it is there */ +void peek_for_as32_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 (asn32, ASN32)) + zlog_debug ("[ASN32] %s rcv OPEN w/ OPTION parameter len: %u, peeking for as32", + peer->host, length); + + /* the error cases do DONT handle, we ONLY try to read as32 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_4BYTE_AS) + { + if (cap.length != CAPABILITY_CODE_4BYTE_AS_LEN) + return; + if (BGP_DEBUG (asn32, ASN32)) + zlog_debug ("[ASN32] %s OPEN peeking found 4BYTEAS capability", peer->host); + + { + /* + * We did not make a "stream_getl" + * Do the byte swivveling now + */ + u_char *gotthis = (char *) &cap.mpc; + peer->as32cap = ((u_char) *gotthis++) << 24; + peer->as32cap |= ((u_char) *gotthis++) << 16; + peer->as32cap |= ((u_char) *gotthis++) << 8; + peer->as32cap |= ((u_char) *gotthis); + + } + SET_FLAG (peer->cap, PEER_CAP_4BYTE_AS_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 +853,7 @@ 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 +940,18 @@ stream_putc (s, CAPABILITY_CODE_REFRESH); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); + /* AS32 */ + SET_FLAG (peer->cap, PEER_CAP_4BYTE_AS_ADV); + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_4BYTE_AS_LEN + 2); + stream_putc (s, CAPABILITY_CODE_4BYTE_AS); + stream_putc (s, CAPABILITY_CODE_4BYTE_AS_LEN); + if ( peer->change_local_as ) + local_as = peer->change_local_as; + else + local_as = peer->local_as; + stream_putl (s, local_as ); + /* ORF capability. */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) Index: bgpd/bgp_open.h =================================================================== --- bgpd/bgp_open.h (.../trunk) (revision 8372) +++ bgpd/bgp_open.h (.../branches/as32) (revision 8372) @@ -59,6 +59,7 @@ #define CAPABILITY_CODE_REFRESH_LEN 0 #define CAPABILITY_CODE_DYNAMIC_LEN 0 #define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */ +#define CAPABILITY_CODE_4BYTE_AS_LEN 4 /* Cooperative Route Filtering Capability. */ @@ -82,5 +83,6 @@ 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_as32_capability (struct peer *, u_char); #endif /* _QUAGGA_BGP_OPEN_H */ Index: bgpd/bgp_packet.c =================================================================== --- bgpd/bgp_packet.c (.../trunk) (revision 8372) +++ bgpd/bgp_packet.c (.../branches/as32) (revision 8372) @@ -804,7 +804,15 @@ /* 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-12: */ + /* 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 @@ 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 @@ 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 as32 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 as32! + */ + peek_for_as32_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->as32cap > BGP_AS_MAX ) + { + /* Take the AS32 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_4BYTE_AS_RCV) ) + { + /* raise error, log this, close session */ + zlog_err ("%s bad OPEN, got AS_TRANS but no 4BYTE_AS capability address peer->cap is %08x, value %d", + peer->host, &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->as32cap; + } + } else { + /* We may have a partner with AS32 who has an asno < BGP_AS_MAX */ + /* If we have got the capability, peer->as32cap must match remote_as */ + if ( CHECK_FLAG (peer->cap, PEER_CAP_4BYTE_AS_RCV) && + peer->as32cap != remote_as ) + { + /* raise error, log this, close session */ + zlog_err ("%s bad OPEN, got 4BYTEAS capability, but remote_as %u mismatch with 16bit 'myasn' %u in open", + peer->host, peer->as32cap, 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 @@ 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 @@ 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 @@ 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); Index: bgpd/ChangeLog =================================================================== --- bgpd/ChangeLog (.../trunk) (revision 8372) +++ bgpd/ChangeLog (.../branches/as32) (revision 8372) @@ -1,3 +1,28 @@ +2006-12-08 Juergen Kammer + + * 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-07 Paul Jakma * bgp_fsm.c: Bug #302 fix, diagnosis, suggestions and testing Index: bgpd/bgpd.c =================================================================== --- bgpd/bgpd.c (.../trunk) (revision 8372) +++ bgpd/bgpd.c (.../branches/as32) (revision 8372) @@ -2104,10 +2104,20 @@ 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->as32cap == remote_as && + CHECK_FLAG (peer->cap, PEER_CAP_4BYTE_AS_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->as32cap == remote_as && + CHECK_FLAG (peer->cap, PEER_CAP_4BYTE_AS_RCV)) + + ) + ) *as = 1; } } @@ -2116,10 +2126,18 @@ 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->as32cap == remote_as && + CHECK_FLAG (peer->cap, PEER_CAP_4BYTE_AS_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->as32cap == remote_as && + CHECK_FLAG (peer->cap, PEER_CAP_4BYTE_AS_RCV)) + ) *as = 1; } } @@ -4384,13 +4402,13 @@ 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 @@ /* 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 @@ write++; } + { + /* Sigh. Wish we woud 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 @@ 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 @@ /* 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 @@ 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); } Index: bgpd/bgp_debug.c =================================================================== --- bgpd/bgp_debug.c (.../trunk) (revision 8372) +++ bgpd/bgp_debug.c (.../branches/as32) (revision 8372) @@ -36,6 +36,7 @@ #include "bgpd/bgp_debug.h" #include "bgpd/bgp_community.h" +unsigned long conf_bgp_debug_asn32; 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_normal; unsigned long conf_bgp_debug_zebra; +unsigned long term_bgp_debug_asn32; unsigned long term_bgp_debug_fsm; unsigned long term_bgp_debug_events; unsigned long term_bgp_debug_packet; @@ -208,8 +210,8 @@ 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,92 @@ return bgp_debug_option & option; } +DEFUN (debug_bgp_asn32, + debug_bgp_asn32_cmd, + "debug bgp asn32", + DEBUG_STR + BGP_STR + "BGP 4Byte Asnumber actions\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (asn32, ASN32); + else + { + TERM_DEBUG_ON (asn32, ASN32); + vty_out (vty, "BGP asn32 debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_asn32, + no_debug_bgp_asn32_cmd, + "no debug bgp asn32", + NO_STR + DEBUG_STR + BGP_STR + "BGP 4Byte Asnumber actions\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (asn32, ASN32); + else + { + TERM_DEBUG_OFF (asn32, ASN32); + vty_out (vty, "BGP asn32 debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_asn32, + undebug_bgp_asn32_cmd, + "undebug bgp asn32", + UNDEBUG_STR + DEBUG_STR + BGP_STR + "BGP 4Byte Asnumber actions\n") + +DEFUN (debug_bgp_asn32_segment, + debug_bgp_asn32_segment_cmd, + "debug bgp asn32 segment", + DEBUG_STR + BGP_STR + "BGP 4Byte Asnumber aspath segment handling\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (asn32, ASN32_SEGMENT); + else + { + TERM_DEBUG_ON (asn32, ASN32_SEGMENT); + vty_out (vty, "BGP asn32 segment debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_asn32_segment, + no_debug_bgp_asn32_segment_cmd, + "no debug bgp asn32 segment", + NO_STR + DEBUG_STR + BGP_STR + "BGP 4Byte Asnumber aspath segment handling\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (asn32, ASN32_SEGMENT); + else + { + TERM_DEBUG_OFF (asn32, ASN32_SEGMENT); + vty_out (vty, "BGP asn32 segment debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_asn32_segment, + undebug_bgp_asn32_segment_cmd, + "undebug bgp asn32 segment", + UNDEBUG_STR + DEBUG_STR + BGP_STR + "BGP 4Byte Asnumber aspath segment handling\n") + DEFUN (debug_bgp_fsm, debug_bgp_fsm_cmd, "debug bgp fsm", @@ -648,6 +736,8 @@ TERM_DEBUG_OFF (keepalive, KEEPALIVE); TERM_DEBUG_OFF (update, UPDATE_IN); TERM_DEBUG_OFF (update, UPDATE_OUT); + TERM_DEBUG_OFF (asn32, ASN32); + TERM_DEBUG_OFF (asn32, ASN32_SEGMENT); TERM_DEBUG_OFF (fsm, FSM); TERM_DEBUG_OFF (filter, FILTER); TERM_DEBUG_OFF (zebra, ZEBRA); @@ -690,6 +780,10 @@ 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 (asn32, ASN32)) + vty_out (vty, " BGP asn32 debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (asn32, ASN32_SEGMENT)) + vty_out (vty, " BGP asn32 aspath segment debugging is on%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -705,6 +799,18 @@ write++; } + if (CONF_BGP_DEBUG (asn32, ASN32)) + { + vty_out (vty, "debug bgp asn32%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (asn32, ASN32_SEGMENT)) + { + vty_out (vty, "debug bgp asn32 segment%s", VTY_NEWLINE); + write++; + } + if (CONF_BGP_DEBUG (events, EVENTS)) { vty_out (vty, "debug bgp events%s", VTY_NEWLINE); @@ -768,6 +874,11 @@ install_element (ENABLE_NODE, &show_debugging_bgp_cmd); + 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 +896,13 @@ install_element (ENABLE_NODE, &debug_bgp_zebra_cmd); install_element (CONFIG_NODE, &debug_bgp_zebra_cmd); + 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); Index: bgpd/bgpd.h =================================================================== --- bgpd/bgpd.h (.../trunk) (revision 8372) +++ bgpd/bgpd.h (.../branches/as32) (revision 8372) @@ -25,7 +25,8 @@ #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 @@ /* Peer's Change local AS number. */ as_t change_local_as; + /* Peer's AS number as received with AS32Capability */ + as_t as32cap; + /* Remote router ID. */ struct in_addr remote_id; @@ -316,7 +320,8 @@ 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 +329,8 @@ #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_4BYTE_AS_ADV (1 << 7) /* 4byteas advertised */ +#define PEER_CAP_4BYTE_AS_RCV (1 << 8) /* 4byteas received */ /* Capability flags (reset in bgp_stop) */ u_int16_t af_cap[AFI_MAX][SAFI_MAX]; @@ -591,6 +598,8 @@ #define BGP_ATTR_MP_REACH_NLRI 14 #define BGP_ATTR_MP_UNREACH_NLRI 15 #define BGP_ATTR_EXT_COMMUNITIES 16 +#define BGP_ATTR_NEW_AS_PATH 17 +#define BGP_ATTR_NEW_AGGREGATOR 18 /* BGP update origin. */ #define BGP_ORIGIN_IGP 0 Index: bgpd/bgp_debug.h =================================================================== --- bgpd/bgp_debug.h (.../trunk) (revision 8372) +++ bgpd/bgp_debug.h (.../branches/as32) (revision 8372) @@ -56,6 +56,7 @@ extern int debug (unsigned int option); +extern unsigned long conf_bgp_debug_asn32; 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_normal; extern unsigned long conf_bgp_debug_zebra; +extern unsigned long term_bgp_debug_asn32; 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_normal; extern unsigned long term_bgp_debug_zebra; +#define BGP_DEBUG_ASN32 0x01 +#define BGP_DEBUG_ASN32_SEGMENT 0x02 + #define BGP_DEBUG_FSM 0x01 #define BGP_DEBUG_EVENTS 0x01 #define BGP_DEBUG_PACKET 0x01 Index: bgpd/bgp_routemap.c =================================================================== --- bgpd/bgp_routemap.c (.../trunk) (revision 8372) +++ bgpd/bgp_routemap.c (.../branches/as32) (revision 8372) @@ -1636,7 +1636,7 @@ 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 (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 @@ 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 @@ 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 @@ 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" Index: bgpd/bgp_route.c =================================================================== --- bgpd/bgp_route.c (.../trunk) (revision 8372) +++ bgpd/bgp_route.c (.../branches/as32) (revision 8372) @@ -5457,7 +5457,7 @@ 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)");