summaryrefslogtreecommitdiff
path: root/bgpd/bgp_attr.c
diff options
context:
space:
mode:
authorPaul Jakma <paul.jakma@sun.com>2007-10-14 22:32:21 +0000
committerPaul Jakma <paul.jakma@sun.com>2007-10-14 22:32:21 +0000
commit0b2aa3a0a8b095bdef1eddda117d173af75dede2 (patch)
tree29201cb2beec187409e842b4078ed8a8047d3f11 /bgpd/bgp_attr.c
parent7593fddfa1558d086e3142ad96cf2790007f5d84 (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.c411
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);
}