summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_attr.c
diff options
context:
space:
mode:
authorJuergen Kammer <j.kammer@eurodata.de>2007-04-09 14:03:25 -0500
committerJeffrey C. Ollie <jeff@ocjtech.us>2007-04-09 14:03:25 -0500
commitfc4dc72017e8208111866382782640117d03fb5f (patch)
treec3a8747eeb471098d0dfb4f2e9138d1ac0cfa2f7 /bgpd/bgp_attr.c
parent6502208c3217e52e693146e6b72e76fd76982a51 (diff)
downloadquagga-fc4dc72017e8208111866382782640117d03fb5f.tar.bz2
quagga-fc4dc72017e8208111866382782640117d03fb5f.tar.xz
Applying quagga-cvs20070307-as4-v05.patchquagga-cvs20070307-as4-v05.patch
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r--bgpd/bgp_attr.c432
1 files changed, 400 insertions, 32 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 4c72d80a..8a6d542e 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -56,6 +56,8 @@ struct message attr_str [] =
{ BGP_ATTR_RCID_PATH, "RCID_PATH" },
{ BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
{ BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
+ { BGP_ATTR_AS4_PATH, "AS4_PATH" },
+ { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
{ 0, NULL }
};
@@ -655,8 +657,6 @@ static int
bgp_attr_aspath (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag, u_char *startp)
{
- struct bgp *bgp;
- struct aspath *aspath;
bgp_size_t total;
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
@@ -674,8 +674,16 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
return -1;
}
+ /*
+ * peer with AS4 => will get 4Byte ASnums
+ * otherwise, will get 16 Bit
+ */
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
+ attr->aspath = aspath_parse (peer->ibuf, length, 1);
+ else
+ attr->aspath = aspath_parse (peer->ibuf, length, 0);
+
/* In case of IBGP, length will be zero. */
- attr->aspath = aspath_parse (peer->ibuf, length);
if (! attr->aspath)
{
zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
@@ -685,6 +693,28 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
return -1;
}
+ /* Forward pointer. */
+/* stream_forward_getp (peer->ibuf, length);*/
+
+ /* Set aspath attribute flag. */
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
+
+ return 0;
+}
+
+static int bgp_attr_aspath_check( struct peer *peer,
+ struct attr *attr)
+{
+ /* These checks were part of bgp_attr_aspath, but with
+ * as4 we should to check aspath things when
+ * aspath synthesizing with as4_aspath has already taken place.
+ * Otherwise we check ASPATH and use the synthesized thing, and that is
+ * not right.
+ * So do the checks later, i.e. here
+ */
+ struct bgp *bgp = peer->bgp;
+ struct aspath *aspath;
+
bgp = peer->bgp;
/* First AS check for EBGP. */
@@ -712,11 +742,20 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
attr->aspath = aspath_intern (aspath);
}
- /* Forward pointer. */
-/* stream_forward_getp (peer->ibuf, length);*/
+ return 0;
+
+}
+
+/* Parse AS4 path information. This function is another wrapper of
+ aspath_parse. */
+static int
+bgp_attr_as4_aspath (struct peer *peer, bgp_size_t length,
+ struct attr *attr, u_char flag, u_char *startp)
+{
+ attr->as4_aspath = aspath_parse (peer->ibuf, length, 1);
/* Set aspath attribute flag. */
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
return 0;
}
@@ -842,16 +881,31 @@ static int
bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag)
{
- if (length != 6)
+ int wantedlen;
+
+ /*
+ * peer with AS4 will send 4 Byte AS, peer without will send 2 Byte
+ */
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
+ wantedlen = 8;
+ else
+ wantedlen = 6;
+
+ if (length != wantedlen)
{
- zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
+ zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
bgp_notify_send (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
- attr->aggregator_as = stream_getw (peer->ibuf);
+
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
+ attr->aggregator_as = stream_getl (peer->ibuf);
+ else
+ attr->aggregator_as = stream_getw (peer->ibuf);
+
attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
/* Set atomic aggregate flag. */
@@ -860,6 +914,34 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
return 0;
}
+/* New Aggregator attribute */
+static int
+bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
+ struct attr *attr, u_char flag)
+{
+ as_t as4_aggregator_as;
+ u_int32_t as4_aggregator_address;
+
+ if (length != 8)
+ {
+ zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
+
+ bgp_notify_send (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ return -1;
+ }
+ as4_aggregator_as = stream_getl (peer->ibuf);
+ as4_aggregator_address = stream_get_ipv4 (peer->ibuf);
+ /* Set atomic aggregate flag. */
+ attr->as4_aggregator_as = as4_aggregator_as;
+ attr->as4_aggregator_addr.s_addr = as4_aggregator_address;
+
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
+
+ return 0;
+}
+
/* Community attribute. */
static int
bgp_attr_community (struct peer *peer, bgp_size_t length,
@@ -1238,6 +1320,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
case BGP_ATTR_AS_PATH:
ret = bgp_attr_aspath (peer, length, attr, flag, startp);
break;
+ case BGP_ATTR_AS4_PATH:
+ ret = bgp_attr_as4_aspath (peer, length, attr, flag, startp);
+ break;
case BGP_ATTR_NEXT_HOP:
ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
break;
@@ -1253,6 +1338,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
case BGP_ATTR_AGGREGATOR:
ret = bgp_attr_aggregator (peer, length, attr, flag);
break;
+ case BGP_ATTR_AS4_AGGREGATOR:
+ ret = bgp_attr_as4_aggregator (peer, length, attr, flag);
+ break;
case BGP_ATTR_COMMUNITIES:
ret = bgp_attr_community (peer, length, attr, flag);
break;
@@ -1303,6 +1391,169 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
return -1;
}
+ /*
+ * At this place we can see whether we got AS4_PATH and/or
+ * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
+ * We can not do this before we've read all attributes because
+ * the as4 handling does not say whether AS4_PATH has to be sent
+ * after AS_PATH or not - and when AS4_AGGREGATOR will be send
+ * in relationship to AGGREGATOR.
+ * So, to be defensive, we are not relying on any order and read
+ * all attributes first, including these 32bit ones, and now,
+ * afterwards, we look what and if something is to be done for as4.
+ */
+
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
+ {
+ /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
+ * if given.
+ * It is worth a warning though, because the peer really
+ * should not send them
+ */
+ if ( CHECK_BITMAP (seen, BGP_ATTR_AS4_PATH) )
+ {
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug ( "[AS4] %s BGP AS4 capable peer send AS4_PATH", peer->host);
+ }
+ if ( CHECK_BITMAP (seen, BGP_ATTR_AS4_AGGREGATOR) )
+ {
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug ( "[AS4] %s BGP AS4 capable peer send AS4_AGGREGATOR", peer->host);
+ }
+ }
+ else
+ {
+ /* We have a asn16 peer. First, look for AS4_AGGREGATOR
+ * because that may override AS4_PATH
+ */
+ int ignore_as4_aspath = 0;
+ if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
+ {
+ if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
+ {
+ /* received both.
+ * if the as_number in aggregator is not AS_TRANS,
+ * then AS4_AGGREGATOR and AS4_PATH shall be ignored
+ * and the Aggregator shall be taken as
+ * info on the aggregating node, and the AS_PATH
+ * shall be taken as the AS_PATH
+ * otherwise
+ * the Aggregator shall be ignored and the
+ * AS4_AGGREGATOR shall be taken as the
+ * Aggregating node and the AS_PATH is to be
+ * constructed "as in all other cases"
+ */
+ if ( attr->aggregator_as != BGP_AS_TRANS )
+ {
+ /* ignore */
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug (
+ "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH", peer->host);
+ ignore_as4_aspath = 1;
+ }
+ else
+ {
+ /* "New_aggregator shall be taken as aggregator" */
+ attr->aggregator_as = attr->as4_aggregator_as;
+ attr->aggregator_addr.s_addr = attr->as4_aggregator_addr.s_addr;
+ }
+ }
+ else
+ {
+ /* We received a AS4_AGGREGATOR but no AGGREGATOR.
+ * That is bogus - but reading the conditions
+ * we have to handle AS4_AGGREGATOR as if it were
+ * AGGREGATOR in that case
+ */
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug (
+ "[AS4] %s BGP not AS4 capable peer send AS4_AGGREGATOR but no AGGREGATOR, will take it as if AGGREGATOR with AS_TRANS had been there", peer->host);
+ attr->aggregator_as = attr->as4_aggregator_as;
+ /* sweep it under the carpet and simulate a "good" AGGREGATOR */
+ SET_BITMAP (seen, BGP_ATTR_AGGREGATOR);
+ attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
+ }
+ }
+ if ( !ignore_as4_aspath && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
+ {
+ if ( ! (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
+ {
+ /* Hu? This is not supposed to happen at all!
+ * got as4_aspath and no aspath,
+ * This should already
+ * have been handled by 'well known attributes missing'
+ * But... yeah, paranoia
+ * Take this as a "malformed attribute"
+ */
+ zlog (peer->log, LOG_ERR,
+ "%s BGP not AS4 capable peer sent AS4_PATH but no AS_PATH, cant do anything here", peer->host);
+ bgp_notify_send (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
+ return -1;
+ }
+ /* We have AS4_PATH AND AS_PATH
+ * Calculate the number of as numbers in both attributes!
+ * What is meant is the number of "hops"!
+ * if numas_in_aspath < numas_in_as4_aspath =>
+ * ignore AS4_PATH, take AS_PATH.
+ * else
+ * take as many as_numbers and path segments from AS_PATH
+ * and prepend them to AS4_PATH so that
+ * num_new = numas_in_aspath
+ * the resulting thing is our AS_PATH
+ * An AS_SET or AS_CONFED_SET is one hop
+ * every other thing has as many hops as asnums
+ */
+ int hopnumdiff = aspath_count_hops( attr->aspath ) - aspath_count_hops( attr->as4_aspath );
+
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug (
+ "[AS4] %s fiddling with aspath and newaspath, hopnumdifference is %d",
+ peer->host, hopnumdiff);
+ if ( hopnumdiff >= 0 )
+ {
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug(
+ "[AS4] %s got AS_PATH %s and AS4_PATH %s synthesizing now", peer->host, attr->aspath->str, attr->as4_aspath->str);
+ aspath_truncateathopsandjoin( &attr->aspath, &attr->as4_aspath, hopnumdiff );
+ if ( BGP_DEBUG(as4, AS4))
+ zlog_debug(
+ "[AS4] %s result of synthesizing is %s", peer->host, attr->aspath->str);
+ }
+ }
+ }
+
+ /* At this stage, we have done all fiddling with as4, and the
+ * resulting info is in attr->aggregator resp. attr->aspath
+ * so we can chuck as4_aggregator and as4_aspath alltogether in
+ * order to save memory
+ */
+ if ( attr->as4_aspath )
+ {
+ aspath_unintern( attr->as4_aspath ); /* unintern - it is in the hash */
+ attr->as4_aspath = NULL;
+ /* The flag that we got this is still there, but that does not
+ * do any trouble
+ */
+ }
+ /*
+ * The "rest" of the code does nothing with as4_aggregator.
+ * there is no memory attached specifically which is not part
+ * of the attr.
+ * so ignoring just means do nothing.
+ */
+ /*
+ * Finally do the checks on the aspath we did not do yet
+ * because we waited for a potentially synthesized aspath.
+ */
+ if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
+ {
+ ret = bgp_attr_aspath_check( peer, attr );
+ if ( ret < 0 )
+ return ret;
+ }
+
/* Finally intern unknown attribute. */
if (attr->transit)
attr->transit = transit_intern (attr->transit);
@@ -1354,6 +1605,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
{
size_t cp;
unsigned int aspath_data_size;
+ unsigned int numas;
struct aspath *aspath;
if (! bgp)
@@ -1401,21 +1653,92 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
else
aspath = attr->aspath;
+ /* If peer is not AS4 capable, then:
+ * - send the created AS_PATH out as AS4_PATH (optional, transitive),
+ * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
+ * types are in it (i.e. exclude them if they are there)
+ * AND do this only if there is at least one asnum > 65535 in the path!
+ * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
+ * all ASnums > 65535 to BGP_AS_TRANS
+ *
+ * Beware: aspath_data_size is ONLY correct if there is no aspath segment
+ * longer 255, and no two segments which are able to be merged
+ * That thing is in the code for a looonng time and nobody bothers.
+ */
+
/* AS path attribute extended length bit check. */
aspath_data_size = aspath_size (aspath);
- if (aspath_data_size > 255)
+ numas = aspath_count_numas( aspath );
+
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
{
- stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_AS_PATH);
- stream_putw (s, aspath_data_size);
+ /* this is the easy part, peer is as4 capable, send 4 byte aspath */
+ if (aspath_data_size > 255)
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_AS_PATH);
+ stream_putw (s, aspath_data_size);
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AS_PATH);
+ stream_putc (s, aspath_data_size);
+ }
+ aspath_put (s, aspath, 1);
}
else
{
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_AS_PATH);
- stream_putc (s, aspath_data_size);
+ /*
+ * size of 16bit aspath is smaller by number of asnums * 2Bytes
+ * actually, number os asnums * (sizeof(as_t) - sizeof(as16_t)),
+ * but that is nit-picking.
+ */
+ if (aspath_data_size - 2*numas > 255)
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_AS_PATH);
+ stream_putw (s, aspath_data_size - 2*numas );
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AS_PATH);
+ stream_putc (s, aspath_data_size - 2*numas );
+ }
+ aspath_put (s, aspath, 0);
+
+ if ( aspath_count_num32as( aspath ) > 0 )
+ {
+ /* put out AS4_PATH (only if there are ASnums > 65535 in path */
+
+ /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
+ * path segments!
+ * Hm, I wonder... confederation things *should* only be at
+ * the beginning of an aspath, right? Then we should use
+ * aspath_delete_confed_seq for this, because it is already
+ * there! (JK)
+ * Folks, talk to me: what is reasonable here!?
+ */
+ if ( aspath_count_confeds(aspath) > 0 ) {
+ aspath_cleanoutall_asconfeds( &aspath, &aspath_data_size );
+ }
+
+ if (aspath_data_size > 255)
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_AS4_PATH);
+ stream_putw (s, aspath_data_size);
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc (s, BGP_ATTR_AS4_PATH);
+ stream_putc (s, aspath_data_size);
+ }
+ aspath_put (s, aspath, 1);
+ }
}
- aspath_put (s, aspath);
if (aspath != attr->aspath)
aspath_free (aspath);
@@ -1467,11 +1790,50 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
/* Aggregator. */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
{
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_AGGREGATOR);
- stream_putc (s, 6);
- stream_putw (s, attr->aggregator_as);
- stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ /* If peer is AS4 capable,
+ * then
+ * send BGP_ATTR_AGGREGATOR with 32 bit AS value
+ * else
+ * if attr->aggregator_as > 65535
+ * change the aggregator_as in the AGGREGATOR to AS_TRANS
+ * and send out a AS4_AGGREGATOR (opt, transitional)
+ * with the correct 4 Bytes thingy.
+ * else
+ * proceed as you always did
+ */
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AGGREGATOR);
+ stream_putc (s, 8);
+ stream_putl (s, attr->aggregator_as);
+ stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ }
+ else
+ {
+ if ( attr->aggregator_as > 65535 )
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AGGREGATOR);
+ stream_putc (s, 6);
+ stream_putw (s, BGP_AS_TRANS);
+ stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
+ stream_putc (s, 8);
+ stream_putl (s, attr->aggregator_as);
+ stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_AGGREGATOR);
+ stream_putc (s, 6);
+ stream_putw (s, (u_int16_t) attr->aggregator_as);
+ stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ }
+ }
}
/* Community attribute. */
@@ -1758,7 +2120,7 @@ bgp_attr_init (void)
/* Make attribute packet. */
void
bgp_dump_routes_attr (struct stream *s, struct attr *attr,
- struct prefix *prefix)
+ struct prefix *prefix, int dump_small_mp_nlri)
{
unsigned long cp;
unsigned long len;
@@ -1791,7 +2153,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
stream_putc (s, BGP_ATTR_AS_PATH);
stream_putc (s, aspathlen);
}
- aspath_put (s, aspath);
+ aspath_put (s, aspath, 1); /* always 32bit. aspath_put size remarks apply */
/* Nexthop attribute. */
/* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
@@ -1838,8 +2200,8 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
{
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_AGGREGATOR);
- stream_putc (s, 6);
- stream_putw (s, attr->aggregator_as);
+ stream_putc (s, 8);
+ stream_putl (s, attr->aggregator_as);
stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
}
@@ -1874,8 +2236,11 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
/* MP header */
stream_putc (s, 0); /* Length of this attribute. */
- stream_putw(s, AFI_IP6); /* AFI */
- stream_putc(s, SAFI_UNICAST); /* SAFI */
+ if(!dump_small_mp_nlri)
+ {
+ stream_putw(s, AFI_IP6); /* AFI */
+ stream_putc(s, SAFI_UNICAST); /* SAFI */
+ }
/* Next hop */
stream_putc(s, attr->mp_nexthop_len);
@@ -1883,11 +2248,14 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
if(attr->mp_nexthop_len == 32)
stream_put(s, &attr->mp_nexthop_local, 16);
- /* SNPA */
- stream_putc(s, 0);
+ if(!dump_small_mp_nlri)
+ {
+ /* SNPA */
+ stream_putc(s, 0);
- /* Prefix */
- stream_put_prefix(s, prefix);
+ /* Prefix */
+ stream_put_prefix(s, prefix);
+ }
/* Set MP attribute length. */
stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);