diff options
author | Paul Jakma <paul.jakma@sun.com> | 2007-10-14 22:32:21 +0000 |
---|---|---|
committer | Paul Jakma <paul.jakma@sun.com> | 2007-10-14 22:32:21 +0000 |
commit | 0b2aa3a0a8b095bdef1eddda117d173af75dede2 (patch) | |
tree | 29201cb2beec187409e842b4078ed8a8047d3f11 /bgpd/bgp_attr.c | |
parent | 7593fddfa1558d086e3142ad96cf2790007f5d84 (diff) |
[bgpd] Merge AS4 support
2007-10-14 Paul Jakma <paul.jakma@sun.com>
* NEWS: Note that MRT dumps are now version 2
* (general) Merge in Juergen Kammer's AS4 patch.
2007-09-27 Paul Jakma <paul.jakma@sun.com>
* bgp_aspath.c: (assegment_normalise) remove duplicates from
from sets.
(aspath_reconcile_as4) disregard a broken part of the RFC around
error handling in path reconciliation.
* aspath_test.c: Test dupe-weeding from sets.
Test that reconciliation merges AS_PATH and AS4_PATH where
former is shorter than latter.
2007-09-26 Paul Jakma <paul.jakma@sun.com>
* aspath_test.c: Test AS4_PATH reconcilation where length
of AS_PATH and AS4_PATH is same.
2007-09-25 Paul Jakma <paul.jakma@sun.com>
* bgp_open.c: (peek_for_as4_capability) Fix to work.
* bgp_packet.c: (bgp_open_receive) Fix sanity check of as4.
* tests/bgp_capability_test.c: (general) Extend tests to validate
peek_for_as4_capability.
Add test of full OPEN Option block, with multiple capabilities,
both as a series of Option, and a single option.
Add some crap to beginning of stream, to prevent code depending
on getp == 0.
2007-09-18 Paul Jakma <paul.jakma@sun.com>
* bgp_open.c: (bgp_capability_as4) debug printf inline with others.
(peek_for_as4_capability) There's no need to signal failure, as
failure is better dealt with through full capability parser -
just return the AS4, simpler.
* bgp_packet.c: (bgp_open_receive) Update to match
peek_for_as4_capability change.
Allow use of BGP_AS_TRANS by 2b speakers.
Use NOTIFY_OPEN_ERR rather than CEASE for OPEN parsing errors.
(bgp_capability_msg_parse) missing argument to debug print
(bgp_capability_receive) missing return values.
* tests/bgp_capability_test.c: (parse_test) update for changes to
peek_for_as4_capability
2007-07-25 Paul Jakma <paul.jakma@sun.com>
* Remove 2-byte size macros, just make existing macros take
argument to indicate which size to use.
Adjust all users - typically they want '1'.
* bgp_aspath.c: (aspath_has_as4) New, return 1 if there are any
as4's in a path.
(aspath_put) Return the number of bytes actually written, to
fix the bug Juergen noted: Splitting of segments will change
the number of bytes written from that already written to the
AS_PATH header.
(aspath_snmp_pathseg) Pass 2-byte flag to aspath_put. SNMP
is still defined as 2b.
(aspath_aggregate) fix latent bug.
(aspath_reconcile_as4) AS_PATH+NEW_AS_PATH reconciliation
function.
(aspath_key_make) Hash the AS_PATH string, rather than
just taking the addition of assegment ASes as the hash value,
hopefully sligthly more collision resistant.
(bgp_attr_munge_as4_attrs) Collide the NEW_ attributes
together with the OLD 2-byte forms, code Juergen
had in bgp_attr_parse but re-organised a bit.
(bgp_attr_parse) Bunch of code from Juergen moves
to previous function.
(bgp_packet_attribute) Compact significantly by
just /always/ using extended-length attr header.
Fix bug Juergen noted, by using aspath_put's
(new) returned size value for the attr header rather
than the (guesstimate) of aspath_size() - the two could
differ when aspath_put had to split large segments, unlikely
this bug was ever hit in the 'wild'.
(bgp_dump_routes_attr) Always use extended-len and
use aspath_put return for header length. Output 4b ASN
for AS_PATH and AGGREGATOR.
* bgp_ecommunity.c: (ecommunity_{hash_make,cmp}) fix
hash callback declarations to match prototypes.
(ecommunity_gettoken) Updated for ECOMMUNITY_ENCODE_AS4,
complete rewrite of Juergen's changes (no asdot support)
* bgp_open.c: (bgp_capability_as4) New, does what it says
on the tin.
(peek_for_as4_capability) Rewritten to use streams and
bgp_capability_as4.
* bgp_packet.c: (bgp_open_send) minor edit
checked (in the abstract at least) with Juergen.
Changes are to be more accepting, e.g, allow AS_TRANS on
a 2-byte session.
* (general) Update all commands to use CMD_AS_RANGE.
* bgp_vty.c: (bgp_clear) Fix return vals to use CMD_..
Remove stuff replicated by VTY_GET_LONG
(bgp_clear_vty) Return bgp_clear directly to vty.
* tests/aspath_test.c: Exercise 32bit parsing. Test reconcile
function.
* tests/ecommunity_test.c: New, test AS4 ecommunity changes,
positive test only at this time, error cases not tested yet.
2007-07-25 Juergen Kammer <j.kammer@eurodata.de>
* (general) AS4 support.
* bgpd.h: as_t changes to 4-bytes.
* bgp_aspath.h: Add BGP_AS4_MAX and BGP_AS_TRANS defines.
* bgp_aspath.c: AS_VALUE_SIZE becomes 4-byte, AS16_VALUE_SIZE
added for 2-byte.
Add AS16 versions of length calc macros.
(aspath_count_numas) New, count number of ASes.
(aspath_has_as4) New, return 1 if there are any as4's in a
path.
(assegments_parse) Interpret assegment as 4 or 2 byte,
according to how the caller instructs us, with a new
argument.
(aspath_parse) Add use32bit argument to pass to
assegments_parse. Adjust all its callers to pass 1, unless
otherwise noted.
(assegment_data_put) Adjust to be able to write 2 or 4 byte
AS, according to new use32bit argument.
(aspath_put) Adjust to write 2 or 4.
(aspath_gettoken) Use a long for passed in asno.
* bgp_attr.c: (attr_str) Add BGP_ATTR_AS4_PATH and
BGP_ATTR_AS4_AGGREGATOR.
(bgp_attr_aspath) Call aspath_parse with right 2/4 arg, as
determined by received-capability flag.
(bgp_attr_aspath_check) New, code previously in attr_aspath
but moved to new func so it can be run after NEW_AS_PATH
reconciliation.
(bgp_attr_as4_path) New, handle NEW_AS_PATH.
(bgp_attr_aggregator) Adjust to cope with 2/4 byte ASes.
(bgp_attr_as4_aggregator) New, read NEW_AGGREGATOR.
(bgp_attr_parse) Add handoffs to previous parsers for the two
new AS4 NEW_ attributes.
Various checks added for NEW/OLD reconciliation.
(bgp_packet_attribute) Support 2/4 for AS_PATH and
AGGREGATOR, detect when NEW_ attrs need to be sent.
* bgp_debug.{c,h}: Add 'debug bgp as4'.
* bgp_dump.c: MRTv2 support, unconditionally enabled, which
supports AS4. Based on patches from Erik (RIPE?).
* bgp_ecommunity.c: (ecommunity_ecom2str) ECOMMUNITY_ENCODE_AS4
support.
* bgp_open.c: (peek_for_as4_capability) New, peek for AS4
capability prior to full capability parsing, so we know which
ASN to use for struct peer lookup.
(bgp_open_capability) Always send AS4 capability.
* bgp_packet.c: (bgp_open_send) AS4 handling for AS field
(bgp_open_receive) Peek for AS4 capability first, and figure
out which AS to believe.
* bgp_vty.c: (bgp_show_peer) Print AS4 cap
* tests/aspath_test.c: Support asn32 changes, call aspath_parse
with 16 bit.
* vtysh/extract.pl: AS4 compatibility for router bgp ASNUMBER
* vtysh/extract.pl.in: AS4 compatibility for router bgp ASNUMBER
* vtysh/vtysh.c: AS4 compatibility for router bgp ASNUMBER
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r-- | bgpd/bgp_attr.c | 411 |
1 files changed, 359 insertions, 52 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 9d13ca6e..b463b3c0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -56,8 +56,10 @@ static struct message attr_str [] = { BGP_ATTR_RCID_PATH, "RCID_PATH" }, { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, - { BGP_ATTR_EXT_COMMUNITIES, "BGP_ATTR_EXT_COMMUNITIES" }, - { BGP_ATTR_AS_PATHLIMIT, "BGP_ATTR_AS_PATHLIMIT" }, + { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" }, + { BGP_ATTR_AS4_PATH, "AS4_PATH" }, + { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, + { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, { 0, NULL } }; int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); @@ -794,8 +796,6 @@ static int bgp_attr_aspath (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { - struct bgp *bgp; - struct aspath *aspath; bgp_size_t total; total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); @@ -813,8 +813,14 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, return -1; } + /* + * peer with AS4 => will get 4Byte ASnums + * otherwise, will get 16 Bit + */ + attr->aspath = aspath_parse (peer->ibuf, length, + CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)); + /* In case of IBGP, length will be zero. */ - attr->aspath = aspath_parse (peer->ibuf, length); if (! attr->aspath) { zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); @@ -824,6 +830,28 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, return -1; } + /* Forward pointer. */ +/* stream_forward_getp (peer->ibuf, length);*/ + + /* Set aspath attribute flag. */ + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + + return 0; +} + +static int bgp_attr_aspath_check( struct peer *peer, + struct attr *attr) +{ + /* These checks were part of bgp_attr_aspath, but with + * as4 we should to check aspath things when + * aspath synthesizing with as4_path has already taken place. + * Otherwise we check ASPATH and use the synthesized thing, and that is + * not right. + * So do the checks later, i.e. here + */ + struct bgp *bgp = peer->bgp; + struct aspath *aspath; + bgp = peer->bgp; /* First AS check for EBGP. */ @@ -851,11 +879,20 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, attr->aspath = aspath_intern (aspath); } - /* Forward pointer. */ -/* stream_forward_getp (peer->ibuf, length);*/ + return 0; + +} + +/* Parse AS4 path information. This function is another wrapper of + aspath_parse. */ +static int +bgp_attr_as4_path (struct peer *peer, bgp_size_t length, + struct attr *attr, struct aspath **as4_path) +{ + *as4_path = aspath_parse (peer->ibuf, length, 1); /* Set aspath attribute flag. */ - attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); return 0; } @@ -981,18 +1018,27 @@ static int bgp_attr_aggregator (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag) { + int wantedlen = 6; struct attr_extra *attre = bgp_attr_extra_get (attr); - if (length != 6) + /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ + if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) + wantedlen = 8; + + if (length != wantedlen) { - zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length); + zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return -1; } - attre->aggregator_as = stream_getw (peer->ibuf); + + if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) + attre->aggregator_as = stream_getl (peer->ibuf); + else + attre->aggregator_as = stream_getw (peer->ibuf); attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf); /* Set atomic aggregate flag. */ @@ -1001,6 +1047,145 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, return 0; } +/* New Aggregator attribute */ +static int +bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, + struct attr *attr, as_t *as4_aggregator_as, + struct in_addr *as4_aggregator_addr) +{ + if (length != 8) + { + zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); + + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + *as4_aggregator_as = stream_getl (peer->ibuf); + as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR); + + return 0; +} + +/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. + */ +static int +bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, + struct aspath *as4_path, as_t as4_aggregator, + struct in_addr *as4_aggregator_addr) +{ + int ignore_as4_path = 0; + struct aspath *newpath; + struct attr_extra *attre = attr->extra; + + if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) ) + { + /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR + * if given. + * It is worth a warning though, because the peer really + * should not send them + */ + if (BGP_DEBUG(as4, AS4)) + { + if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))) + zlog_debug ("[AS4] %s %s AS4_PATH", + peer->host, "AS4 capable peer, yet it sent"); + + if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) + zlog_debug ("[AS4] %s %s AS4_AGGREGATOR", + peer->host, "AS4 capable peer, yet it sent"); + } + + return 0; + } + + if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)) + && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))) + { + /* Hu? This is not supposed to happen at all! + * got as4_path and no aspath, + * This should already + * have been handled by 'well known attributes missing' + * But... yeah, paranoia + * Take this as a "malformed attribute" + */ + zlog (peer->log, LOG_ERR, + "%s BGP not AS4 capable peer sent AS4_PATH but" + " no AS_PATH, cant do anything here", peer->host); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + return -1; + } + + /* We have a asn16 peer. First, look for AS4_AGGREGATOR + * because that may override AS4_PATH + */ + if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) ) + { + assert (attre); + + if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) + { + /* received both. + * if the as_number in aggregator is not AS_TRANS, + * then AS4_AGGREGATOR and AS4_PATH shall be ignored + * and the Aggregator shall be taken as + * info on the aggregating node, and the AS_PATH + * shall be taken as the AS_PATH + * otherwise + * the Aggregator shall be ignored and the + * AS4_AGGREGATOR shall be taken as the + * Aggregating node and the AS_PATH is to be + * constructed "as in all other cases" + */ + if ( attre->aggregator_as != BGP_AS_TRANS ) + { + /* ignore */ + if ( BGP_DEBUG(as4, AS4)) + zlog_debug ("[AS4] %s BGP not AS4 capable peer" + " send AGGREGATOR != AS_TRANS and" + " AS4_AGGREGATOR, so ignore" + " AS4_AGGREGATOR and AS4_PATH", peer->host); + ignore_as4_path = 1; + } + else + { + /* "New_aggregator shall be taken as aggregator" */ + attre->aggregator_as = as4_aggregator; + attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr; + } + } + else + { + /* We received a AS4_AGGREGATOR but no AGGREGATOR. + * That is bogus - but reading the conditions + * we have to handle AS4_AGGREGATOR as if it were + * AGGREGATOR in that case + */ + if ( BGP_DEBUG(as4, AS4)) + zlog_debug ("[AS4] %s BGP not AS4 capable peer send" + " AS4_AGGREGATOR but no AGGREGATOR, will take" + " it as if AGGREGATOR with AS_TRANS had been there", peer->host); + attre->aggregator_as = as4_aggregator; + /* sweep it under the carpet and simulate a "good" AGGREGATOR */ + attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)); + } + } + + /* need to reconcile NEW_AS_PATH and AS_PATH */ + if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) ) + { + newpath = aspath_reconcile_as4 (attr->aspath, as4_path); + aspath_unintern (attr->aspath); + attr->aspath = aspath_intern (newpath); + } + return 0; +} + /* Community attribute. */ static int bgp_attr_community (struct peer *peer, bgp_size_t length, @@ -1318,11 +1503,16 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, { int ret; u_char flag; - u_char type; + u_char type = 0; bgp_size_t length; u_char *startp, *endp; u_char *attr_endp; u_char seen[BGP_ATTR_BITMAP_SIZE]; + /* we need the as4_path only until we have synthesized the as_path with it */ + /* same goes for as4_aggregator */ + struct aspath *as4_path = NULL; + as_t as4_aggregator = 0; + struct in_addr as4_aggregator_addr = { 0 }; /* Initialize bitmap. */ memset (seen, 0, BGP_ATTR_BITMAP_SIZE); @@ -1339,7 +1529,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, /* XXX warning: long int format, int arg (arg 5) */ zlog (peer->log, LOG_WARNING, "%s error BGP attribute length %lu is smaller than min len", - peer->host, endp - STREAM_PNT (BGP_INPUT (peer))); + peer->host, + (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, @@ -1401,6 +1592,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_AS_PATH: ret = bgp_attr_aspath (peer, length, attr, flag, startp); break; + case BGP_ATTR_AS4_PATH: + ret = bgp_attr_as4_path (peer, length, attr, &as4_path ); + break; case BGP_ATTR_NEXT_HOP: ret = bgp_attr_nexthop (peer, length, attr, flag, startp); break; @@ -1416,6 +1610,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_AGGREGATOR: ret = bgp_attr_aggregator (peer, length, attr, flag); break; + case BGP_ATTR_AS4_AGGREGATOR: + ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr); + break; case BGP_ATTR_COMMUNITIES: ret = bgp_attr_community (peer, length, attr, flag); break; @@ -1480,6 +1677,51 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, return -1; } + /* + * At this place we can see whether we got AS4_PATH and/or + * AS4_AGGREGATOR from a 16Bit peer and act accordingly. + * We can not do this before we've read all attributes because + * the as4 handling does not say whether AS4_PATH has to be sent + * after AS_PATH or not - and when AS4_AGGREGATOR will be send + * in relationship to AGGREGATOR. + * So, to be defensive, we are not relying on any order and read + * all attributes first, including these 32bit ones, and now, + * afterwards, we look what and if something is to be done for as4. + */ + if (bgp_attr_munge_as4_attrs (peer, attr, as4_path, + as4_aggregator, &as4_aggregator_addr)) + return -1; + + /* At this stage, we have done all fiddling with as4, and the + * resulting info is in attr->aggregator resp. attr->aspath + * so we can chuck as4_aggregator and as4_path alltogether in + * order to save memory + */ + if ( as4_path ) + { + aspath_unintern( as4_path ); /* unintern - it is in the hash */ + as4_path = NULL; + /* The flag that we got this is still there, but that does not + * do any trouble + */ + } + /* + * The "rest" of the code does nothing with as4_aggregator. + * there is no memory attached specifically which is not part + * of the attr. + * so ignoring just means do nothing. + */ + /* + * Finally do the checks on the aspath we did not do yet + * because we waited for a potentially synthesized aspath. + */ + if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))) + { + ret = bgp_attr_aspath_check( peer, attr ); + if ( ret < 0 ) + return ret; + } + /* Finally intern unknown attribute. */ if (attr->extra && attr->extra->transit) attr->extra->transit = transit_intern (attr->extra->transit); @@ -1530,8 +1772,11 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, struct prefix_rd *prd, u_char *tag) { size_t cp; - unsigned int aspath_data_size; + size_t aspath_sizep; struct aspath *aspath; + int send_as4_path = 0; + int send_as4_aggregator = 0; + int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0; if (! bgp) bgp = bgp_get_default (); @@ -1578,25 +1823,27 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, else aspath = attr->aspath; - /* AS path attribute extended length bit check. */ - aspath_data_size = aspath_size (aspath); - if (aspath_data_size > 255) - { - stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); - stream_putc (s, BGP_ATTR_AS_PATH); - stream_putw (s, aspath_data_size); - } - else - { - stream_putc (s, BGP_ATTR_FLAG_TRANS); - stream_putc (s, BGP_ATTR_AS_PATH); - stream_putc (s, aspath_data_size); - } - aspath_put (s, aspath); - - if (aspath != attr->aspath) - aspath_free (aspath); - + /* If peer is not AS4 capable, then: + * - send the created AS_PATH out as AS4_PATH (optional, transitive), + * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment + * types are in it (i.e. exclude them if they are there) + * AND do this only if there is at least one asnum > 65535 in the path! + * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change + * all ASnums > 65535 to BGP_AS_TRANS + */ + + stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_AS_PATH); + aspath_sizep = stream_get_endp (s); + stream_putw (s, 0); + stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit)); + + /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs + * in the path + */ + if (!use32bit && aspath_has_as4 (aspath)) + send_as4_path = 1; /* we'll do this later, at the correct place */ + /* Nexthop attribute. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP) { @@ -1645,10 +1892,36 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) { assert (attr->extra); + + /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); - stream_putc (s, 6); - stream_putw (s, attr->extra->aggregator_as); + + if (use32bit) + { + /* AS4 capable peer */ + stream_putc (s, 8); + stream_putl (s, attr->extra->aggregator_as); + } + else + { + /* 2-byte AS peer */ + stream_putc (s, 6); + + /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */ + if ( attr->extra->aggregator_as > 65535 ) + { + stream_putw (s, BGP_AS_TRANS); + + /* we have to send AS4_AGGREGATOR, too. + * we'll do that later in order to send attributes in ascending + * order. + */ + send_as4_aggregator = 1; + } + else + stream_putw (s, (u_int16_t) attr->extra->aggregator_as); + } stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } @@ -1873,6 +2146,47 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } } } + + if ( send_as4_path ) + { + /* If the peer is NOT As4 capable, AND */ + /* there are ASnums > 65535 in path THEN + * give out AS4_PATH */ + + /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET + * path segments! + * Hm, I wonder... confederation things *should* only be at + * the beginning of an aspath, right? Then we should use + * aspath_delete_confed_seq for this, because it is already + * there! (JK) + * Folks, talk to me: what is reasonable here!? + */ + aspath = aspath_delete_confed_seq (aspath); + + stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_AS4_PATH); + aspath_sizep = stream_get_endp (s); + stream_putw (s, 0); + stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1)); + } + + if (aspath != attr->aspath) + aspath_free (aspath); + + if ( send_as4_aggregator ) + { + assert (attr->extra); + + /* send AS4_AGGREGATOR, at this place */ + /* this section of code moved here in order to ensure the correct + * *ascending* order of attributes + */ + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_AS4_AGGREGATOR); + stream_putc (s, 8); + stream_putl (s, attr->extra->aggregator_as); + stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); + } /* AS-Pathlimit */ if (attr->pathlimit.ttl) @@ -1967,7 +2281,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, { unsigned long cp; unsigned long len; - unsigned int aspathlen; + size_t aspath_lenp; struct aspath *aspath; /* Remember current pointer. */ @@ -1983,20 +2297,13 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, stream_putc (s, attr->origin); aspath = attr->aspath; - - if ( (aspathlen = aspath_size (aspath)) > 255 ) - { - stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); - stream_putc (s, BGP_ATTR_AS_PATH); - stream_putw (s, aspathlen); - } - else - { - stream_putc (s, BGP_ATTR_FLAG_TRANS); - stream_putc (s, BGP_ATTR_AS_PATH); - stream_putc (s, aspathlen); - } - aspath_put (s, aspath); + + stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_AS_PATH); + aspath_lenp = stream_get_endp (s); + stream_putw (s, 0); + + stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1)); /* Nexthop attribute. */ /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */ @@ -2044,8 +2351,8 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, assert (attr->extra); stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); - stream_putc (s, 6); - stream_putw (s, attr->extra->aggregator_as); + stream_putc (s, 8); + stream_putl (s, attr->extra->aggregator_as); stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } |