summaryrefslogtreecommitdiff
path: root/bgpd/bgp_attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r--bgpd/bgp_attr.c385
1 files changed, 246 insertions, 139 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 28f01609..07c94130 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -282,9 +282,47 @@ transit_init ()
}
/* Attribute hash routines. */
-
struct hash *attrhash;
+static struct attr_extra *
+bgp_attr_extra_new (void)
+{
+ return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
+}
+
+void
+bgp_attr_extra_free (struct attr *attr)
+{
+ if (attr->extra)
+ {
+ XFREE (MTYPE_ATTR_EXTRA, attr->extra);
+ attr->extra = NULL;
+ }
+}
+
+struct attr_extra *
+bgp_attr_extra_get (struct attr *attr)
+{
+ if (!attr->extra)
+ attr->extra = bgp_attr_extra_new();
+ return attr->extra;
+}
+
+/* Shallow copy of an attribute
+ * Though, not so shallow that it doesn't copy the contents
+ * of the attr_extra pointed to by 'extra'
+ */
+void
+bgp_attr_dup (struct attr *new, struct attr *orig)
+{
+ *new = *orig;
+ if (orig->extra)
+ {
+ new->extra = bgp_attr_extra_new();
+ *new->extra = *orig->extra;
+ }
+}
+
unsigned long int
attr_count (void)
{
@@ -307,33 +345,41 @@ attrhash_key_make (void *p)
key += attr->nexthop.s_addr;
key += attr->med;
key += attr->local_pref;
- key += attr->aggregator_as;
- key += attr->aggregator_addr.s_addr;
- key += attr->weight;
-
- key += attr->mp_nexthop_global_in.s_addr;
+
+ if (attr->extra)
+ {
+ key += attr->extra->aggregator_as;
+ key += attr->extra->aggregator_addr.s_addr;
+ key += attr->extra->weight;
+ key += attr->extra->mp_nexthop_global_in.s_addr;
+ }
+
if (attr->aspath)
key += aspath_key_make (attr->aspath);
if (attr->community)
key += community_hash_make (attr->community);
- if (attr->ecommunity)
- key += ecommunity_hash_make (attr->ecommunity);
- if (attr->cluster)
- key += cluster_hash_key_make (attr->cluster);
- if (attr->transit)
- key += transit_hash_key_make (attr->transit);
+
+ if (attr->extra)
+ {
+ if (attr->extra->ecommunity)
+ key += ecommunity_hash_make (attr->extra->ecommunity);
+ if (attr->extra->cluster)
+ key += cluster_hash_key_make (attr->extra->cluster);
+ if (attr->extra->transit)
+ key += transit_hash_key_make (attr->extra->transit);
#ifdef HAVE_IPV6
- {
- int i;
-
- key += attr->mp_nexthop_len;
- for (i = 0; i < 16; i++)
- key += attr->mp_nexthop_global.s6_addr[i];
- for (i = 0; i < 16; i++)
- key += attr->mp_nexthop_local.s6_addr[i];
- }
+ {
+ int i;
+
+ key += attr->extra->mp_nexthop_len;
+ for (i = 0; i < 16; i++)
+ key += attr->extra->mp_nexthop_global.s6_addr[i];
+ for (i = 0; i < 16; i++)
+ key += attr->extra->mp_nexthop_local.s6_addr[i];
+ }
#endif /* HAVE_IPV6 */
+ }
return key;
}
@@ -347,23 +393,33 @@ attrhash_cmp (void *p1, void *p2)
if (attr1->flag == attr2->flag
&& attr1->origin == attr2->origin
&& attr1->nexthop.s_addr == attr2->nexthop.s_addr
+ && attr1->aspath == attr2->aspath
+ && attr1->community == attr2->community
&& attr1->med == attr2->med
- && attr1->local_pref == attr2->local_pref
- && attr1->aggregator_as == attr2->aggregator_as
- && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
- && attr1->weight == attr2->weight
+ && attr1->local_pref == attr2->local_pref)
+ {
+ struct attr_extra *ae1 = attr1->extra;
+ struct attr_extra *ae2 = attr2->extra;
+
+ if (ae1 && ae2
+ && ae1->aggregator_as == ae2->aggregator_as
+ && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
+ && ae1->weight == ae2->weight
#ifdef HAVE_IPV6
- && attr1->mp_nexthop_len == attr2->mp_nexthop_len
- && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
- && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
+ && ae1->mp_nexthop_len == ae2->mp_nexthop_len
+ && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
+ && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
#endif /* HAVE_IPV6 */
- && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
- && attr1->aspath == attr2->aspath
- && attr1->community == attr2->community
- && attr1->ecommunity == attr2->ecommunity
- && attr1->cluster == attr2->cluster
- && attr1->transit == attr2->transit)
- return 1;
+ && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
+ && ae1->ecommunity == ae2->ecommunity
+ && ae1->cluster == ae2->cluster
+ && ae1->transit == ae2->transit)
+ return 1;
+ else if (ae1 || ae2)
+ return 0;
+ /* neither attribute has extra attributes, so they're same */
+ return 1;
+ }
else
return 0;
}
@@ -400,6 +456,11 @@ bgp_attr_hash_alloc (void *p)
attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
*attr = *val;
+ if (val->extra)
+ {
+ attr->extra = bgp_attr_extra_new ();
+ *attr->extra = *val->extra;
+ }
attr->refcnt = 0;
return attr;
}
@@ -425,26 +486,31 @@ bgp_attr_intern (struct attr *attr)
else
attr->community->refcnt++;
}
- if (attr->ecommunity)
+ if (attr->extra)
{
- if (! attr->ecommunity->refcnt)
- attr->ecommunity = ecommunity_intern (attr->ecommunity);
- else
- attr->ecommunity->refcnt++;
- }
- if (attr->cluster)
- {
- if (! attr->cluster->refcnt)
- attr->cluster = cluster_intern (attr->cluster);
- else
- attr->cluster->refcnt++;
- }
- if (attr->transit)
- {
- if (! attr->transit->refcnt)
- attr->transit = transit_intern (attr->transit);
- else
- attr->transit->refcnt++;
+ struct attr_extra *attre = attr->extra;
+
+ if (attre->ecommunity)
+ {
+ if (! attre->ecommunity->refcnt)
+ attre->ecommunity = ecommunity_intern (attre->ecommunity);
+ else
+ attre->ecommunity->refcnt++;
+ }
+ if (attre->cluster)
+ {
+ if (! attre->cluster->refcnt)
+ attre->cluster = cluster_intern (attre->cluster);
+ else
+ attre->cluster->refcnt++;
+ }
+ if (attre->transit)
+ {
+ if (! attre->transit->refcnt)
+ attre->transit = transit_intern (attre->transit);
+ else
+ attre->transit->refcnt++;
+ }
}
find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
@@ -459,15 +525,16 @@ struct attr *
bgp_attr_default_set (struct attr *attr, u_char origin)
{
memset (attr, 0, sizeof (struct attr));
-
+ bgp_attr_extra_get (attr);
+
attr->origin = origin;
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
attr->aspath = aspath_empty ();
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
- attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
+ attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
#ifdef HAVE_IPV6
- attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
+ attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
#endif
return attr;
@@ -480,10 +547,16 @@ bgp_attr_default_intern (u_char origin)
{
struct attr attr;
struct attr *new;
-
+ struct attr_extra *attre;
+
+ memset (&attr, 0, sizeof (struct attr));
+ attre = bgp_attr_extra_get (&attr);
+
bgp_attr_default_set(&attr, origin);
new = bgp_attr_intern (&attr);
+ bgp_attr_extra_free (&attr);
+
aspath_unintern (new->aspath);
return new;
}
@@ -495,9 +568,11 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
{
struct attr attr;
struct attr *new;
+ struct attr_extra *attre;
memset (&attr, 0, sizeof (struct attr));
-
+ attre = bgp_attr_extra_get (&attr);
+
/* Origin attribute. */
attr.origin = origin;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
@@ -518,20 +593,22 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
}
- attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
+ attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
#ifdef HAVE_IPV6
- attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
+ attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
#endif
if (! as_set)
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
- attr.aggregator_as = bgp->confed_id;
+ attre->aggregator_as = bgp->confed_id;
else
- attr.aggregator_as = bgp->as;
- attr.aggregator_addr = bgp->router_id;
+ attre->aggregator_as = bgp->as;
+ attre->aggregator_addr = bgp->router_id;
new = bgp_attr_intern (&attr);
+ bgp_attr_extra_free (&attr);
+
aspath_unintern (new->aspath);
return new;
}
@@ -543,23 +620,27 @@ bgp_attr_unintern (struct attr *attr)
struct attr *ret;
struct aspath *aspath;
struct community *community;
- struct ecommunity *ecommunity;
- struct cluster_list *cluster;
- struct transit *transit;
+ struct ecommunity *ecommunity = NULL;
+ struct cluster_list *cluster = NULL;
+ struct transit *transit = NULL;
/* Decrement attribute reference. */
attr->refcnt--;
aspath = attr->aspath;
community = attr->community;
- ecommunity = attr->ecommunity;
- cluster = attr->cluster;
- transit = attr->transit;
+ if (attr->extra)
+ {
+ ecommunity = attr->extra->ecommunity;
+ cluster = attr->extra->cluster;
+ transit = attr->extra->transit;
+ }
/* If reference becomes zero then free attribute object. */
if (attr->refcnt == 0)
{
ret = hash_release (attrhash, attr);
assert (ret != NULL);
+ bgp_attr_extra_free (attr);
XFREE (MTYPE_ATTR, attr);
}
@@ -583,12 +664,16 @@ bgp_attr_flush (struct attr *attr)
aspath_free (attr->aspath);
if (attr->community && ! attr->community->refcnt)
community_free (attr->community);
- if (attr->ecommunity && ! attr->ecommunity->refcnt)
- ecommunity_free (attr->ecommunity);
- if (attr->cluster && ! attr->cluster->refcnt)
- cluster_free (attr->cluster);
- if (attr->transit && ! attr->transit->refcnt)
- transit_free (attr->transit);
+ if (attr->extra)
+ {
+ struct attr_extra *attre = attr->extra;
+ if (attre->ecommunity && ! attre->ecommunity->refcnt)
+ ecommunity_free (attre->ecommunity);
+ if (attre->cluster && ! attre->cluster->refcnt)
+ cluster_free (attre->cluster);
+ if (attre->transit && ! attre->transit->refcnt)
+ transit_free (attre->transit);
+ }
}
/* Get origin attribute of the update message. */
@@ -851,6 +936,8 @@ static int
bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag)
{
+ struct attr_extra *attre = bgp_attr_extra_get (attr);
+
if (length != 6)
{
zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
@@ -860,8 +947,8 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
- attr->aggregator_as = stream_getw (peer->ibuf);
- attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
+ attre->aggregator_as = stream_getw (peer->ibuf);
+ attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
/* Set atomic aggregate flag. */
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
@@ -903,7 +990,8 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
return -1;
}
- attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
+ (bgp_attr_extra_get (attr))->originator_id.s_addr
+ = stream_get_ipv4 (peer->ibuf);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
@@ -926,8 +1014,8 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
return -1;
}
- attr->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf),
- length);
+ (bgp_attr_extra_get (attr))->cluster
+ = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
stream_forward_getp (peer->ibuf, length);;
@@ -947,6 +1035,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
size_t start;
int ret;
struct stream *s;
+ struct attr_extra *attre = bgp_attr_extra_get(attr);
/* Set end of packet. */
s = BGP_INPUT(peer);
@@ -962,16 +1051,16 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
safi = stream_getc (s);
/* Get nexthop length. */
- attr->mp_nexthop_len = stream_getc (s);
+ attre->mp_nexthop_len = stream_getc (s);
- if (STREAM_READABLE(s) < attr->mp_nexthop_len)
+ if (STREAM_READABLE(s) < attre->mp_nexthop_len)
return -1;
/* Nexthop length check. */
- switch (attr->mp_nexthop_len)
+ switch (attre->mp_nexthop_len)
{
case 4:
- stream_get (&attr->mp_nexthop_global_in, s, 4);
+ stream_get (&attre->mp_nexthop_global_in, s, 4);
break;
case 12:
{
@@ -980,35 +1069,35 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
rd_high = stream_getl (s);
rd_low = stream_getl (s);
- stream_get (&attr->mp_nexthop_global_in, s, 4);
+ stream_get (&attre->mp_nexthop_global_in, s, 4);
}
break;
#ifdef HAVE_IPV6
case 16:
- stream_get (&attr->mp_nexthop_global, s, 16);
+ stream_get (&attre->mp_nexthop_global, s, 16);
break;
case 32:
- stream_get (&attr->mp_nexthop_global, s, 16);
- stream_get (&attr->mp_nexthop_local, s, 16);
- if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
+ stream_get (&attre->mp_nexthop_global, s, 16);
+ stream_get (&attre->mp_nexthop_local, s, 16);
+ if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
{
char buf1[INET6_ADDRSTRLEN];
char buf2[INET6_ADDRSTRLEN];
if (BGP_DEBUG (update, UPDATE_IN))
zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
- inet_ntop (AF_INET6, &attr->mp_nexthop_global,
+ inet_ntop (AF_INET6, &attre->mp_nexthop_global,
buf1, INET6_ADDRSTRLEN),
- inet_ntop (AF_INET6, &attr->mp_nexthop_local,
+ inet_ntop (AF_INET6, &attre->mp_nexthop_local,
buf2, INET6_ADDRSTRLEN));
- attr->mp_nexthop_len = 16;
+ attre->mp_nexthop_len = 16;
}
break;
#endif /* HAVE_IPV6 */
default:
zlog_info ("Wrong multiprotocol next hop length: %d",
- attr->mp_nexthop_len);
+ attre->mp_nexthop_len);
return -1;
}
@@ -1089,10 +1178,13 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag)
{
if (length == 0)
- attr->ecommunity = NULL;
+ {
+ if (attr->extra)
+ attr->extra->ecommunity = NULL;
+ }
else
{
- attr->ecommunity =
+ (bgp_attr_extra_get (attr))->ecommunity =
ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
stream_forward_getp (peer->ibuf, length);
}
@@ -1108,6 +1200,7 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
{
bgp_size_t total;
struct transit *transit;
+ struct attr_extra *attre;
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
@@ -1149,13 +1242,13 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
/* Store transitive attribute to the end of attr->transit. */
- if (! attr->transit)
+ if (! ((attre = bgp_attr_extra_get(attr))->transit) )
{
- attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
- memset (attr->transit, 0, sizeof (struct transit));
+ attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
+ memset (attre->transit, 0, sizeof (struct transit));
}
- transit = attr->transit;
+ transit = attre->transit;
if (transit->val)
transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
@@ -1337,8 +1430,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
}
/* Finally intern unknown attribute. */
- if (attr->transit)
- attr->transit = transit_intern (attr->transit);
+ if (attr->extra && attr->extra->transit)
+ attr->extra->transit = transit_intern (attr->extra->transit);
return 0;
}
@@ -1500,11 +1593,12 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
/* Aggregator. */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
{
+ 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->aggregator_as);
- stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ stream_putw (s, attr->extra->aggregator_as);
+ stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
}
/* Community attribute. */
@@ -1531,13 +1625,15 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
&& from
&& peer_sort (from) == BGP_PEER_IBGP)
{
+ assert (attr->extra);
+
/* Originator ID. */
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
stream_putc (s, 4);
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- stream_put_in_addr (s, &attr->originator_id);
+ stream_put_in_addr (s, &attr->extra->originator_id);
else
stream_put_in_addr (s, &from->remote_id);
@@ -1545,15 +1641,16 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc (s, BGP_ATTR_CLUSTER_LIST);
- if (attr->cluster)
+ if (attr->extra->cluster)
{
- stream_putc (s, attr->cluster->length + 4);
+ stream_putc (s, attr->extra->cluster->length + 4);
/* If this peer configuration's parent BGP has cluster_id. */
if (bgp->config & BGP_CONFIG_CLUSTER_ID)
stream_put_in_addr (s, &bgp->cluster_id);
else
stream_put_in_addr (s, &bgp->router_id);
- stream_put (s, attr->cluster->list, attr->cluster->length);
+ stream_put (s, attr->extra->cluster->list,
+ attr->extra->cluster->length);
}
else
{
@@ -1571,22 +1668,25 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
if (p->family == AF_INET6)
{
unsigned long sizep;
-
+ struct attr_extra *attre = attr->extra;
+
+ assert (attr->extra);
+
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
sizep = stream_get_endp (s);
- stream_putc (s, 0); /* Length of this attribute. */
+ stream_putc (s, 0); /* Marker: Attribute length. */
stream_putw (s, AFI_IP6); /* AFI */
stream_putc (s, safi); /* SAFI */
- stream_putc (s, attr->mp_nexthop_len);
+ stream_putc (s, attre->mp_nexthop_len);
- if (attr->mp_nexthop_len == 16)
- stream_put (s, &attr->mp_nexthop_global, 16);
- else if (attr->mp_nexthop_len == 32)
+ if (attre->mp_nexthop_len == 16)
+ stream_put (s, &attre->mp_nexthop_global, 16);
+ else if (attre->mp_nexthop_len == 32)
{
- stream_put (s, &attr->mp_nexthop_global, 16);
- stream_put (s, &attr->mp_nexthop_local, 16);
+ stream_put (s, &attre->mp_nexthop_global, 16);
+ stream_put (s, &attre->mp_nexthop_local, 16);
}
/* SNPA */
@@ -1607,7 +1707,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
sizep = stream_get_endp (s);
- stream_putc (s, 0); /* Length of this attribute. */
+ stream_putc (s, 0); /* Marker: Attribute Length. */
stream_putw (s, AFI_IP); /* AFI */
stream_putc (s, SAFI_MULTICAST); /* SAFI */
@@ -1638,7 +1738,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
stream_putc (s, 12);
stream_putl (s, 0);
stream_putl (s, 0);
- stream_put (s, &attr->mp_nexthop_global_in, 4);
+ stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
/* SNPA */
stream_putc (s, 0);
@@ -1657,21 +1757,26 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
&& (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
{
- if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
+ struct attr_extra *attre = attr->extra;
+
+ assert (attre);
+
+ if (peer_sort (peer) == BGP_PEER_IBGP
+ || peer_sort (peer) == BGP_PEER_CONFED)
{
- if (attr->ecommunity->size * 8 > 255)
+ if (attre->ecommunity->size * 8 > 255)
{
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putw (s, attr->ecommunity->size * 8);
+ stream_putw (s, attre->ecommunity->size * 8);
}
else
{
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putc (s, attr->ecommunity->size * 8);
+ stream_putc (s, attre->ecommunity->size * 8);
}
- stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
+ stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
}
else
{
@@ -1680,9 +1785,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
int ecom_tr_size = 0;
int i;
- for (i = 0; i < attr->ecommunity->size; i++)
+ for (i = 0; i < attre->ecommunity->size; i++)
{
- pnt = attr->ecommunity->val + (i * 8);
+ pnt = attre->ecommunity->val + (i * 8);
tbit = *pnt;
if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
@@ -1706,9 +1811,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
stream_putc (s, ecom_tr_size * 8);
}
- for (i = 0; i < attr->ecommunity->size; i++)
+ for (i = 0; i < attre->ecommunity->size; i++)
{
- pnt = attr->ecommunity->val + (i * 8);
+ pnt = attre->ecommunity->val + (i * 8);
tbit = *pnt;
if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
@@ -1721,8 +1826,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
}
/* Unknown transit attribute. */
- if (attr->transit)
- stream_put (s, attr->transit->val, attr->transit->length);
+ if (attr->extra && attr->extra->transit)
+ stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
/* Return total size of attribute. */
return stream_get_endp (s) - cp;
@@ -1869,11 +1974,12 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
/* Aggregator. */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
{
+ 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->aggregator_as);
- stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+ stream_putw (s, attr->extra->aggregator_as);
+ stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
}
/* Community attribute. */
@@ -1896,25 +2002,26 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
#ifdef HAVE_IPV6
/* Add a MP_NLRI attribute to dump the IPv6 next hop */
- if(prefix != NULL && prefix->family == AF_INET6 &&
- (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) )
+ if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
+ (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
{
int sizep;
-
+ struct attr_extra *attre = attr->extra;
+
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
sizep = stream_get_endp (s);
/* MP header */
- stream_putc (s, 0); /* Length of this attribute. */
+ stream_putc (s, 0); /* Marker: Attribute length. */
stream_putw(s, AFI_IP6); /* AFI */
stream_putc(s, SAFI_UNICAST); /* SAFI */
/* Next hop */
- stream_putc(s, attr->mp_nexthop_len);
- stream_put(s, &attr->mp_nexthop_global, 16);
- if(attr->mp_nexthop_len == 32)
- stream_put(s, &attr->mp_nexthop_local, 16);
+ stream_putc(s, attre->mp_nexthop_len);
+ stream_put(s, &attre->mp_nexthop_global, 16);
+ if (attre->mp_nexthop_len == 32)
+ stream_put(s, &attre->mp_nexthop_local, 16);
/* SNPA */
stream_putc(s, 0);