summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/ChangeLog27
-rw-r--r--bgpd/bgp_attr.c385
-rw-r--r--bgpd/bgp_attr.h59
-rw-r--r--bgpd/bgp_damp.c32
-rw-r--r--bgpd/bgp_debug.c39
-rw-r--r--bgpd/bgp_nexthop.c40
-rw-r--r--bgpd/bgp_packet.c20
-rw-r--r--bgpd/bgp_route.c466
-rw-r--r--bgpd/bgp_route.h37
-rw-r--r--bgpd/bgp_routemap.c53
-rw-r--r--bgpd/bgp_snmp.c10
-rw-r--r--bgpd/bgp_vty.c10
-rw-r--r--bgpd/bgp_zebra.c26
-rw-r--r--lib/ChangeLog4
-rw-r--r--lib/memtypes.c4
15 files changed, 786 insertions, 426 deletions
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
index d5822fac..ed606494 100644
--- a/bgpd/ChangeLog
+++ b/bgpd/ChangeLog
@@ -1,5 +1,30 @@
-2007-04-22 Sebastien Tandel <sebastien@tandel.be>
+2007-05-03 Paul Jakma <paul.jakma@sun.com>
+
+ * bgp_route.h: (struct info) Move less frequently used
+ fields to a lazily allocated struct info_extra.
+ Export bgp_info_extra_get
+ * bgp_route.c: (bgp_info_extra_new) allocate extra
+ (bgp_info_extra_free) Free damp info and the info_extra.
+ (bgp_info_extra_get) Retrieve the info_extra of a struct
+ info, allocating as required.
+ (generally) adjust to use info->extra
+ * bgp_damp.c: (generally) use bgp_info_extra_get to access
+ dampinfo
+ * bgp_attr.h: Move rarely allocated attributes from struct attr
+ to a struct attr_extra, for a substantial saving in size of
+ struct attr.
+ * bgp_attr.c: (bgp_attr_extra_{new,free}), new, self-explanatory.
+ (bgp_attr_extra_get) Get the attr_extra for a given struct
+ attr, allocating it if needs be.
+ (bgp_attr_dup) Shallow copy the struct attr and its attr_extra.
+ (generally) adjust to know about attr->extra.
+ * bgp_debug.c: (bgp_dump_attr) ditto
+ * bgp_vty.c: (show_bgp_memory) print attr and info extra sizes.
+ * bgp_nexthop.c: (generally) adjust to know about attr->extra
+ and info->extra.
+ * bgp_{packet,routemap,snmp,zebra}.c: ditto
+2007-04-22 Sebastien Tandel <sebastien@tandel.be>
* bgp_advertise.c : (baa_hash_alloc, baa_hash_key, baa_hash_cmp)
conforms to quagga hash API. Defines _hash_[alloc|key|cmp] with
void * arguments as defined by the API.
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);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 0734bc27..ac14947f 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -45,24 +45,20 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* BGP attribute header must bigger than 2. */
#define BGP_ATTR_MIN_LEN 2 /* Attribute flag and type. */
-
#define BGP_ATTR_DEFAULT_WEIGHT 32768
-/* BGP attribute structure. */
-struct attr
+/* Additional/uncommon BGP attributes.
+ * lazily allocated as and when a struct attr
+ * requires it.
+ */
+struct attr_extra
{
- /* Attributes. */
+ /* Multi-Protocol Nexthop, AFI IPv6 */
#ifdef HAVE_IPV6
struct in6_addr mp_nexthop_global;
struct in6_addr mp_nexthop_local;
#endif /* HAVE_IPV6 */
- /* AS Path structure */
- struct aspath *aspath;
-
- /* Community structure */
- struct community *community;
-
/* Extended Communities attribute. */
struct ecommunity *ecommunity;
@@ -72,6 +68,37 @@ struct attr
/* Unknown transitive attribute. */
struct transit *transit;
+ struct in_addr mp_nexthop_global_in;
+ struct in_addr mp_nexthop_local_in;
+
+ /* Aggregator Router ID attribute */
+ struct in_addr aggregator_addr;
+
+ /* Route Reflector Originator attribute */
+ struct in_addr originator_id;
+
+ /* Local weight, not actually an attribute */
+ u_int32_t weight;
+
+ /* Aggregator ASN */
+ as_t aggregator_as;
+
+ /* MP Nexthop length */
+ u_char mp_nexthop_len;
+};
+
+/* BGP core attribute structure. */
+struct attr
+{
+ /* AS Path structure */
+ struct aspath *aspath;
+
+ /* Community structure */
+ struct community *community;
+
+ /* Lazily allocated pointer to extra attributes */
+ struct attr_extra *extra;
+
/* Reference count of this attribute. */
unsigned long refcnt;
@@ -82,14 +109,9 @@ struct attr
struct in_addr nexthop;
u_int32_t med;
u_int32_t local_pref;
- struct in_addr 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;
+
+ /* Path origin attribute */
u_char origin;
- u_char mp_nexthop_len;
};
/* Router Reflector related structure. */
@@ -115,6 +137,9 @@ extern void bgp_attr_init (void);
extern int bgp_attr_parse (struct peer *, struct attr *, bgp_size_t,
struct bgp_nlri *, struct bgp_nlri *);
extern int bgp_attr_check (struct peer *, struct attr *);
+extern struct attr_extra *bgp_attr_extra_get (struct attr *);
+extern void bgp_attr_extra_free (struct attr *);
+extern void bgp_attr_dup (struct attr *, struct attr *);
extern struct attr *bgp_attr_intern (struct attr *attr);
extern void bgp_attr_unintern (struct attr *);
extern void bgp_attr_flush (struct attr *);
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 8ba39b65..5a7c9aaa 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -178,14 +178,15 @@ bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn,
afi_t afi, safi_t safi, int attr_change)
{
time_t t_now;
- struct bgp_damp_info *bdi;
+ struct bgp_damp_info *bdi = NULL;
double last_penalty = 0;
t_now = time (NULL);
/* Processing Unreachable Messages. */
- bdi = binfo->damp_info;
-
+ if (binfo->extra)
+ bdi = binfo->extra->damp_info;
+
if (bdi == NULL)
{
/* If there is no previous stability history. */
@@ -205,7 +206,7 @@ bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn,
bdi->index = -1;
bdi->afi = afi;
bdi->safi = safi;
- binfo->damp_info = bdi;
+ (bgp_info_extra_get (binfo))->damp_info = bdi;
BGP_DAMP_LIST_ADD (damp, bdi);
}
else
@@ -264,8 +265,7 @@ bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn,
struct bgp_damp_info *bdi;
int status;
- bdi = binfo->damp_info;
- if (! bdi)
+ if (!binfo->extra || !((bdi = binfo->extra->damp_info)))
return BGP_DAMP_USED;
t_now = time (NULL);
@@ -303,9 +303,11 @@ bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi)
{
time_t t_now, t_diff;
struct bgp_damp_info *bdi;
-
+
+ assert (binfo->extra && binfo->extra->damp_info);
+
t_now = time (NULL);
- bdi = binfo->damp_info;
+ bdi = binfo->extra->damp_info;
if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
{
@@ -353,7 +355,7 @@ bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw)
return;
binfo = bdi->binfo;
- binfo->damp_info = NULL;
+ binfo->extra->damp_info = NULL;
if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
bgp_reuse_list_delete (bdi);
@@ -590,8 +592,11 @@ bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo)
char timebuf[BGP_UPTIME_LEN];
int penalty;
+ if (!binfo->extra)
+ return;
+
/* BGP dampening information. */
- bdi = binfo->damp_info;
+ bdi = binfo->extra->damp_info;
/* If dampening is not enabled or there is no dampening information,
return immediately. */
@@ -622,9 +627,12 @@ bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo)
time_t t_now, t_diff;
char timebuf[BGP_UPTIME_LEN];
int penalty;
-
+
+ if (!binfo->extra)
+ return NULL;
+
/* BGP dampening information. */
- bdi = binfo->damp_info;
+ bdi = binfo->extra->damp_info;
/* If dampening is not enabled or there is no dampening information,
return immediately. */
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 1986b35b..60284a2d 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -176,20 +176,22 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
bgp_origin_str[attr->origin]);
#ifdef HAVE_IPV6
- {
- char addrbuf[BUFSIZ];
-
- /* Add MP case. */
- if (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32)
- snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s",
- inet_ntop (AF_INET6, &attr->mp_nexthop_global,
- addrbuf, BUFSIZ));
-
- if (attr->mp_nexthop_len == 32)
- snprintf (buf + strlen (buf), size - strlen (buf), "(%s)",
- inet_ntop (AF_INET6, &attr->mp_nexthop_local,
- addrbuf, BUFSIZ));
- }
+ if (attr->extra)
+ {
+ char addrbuf[BUFSIZ];
+
+ /* Add MP case. */
+ if (attr->extra->mp_nexthop_len == 16
+ || attr->extra->mp_nexthop_len == 32)
+ snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s",
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
+ addrbuf, BUFSIZ));
+
+ if (attr->extra->mp_nexthop_len == 32)
+ snprintf (buf + strlen (buf), size - strlen (buf), "(%s)",
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local,
+ addrbuf, BUFSIZ));
+ }
#endif /* HAVE_IPV6 */
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
@@ -209,20 +211,21 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
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));
+ attr->extra->aggregator_as,
+ inet_ntoa (attr->extra->aggregator_addr));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)))
snprintf (buf + strlen (buf), size - strlen (buf), ", originator %s",
- inet_ntoa (attr->originator_id));
+ inet_ntoa (attr->extra->originator_id));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)))
{
int i;
snprintf (buf + strlen (buf), size - strlen (buf), ", clusterlist");
- for (i = 0; i < attr->cluster->length / 4; i++)
+ for (i = 0; i < attr->extra->cluster->length / 4; i++)
snprintf (buf + strlen (buf), size - strlen (buf), " %s",
- inet_ntoa (attr->cluster->list[i]));
+ inet_ntoa (attr->extra->cluster->list[i]));
}
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 50ae74e4..4dd5d946 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -196,15 +196,15 @@ bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr)
#ifdef HAVE_IPV6
else if (afi == AFI_IP6)
{
- if (attr->mp_nexthop_len == 32)
+ if (attr->extra->mp_nexthop_len == 32)
return 1;
- else if (attr->mp_nexthop_len == 16)
+ else if (attr->extra->mp_nexthop_len == 16)
{
- if (IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global))
+ if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global))
return 1;
rn = bgp_node_match_ipv6 (bgp_connected_table[AFI_IP6],
- &attr->mp_nexthop_global);
+ &attr->extra->mp_nexthop_global);
if (rn)
{
bgp_unlock_node (rn);
@@ -230,21 +230,22 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
/* If lookup is not enabled, return valid. */
if (zlookup->sock < 0)
{
- ri->igpmetric = 0;
+ if (ri->extra)
+ ri->extra->igpmetric = 0;
return 1;
}
/* Only check IPv6 global address only nexthop. */
attr = ri->attr;
- if (attr->mp_nexthop_len != 16
- || IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global))
+ if (attr->extra->mp_nexthop_len != 16
+ || IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global))
return 1;
memset (&p, 0, sizeof (struct prefix));
p.family = AF_INET6;
p.prefixlen = IPV6_MAX_BITLEN;
- p.u.prefix6 = attr->mp_nexthop_global;
+ p.u.prefix6 = attr->extra->mp_nexthop_global;
/* IBGP or ebgp-multihop */
rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p);
@@ -256,7 +257,7 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
}
else
{
- bnc = zlookup_query_ipv6 (&attr->mp_nexthop_global);
+ bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global);
if (bnc)
{
struct bgp_table *old;
@@ -296,10 +297,10 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
if (metricchanged)
*metricchanged = bnc->metricchanged;
- if (bnc->valid)
- ri->igpmetric = bnc->metric;
- else
- ri->igpmetric = 0;
+ if (bnc->valid && bnc->metric)
+ (bgp_info_extra_get (ri))->igpmetric = bnc->metric;
+ else if (ri->extra)
+ ri->extra->igpmetric = 0;
return bnc->valid;
}
@@ -318,7 +319,8 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
/* If lookup is not enabled, return valid. */
if (zlookup->sock < 0)
{
- ri->igpmetric = 0;
+ if (ri->extra)
+ ri->extra->igpmetric = 0;
return 1;
}
@@ -384,10 +386,10 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
if (metricchanged)
*metricchanged = bnc->metricchanged;
- if (bnc->valid)
- ri->igpmetric = bnc->metric;
- else
- ri->igpmetric = 0;
+ if (bnc->valid && bnc->metric)
+ (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
+ else if (ri->extra)
+ ri->extra->igpmetric = 0;
return bnc->valid;
}
@@ -490,7 +492,7 @@ bgp_scan (afi_t afi, safi_t safi)
if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_DAMPENING)
- && bi->damp_info )
+ && bi->extra && bi->extra->damp_info )
if (bgp_damp_scan (bi, afi, SAFI_UNICAST))
bgp_aggregate_increment (bgp, &rn->p, bi,
afi, SAFI_UNICAST);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 9859e50b..26532011 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -177,9 +177,9 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
- if (binfo)
+ if (binfo && binfo->extra)
{
- tag = binfo->tag;
+ tag = binfo->extra->tag;
from = binfo->peer;
}
@@ -1706,12 +1706,16 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
aspath_unintern (attr.aspath);
if (attr.community)
community_unintern (attr.community);
- if (attr.ecommunity)
- ecommunity_unintern (attr.ecommunity);
- if (attr.cluster)
- cluster_unintern (attr.cluster);
- if (attr.transit)
- transit_unintern (attr.transit);
+ if (attr.extra)
+ {
+ if (attr.extra->ecommunity)
+ ecommunity_unintern (attr.extra->ecommunity);
+ if (attr.extra->cluster)
+ cluster_unintern (attr.extra->cluster);
+ if (attr.extra->transit)
+ transit_unintern (attr.extra->transit);
+ bgp_attr_extra_free (&attr);
+ }
/* If peering is stopped due to some reason, do not generate BGP
event. */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index c33c596e..db0f3a74 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -89,6 +89,42 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
return rn;
}
+/* Allocate bgp_info_extra */
+static struct bgp_info_extra *
+bgp_info_extra_new (void)
+{
+ struct bgp_info_extra *new;
+ new = XCALLOC (MTYPE_BGP_ROUTE_EXTRA, sizeof (struct bgp_info_extra));
+ return new;
+}
+
+static void
+bgp_info_extra_free (struct bgp_info_extra **extra)
+{
+ if (extra && *extra)
+ {
+ if ((*extra)->damp_info)
+ bgp_damp_info_free ((*extra)->damp_info, 0);
+
+ (*extra)->damp_info = NULL;
+
+ XFREE (MTYPE_BGP_ROUTE_EXTRA, *extra);
+
+ *extra = NULL;
+ }
+}
+
+/* Get bgp_info extra information for the given bgp_info, lazy allocated
+ * if required.
+ */
+struct bgp_info_extra *
+bgp_info_extra_get (struct bgp_info *ri)
+{
+ if (!ri->extra)
+ ri->extra = bgp_info_extra_new();
+ return ri->extra;
+}
+
/* Allocate new bgp info structure. */
static struct bgp_info *
bgp_info_new ()
@@ -107,9 +143,8 @@ bgp_info_free (struct bgp_info *binfo)
{
if (binfo->attr)
bgp_attr_unintern (binfo->attr);
-
- if (binfo->damp_info)
- bgp_damp_info_free (binfo->damp_info, 0);
+
+ bgp_info_extra_free (&binfo->extra);
peer_unlock (binfo->peer); /* bgp_info peer reference */
@@ -292,6 +327,8 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
u_int32_t exist_pref;
u_int32_t new_med;
u_int32_t exist_med;
+ u_int32_t new_weight = 0;
+ u_int32_t exist_weight = 0;
struct in_addr new_id;
struct in_addr exist_id;
int new_cluster;
@@ -307,9 +344,13 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
return 1;
/* 1. Weight check. */
- if (new->attr->weight > exist->attr->weight)
+ if (new->attr->extra)
+ new_weight = new->attr->extra->weight;
+ if (exist->attr->extra)
+ exist_weight = exist->attr->extra->weight;
+ if (new_weight > exist_weight)
return 1;
- if (new->attr->weight < exist->attr->weight)
+ if (new_weight < exist_weight)
return 0;
/* 2. Local preference check. */
@@ -418,10 +459,16 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
return 0;
/* 8. IGP metric check. */
- if (new->igpmetric < exist->igpmetric)
- return 1;
- if (new->igpmetric > exist->igpmetric)
- return 0;
+ if (new->extra || exist->extra)
+ {
+ uint32_t newm = (new->extra ? new->extra->igpmetric : 0);
+ uint32_t existm = (exist->extra ? exist->extra->igpmetric : 0);
+
+ if (newm < existm)
+ return 1;
+ if (newm > existm)
+ return 0;
+ }
/* 9. Maximum path check. */
@@ -441,11 +488,11 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
/* 11. Rourter-ID comparision. */
if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- new_id.s_addr = new->attr->originator_id.s_addr;
+ new_id.s_addr = new->attr->extra->originator_id.s_addr;
else
new_id.s_addr = new->peer->remote_id.s_addr;
if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- exist_id.s_addr = exist->attr->originator_id.s_addr;
+ exist_id.s_addr = exist->attr->extra->originator_id.s_addr;
else
exist_id.s_addr = exist->peer->remote_id.s_addr;
@@ -456,11 +503,11 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
/* 12. Cluster length comparision. */
if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
- new_cluster = new->attr->cluster->length;
+ new_cluster = new->attr->extra->cluster->length;
else
new_cluster = 0;
if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
- exist_cluster = exist->attr->cluster->length;
+ exist_cluster = exist->attr->extra->cluster->length;
else
exist_cluster = 0;
@@ -556,14 +603,14 @@ bgp_cluster_filter (struct peer *peer, struct attr *attr)
{
struct in_addr cluster_id;
- if (attr->cluster)
+ if (attr->extra && attr->extra->cluster)
{
if (peer->bgp->config & BGP_CONFIG_CLUSTER_ID)
cluster_id = peer->bgp->cluster_id;
else
cluster_id = peer->bgp->router_id;
- if (cluster_loop_check (attr->cluster, cluster_id))
+ if (cluster_loop_check (attr->extra->cluster, cluster_id))
return 1;
}
return 0;
@@ -580,7 +627,8 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
filter = &peer->filter[afi][safi];
/* Apply default weight value. */
- attr->weight = peer->weight;
+ if (peer->weight)
+ (bgp_attr_extra_get (attr))->weight = peer->weight;
/* Route map apply. */
if (ROUTE_MAP_IN_NAME (filter))
@@ -651,7 +699,8 @@ bgp_import_modifier (struct peer *rsclient, struct peer *peer,
filter = &rsclient->filter[afi][safi];
/* Apply default weight value. */
- attr->weight = peer->weight;
+ if (peer->weight)
+ (bgp_attr_extra_get (attr))->weight = peer->weight;
/* Route map apply. */
if (ROUTE_MAP_IMPORT_NAME (filter))
@@ -716,7 +765,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
#endif
/* Aggregate-address suppress check. */
- if (ri->suppress)
+ if (ri->extra && ri->extra->suppress)
if (! UNSUPPRESS_MAP_NAME (filter))
return 0;
@@ -746,7 +795,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
peer's id. */
if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
{
- if (IPV4_ADDR_SAME (&peer->remote_id, &ri->attr->originator_id))
+ if (IPV4_ADDR_SAME (&peer->remote_id, &ri->attr->extra->originator_id))
{
if (BGP_DEBUG (filter, FILTER))
zlog (peer->log, LOG_DEBUG,
@@ -836,8 +885,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
}
/* For modify attribute, copy it to temporary structure. */
- *attr = *ri->attr;
-
+ bgp_attr_dup (attr, ri->attr);
+
/* If local-preference is not set. */
if ((peer_sort (peer) == BGP_PEER_IBGP
|| peer_sort (peer) == BGP_PEER_CONFED)
@@ -862,7 +911,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
&& ((p->family == AF_INET && attr->nexthop.s_addr)
#ifdef HAVE_IPV6
|| (p->family == AF_INET6 &&
- ! IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global))
+ ! IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
#endif /* HAVE_IPV6 */
)))
{
@@ -872,7 +921,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
|| (p->family == AF_INET && attr->nexthop.s_addr == 0)
#ifdef HAVE_IPV6
|| (p->family == AF_INET6 &&
- IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global))
+ IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
#endif /* HAVE_IPV6 */
|| (peer_sort (peer) == BGP_PEER_EBGP
&& bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0))
@@ -881,7 +930,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
if (p->family == AF_INET)
{
if (safi == SAFI_MPLS_VPN)
- memcpy (&attr->mp_nexthop_global_in, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
+ memcpy (&attr->extra->mp_nexthop_global_in, &peer->nexthop.v4,
+ IPV4_MAX_BYTELEN);
else
memcpy (&attr->nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
}
@@ -890,9 +940,9 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
if (p->family == AF_INET6)
{
/* IPv6 global nexthop must be included. */
- memcpy (&attr->mp_nexthop_global, &peer->nexthop.v6_global,
+ memcpy (&attr->extra->mp_nexthop_global, &peer->nexthop.v6_global,
IPV6_MAX_BYTELEN);
- attr->mp_nexthop_len = 16;
+ attr->extra->mp_nexthop_len = 16;
}
#endif /* HAVE_IPV6 */
}
@@ -904,35 +954,35 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
if ( CHECK_FLAG (peer->af_flags[afi][safi],
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) )
{
- if ( IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local) )
- attr->mp_nexthop_len=32;
+ if ( IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_local) )
+ attr->extra->mp_nexthop_len=32;
else
- attr->mp_nexthop_len=16;
+ attr->extra->mp_nexthop_len=16;
}
/* Default nexthop_local treatment for non-RS-Clients */
else
{
/* Link-local address should not be transit to different peer. */
- attr->mp_nexthop_len = 16;
+ attr->extra->mp_nexthop_len = 16;
/* Set link-local address for shared network peer. */
if (peer->shared_network
&& ! IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
{
- memcpy (&attr->mp_nexthop_local, &peer->nexthop.v6_local,
+ memcpy (&attr->extra->mp_nexthop_local, &peer->nexthop.v6_local,
IPV6_MAX_BYTELEN);
- attr->mp_nexthop_len = 32;
+ attr->extra->mp_nexthop_len = 32;
}
/* If bgpd act as BGP-4+ route-reflector, do not send link-local
address.*/
if (reflect)
- attr->mp_nexthop_len = 16;
+ attr->extra->mp_nexthop_len = 16;
/* If BGP-4+ link-local nexthop is not link-local nexthop. */
if (! IN6_IS_ADDR_LINKLOCAL (&peer->nexthop.v6_local))
- attr->mp_nexthop_len = 16;
+ attr->extra->mp_nexthop_len = 16;
}
}
@@ -946,32 +996,36 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
/* Route map & unsuppress-map apply. */
if (ROUTE_MAP_OUT_NAME (filter)
- || ri->suppress)
+ || (ri->extra && ri->extra->suppress) )
{
struct bgp_info info;
struct attr dummy_attr;
info.peer = peer;
info.attr = attr;
+
/* The route reflector is not allowed to modify the attributes
of the reflected IBGP routes. */
if (peer_sort (from) == BGP_PEER_IBGP
&& peer_sort (peer) == BGP_PEER_IBGP)
{
- dummy_attr = *attr;
- info.attr = &dummy_attr;
+ dummy_attr.extra = NULL;
+ bgp_attr_dup (&dummy_attr, attr);
+ info.attr = &dummy_attr;
}
SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT);
- if (ri->suppress)
+ if (ri->extra && ri->extra->suppress)
ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info);
else
ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info);
peer->rmap_type = 0;
-
+
+ bgp_attr_extra_free (&dummy_attr);
+
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (attr);
@@ -1005,7 +1059,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
return 0;
/* Aggregate-address suppress check. */
- if (ri->suppress)
+ if (ri->extra && ri->extra->suppress)
if (! UNSUPPRESS_MAP_NAME (filter))
return 0;
@@ -1025,7 +1079,8 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
peer's id. */
if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
{
- if (IPV4_ADDR_SAME (&rsclient->remote_id, &ri->attr->originator_id))
+ if (IPV4_ADDR_SAME (&rsclient->remote_id,
+ &ri->attr->extra->originator_id))
{
if (BGP_DEBUG (filter, FILTER))
zlog (rsclient->log, LOG_DEBUG,
@@ -1078,7 +1133,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
if ((p->family == AF_INET && attr->nexthop.s_addr == 0)
#ifdef HAVE_IPV6
|| (p->family == AF_INET6 &&
- IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global))
+ IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
#endif /* HAVE_IPV6 */
)
{
@@ -1086,7 +1141,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
if (p->family == AF_INET)
{
if (safi == SAFI_MPLS_VPN)
- memcpy (&attr->mp_nexthop_global_in, &rsclient->nexthop.v4,
+ memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4,
IPV4_MAX_BYTELEN);
else
memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN);
@@ -1096,10 +1151,9 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
if (p->family == AF_INET6)
{
/* IPv6 global nexthop must be included. */
- memcpy (&attr->mp_nexthop_global, &rsclient->nexthop.v6_global,
-
+ memcpy (&attr->extra->mp_nexthop_global, &rsclient->nexthop.v6_global,
IPV6_MAX_BYTELEN);
- attr->mp_nexthop_len = 16;
+ attr->extra->mp_nexthop_len = 16;
}
#endif /* HAVE_IPV6 */
}
@@ -1107,14 +1161,18 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
#ifdef HAVE_IPV6
if (p->family == AF_INET6)
{
+ struct attr_extra *attre = attr->extra;
+
+ assert (attr->extra);
+
/* Left nexthop_local unchanged if so configured. */
if ( CHECK_FLAG (rsclient->af_flags[afi][safi],
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) )
{
- if ( IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local) )
- attr->mp_nexthop_len=32;
+ if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) )
+ attre->mp_nexthop_len=32;
else
- attr->mp_nexthop_len=16;
+ attre->mp_nexthop_len=16;
}
/* Default nexthop_local treatment for RS-Clients */
@@ -1124,23 +1182,23 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
if (rsclient->shared_network && from->shared_network &&
(rsclient->ifindex == from->ifindex))
{
- if ( IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local) )
- attr->mp_nexthop_len=32;
+ if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) )
+ attre->mp_nexthop_len=32;
else
- attr->mp_nexthop_len=16;
+ attre->mp_nexthop_len=16;
}
/* Set link-local address for shared network peer. */
else if (rsclient->shared_network
&& IN6_IS_ADDR_LINKLOCAL (&rsclient->nexthop.v6_local))
{
- memcpy (&attr->mp_nexthop_local, &rsclient->nexthop.v6_local,
+ memcpy (&attre->mp_nexthop_local, &rsclient->nexthop.v6_local,
IPV6_MAX_BYTELEN);
- attr->mp_nexthop_len = 32;
+ attre->mp_nexthop_len = 32;
}
else
- attr->mp_nexthop_len = 16;
+ attre->mp_nexthop_len = 16;
}
}
@@ -1154,14 +1212,14 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
attr->aspath = aspath_empty_get ();
/* Route map & unsuppress-map apply. */
- if (ROUTE_MAP_OUT_NAME (filter) || ri->suppress)
+ if (ROUTE_MAP_OUT_NAME (filter) || (ri->extra && ri->extra->suppress) )
{
info.peer = rsclient;
info.attr = attr;
SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_OUT);
- if (ri->suppress)
+ if (ri->extra && ri->extra->suppress)
ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info);
else
ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info);
@@ -1336,6 +1394,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
struct listnode *node, *nnode;
struct peer *rsclient = rn->table->owner;
+ memset (&attr, 0, sizeof (struct attr));
/* Best path selection. */
bgp_best_selection (bgp, rn, &old_and_new);
new_select = old_and_new.new;
@@ -1378,6 +1437,8 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
bgp_info_reap (rn, old_select);
+ bgp_attr_extra_free (&attr);
+
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return WQ_SUCCESS;
}
@@ -1398,6 +1459,8 @@ bgp_process_main (struct work_queue *wq, void *data)
struct peer *peer;
struct attr attr;
+ memset (&attr, 0, sizeof (struct attr));
+
/* Best path selection. */
bgp_best_selection (bgp, rn, &old_and_new);
old_select = old_and_new.old;
@@ -1453,6 +1516,8 @@ bgp_process_main (struct work_queue *wq, void *data)
if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
bgp_info_reap (rn, old_select);
+ bgp_attr_extra_free (&attr);
+
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return WQ_SUCCESS;
}
@@ -1663,7 +1728,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
{
struct bgp_node *rn;
struct bgp *bgp;
- struct attr new_attr;
+ struct attr new_attr = { 0 };
struct attr *attr_new;
struct attr *attr_new2;
struct bgp_info *ri;
@@ -1671,6 +1736,8 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
const char *reason;
char buf[SU_ADDRSTRLEN];
+ //memset (new_attr, 0, sizeof (struct attr));
+
/* Do not insert announces from a rsclient into its own 'bgp_table'. */
if (peer == rsclient)
return;
@@ -1692,13 +1759,13 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
/* Route reflector originator ID check. */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)
- && IPV4_ADDR_SAME (&rsclient->remote_id, &attr->originator_id))
+ && IPV4_ADDR_SAME (&rsclient->remote_id, &attr->extra->originator_id))
{
reason = "originator is us;";
goto filtered;
}
-
- new_attr = *attr;
+
+ bgp_attr_dup (&new_attr, attr);
/* Apply export policy. */
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) &&
@@ -1709,7 +1776,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
}
attr_new2 = bgp_attr_intern (&new_attr);
-
+
/* Apply import policy. */
if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY)
{
@@ -1735,7 +1802,10 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
goto filtered;
}
}
-
+
+ /* new_attr isn't passed to any functions after here */
+ bgp_attr_extra_free (&new_attr);
+
/* If the update is implicit withdraw. */
if (ri)
{
@@ -1781,7 +1851,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
/* Update MPLS tag. */
if (safi == SAFI_MPLS_VPN)
- memcpy (ri->tag, tag, 3);
+ memcpy ((bgp_info_extra_get (ri))->tag, tag, 3);
bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
@@ -1811,7 +1881,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
/* Update MPLS tag. */
if (safi == SAFI_MPLS_VPN)
- memcpy (new->tag, tag, 3);
+ memcpy ((bgp_info_extra_get (new))->tag, tag, 3);
bgp_info_set_flag (rn, new, BGP_INFO_VALID);
@@ -1823,7 +1893,9 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
/* Process change. */
bgp_process (bgp, rn, afi, safi);
-
+
+ bgp_attr_extra_free (&new_attr);
+
return;
filtered:
@@ -1840,7 +1912,10 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
bgp_rib_remove (rn, ri, peer, afi, safi);
bgp_unlock_node (rn);
-
+
+ if (new_attr.extra)
+ bgp_attr_extra_free (&new_attr);
+
return;
}
@@ -1885,7 +1960,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
int aspath_loop_count = 0;
struct bgp_node *rn;
struct bgp *bgp;
- struct attr new_attr;
+ struct attr new_attr = { 0 };
struct attr *attr_new;
struct bgp_info *ri;
struct bgp_info *new;
@@ -1894,7 +1969,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp = peer->bgp;
rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);
-
+
/* When peer's soft reconfiguration enabled. Record input packet in
Adj-RIBs-In. */
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)
@@ -1931,7 +2006,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Route reflector originator ID check. */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)
- && IPV4_ADDR_SAME (&bgp->router_id, &attr->originator_id))
+ && IPV4_ADDR_SAME (&bgp->router_id, &attr->extra->originator_id))
{
reason = "originator is us;";
goto filtered;
@@ -1952,7 +2027,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
/* Apply incoming route-map. */
- new_attr = *attr;
+ bgp_attr_dup (&new_attr, attr);
if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY)
{
@@ -2032,6 +2107,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
+ bgp_attr_extra_free (&new_attr);
+
return 0;
}
@@ -2081,7 +2158,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Update MPLS tag. */
if (safi == SAFI_MPLS_VPN)
- memcpy (ri->tag, tag, 3);
+ memcpy ((bgp_info_extra_get (ri))->tag, tag, 3);
/* Update bgp route dampening information. */
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
@@ -2092,6 +2169,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
if (ret == BGP_DAMP_SUPPRESSED)
{
bgp_unlock_node (rn);
+ bgp_attr_extra_free (&new_attr);
return 0;
}
}
@@ -2116,6 +2194,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp_process (bgp, rn, afi, safi);
bgp_unlock_node (rn);
+ bgp_attr_extra_free (&new_attr);
+
return 0;
}
@@ -2138,7 +2218,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Update MPLS tag. */
if (safi == SAFI_MPLS_VPN)
- memcpy (new->tag, tag, 3);
+ memcpy ((bgp_info_extra_get (new))->tag, tag, 3);
/* Nexthop reachability check. */
if ((afi == AFI_IP || afi == AFI_IP6)
@@ -2164,6 +2244,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* route_node_get lock */
bgp_unlock_node (rn);
+ bgp_attr_extra_free (&new_attr);
+
/* If maximum prefix count is configured and current prefix
count exeed it. */
if (bgp_maximum_prefix_overflow (peer, afi, safi, 0))
@@ -2188,7 +2270,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp_rib_remove (rn, ri, peer, afi, safi);
bgp_unlock_node (rn);
-
+
+ bgp_attr_extra_free (&new_attr);
+
return 0;
}
@@ -2280,15 +2364,18 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
{
struct bgp *bgp;
struct attr attr;
- struct aspath *aspath;
+ struct aspath *aspath = { 0 };
struct prefix p;
struct bgp_info binfo;
struct peer *from;
int ret = RMAP_DENYMATCH;
-
+
+ if (afi != AFI_IP || afi != AFI_IP6)
+ return;
+
bgp = peer->bgp;
from = bgp->peer_self;
-
+
bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
aspath = attr.aspath;
attr.local_pref = bgp->default_local_pref;
@@ -2299,26 +2386,30 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
#ifdef HAVE_IPV6
else if (afi == AFI_IP6)
{
+ struct attr_extra *ae;
+ attr.extra = NULL;
+
+ ae = bgp_attr_extra_get (&attr);
+ attr.extra = ae;
+
str2prefix ("::/0", &p);
/* IPv6 global nexthop must be included. */
- memcpy (&attr.mp_nexthop_global, &peer->nexthop.v6_global,
+ memcpy (&ae->mp_nexthop_global, &peer->nexthop.v6_global,
IPV6_MAX_BYTELEN);
- attr.mp_nexthop_len = 16;
+ ae->mp_nexthop_len = 16;
/* If the peer is on shared nextwork and we have link-local
nexthop set it. */
if (peer->shared_network
&& !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
{
- memcpy (&attr.mp_nexthop_local, &peer->nexthop.v6_local,
+ memcpy (&ae->mp_nexthop_local, &peer->nexthop.v6_local,
IPV6_MAX_BYTELEN);
- attr.mp_nexthop_len = 32;
+ ae->mp_nexthop_len = 32;
}
}
#endif /* HAVE_IPV6 */
- else
- return;
if (peer->default_rmap[afi][safi].name)
{
@@ -2350,7 +2441,8 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE);
bgp_default_update_send (peer, &attr, afi, safi, from);
}
-
+
+ bgp_attr_extra_free (&attr);
aspath_unintern (aspath);
}
@@ -2361,7 +2453,9 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
struct bgp_node *rn;
struct bgp_info *ri;
struct attr attr;
-
+
+ memset (&attr, 0, sizeof (struct attr));
+
if (! table)
table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi];
@@ -2379,6 +2473,8 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri);
else
bgp_adj_out_unset (rn, peer, &rn->p, afi, safi);
+
+ bgp_attr_extra_free (&attr);
}
}
@@ -3028,15 +3124,16 @@ bgp_static_withdraw_rsclient (struct bgp *bgp, struct peer *rsclient,
static void
bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
- struct bgp_static *bgp_static, afi_t afi, safi_t safi)
+ struct bgp_static *bgp_static,
+ afi_t afi, safi_t safi)
{
struct bgp_node *rn;
struct bgp_info *ri;
struct bgp_info *new;
struct bgp_info info;
- struct attr new_attr;
struct attr *attr_new;
- struct attr attr;
+ struct attr attr = {0 };
+ struct attr new_attr = { .extra = 0 };
struct bgp *bgp;
int ret;
char buf[SU_ADDRSTRLEN];
@@ -3055,14 +3152,13 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
attr.med = bgp_static->igpmetric;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
- new_attr = attr;
-
/* Apply network route-map for export to this rsclient. */
if (bgp_static->rmap.name)
{
+ struct attr attr_tmp = attr;
info.peer = rsclient;
- info.attr = &new_attr;
-
+ info.attr = &attr_tmp;
+
SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT);
SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_NETWORK);
@@ -3073,25 +3169,27 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
if (ret == RMAP_DENYMATCH)
{
/* Free uninterned attribute. */
- bgp_attr_flush (&new_attr);
+ bgp_attr_flush (&attr_tmp);
/* Unintern original. */
aspath_unintern (attr.aspath);
bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);
-
+ bgp_attr_extra_free (&attr);
+
return;
}
- attr_new = bgp_attr_intern (&new_attr);
+ attr_new = bgp_attr_intern (&attr_tmp);
}
else
attr_new = bgp_attr_intern (&attr);
-
+
new_attr = *attr_new;
-
+
SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK);
- if (bgp_import_modifier (rsclient, bgp->peer_self, p, &new_attr, afi, safi) == RMAP_DENY)
-{
+ if (bgp_import_modifier (rsclient, bgp->peer_self, p, &new_attr, afi, safi)
+ == RMAP_DENY)
+ {
/* This BGP update is filtered. Log the reason then update BGP entry. */
if (BGP_DEBUG (update, UPDATE_IN))
zlog (rsclient->log, LOG_DEBUG,
@@ -3103,11 +3201,12 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp_attr_unintern (attr_new);
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);
return;
- }
+ }
bgp->peer_self->rmap_type = 0;
@@ -3127,6 +3226,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
return;
}
else
@@ -3145,10 +3245,11 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp_process (bgp, rn, afi, safi);
bgp_unlock_node (rn);
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
return;
+ }
}
-}
-
+
/* Make new BGP info. */
new = bgp_info_new ();
new->type = ZEBRA_ROUTE_BGP;
@@ -3169,6 +3270,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
/* Unintern original. */
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
}
static void
@@ -3179,8 +3281,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
struct bgp_info *ri;
struct bgp_info *new;
struct bgp_info info;
- struct attr attr;
- struct attr attr_tmp;
+ struct attr attr = { 0 };
struct attr *attr_new;
int ret;
@@ -3199,7 +3300,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
/* Apply route-map. */
if (bgp_static->rmap.name)
{
- attr_tmp = attr;
+ struct attr attr_tmp = attr;
info.peer = bgp->peer_self;
info.attr = &attr_tmp;
@@ -3216,6 +3317,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
/* Unintern original. */
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
bgp_static_withdraw (bgp, p, afi, safi);
return;
}
@@ -3237,6 +3339,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
return;
}
else
@@ -3258,6 +3361,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
bgp_process (bgp, rn, afi, safi);
bgp_unlock_node (rn);
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
return;
}
}
@@ -3285,6 +3389,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
/* Unintern original. */
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
}
void
@@ -3309,7 +3414,7 @@ bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
{
struct bgp_node *rn;
struct bgp_info *new;
-
+
rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);
/* Make new BGP info. */
@@ -3320,7 +3425,8 @@ bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP);
SET_FLAG (new->flags, BGP_INFO_VALID);
new->uptime = time (NULL);
- memcpy (new->tag, tag, 3);
+ new->extra = bgp_info_extra_new();
+ memcpy (new->extra->tag, tag, 3);
/* Aggregate address increment. */
bgp_aggregate_increment (bgp, p, new, afi, safi);
@@ -4184,7 +4290,7 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
{
if (aggregate->summary_only)
{
- ri->suppress++;
+ (bgp_info_extra_get (ri))->suppress++;
bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
match++;
}
@@ -4230,7 +4336,7 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
aggregate->count++;
if (aggregate->summary_only)
- rinew->suppress++;
+ (bgp_info_extra_get (rinew))->suppress++;
if (aggregate->as_set)
{
@@ -4387,7 +4493,7 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
route announcement. */
if (aggregate->summary_only)
{
- ri->suppress++;
+ (bgp_info_extra_get (ri))->suppress++;
bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
match++;
}
@@ -4482,11 +4588,11 @@ bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,
if (ri->sub_type != BGP_ROUTE_AGGREGATE)
{
- if (aggregate->summary_only)
+ if (aggregate->summary_only && ri->extra)
{
- ri->suppress--;
+ ri->extra->suppress--;
- if (ri->suppress == 0)
+ if (ri->extra->suppress == 0)
{
bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
match++;
@@ -4496,7 +4602,7 @@ bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,
}
}
- /* If this node is suppressed, process the change. */
+ /* If this node was suppressed, process the change. */
if (match)
bgp_process (bgp, rn, afi, safi);
}
@@ -4968,8 +5074,8 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
struct bgp_info *bi;
struct bgp_info info;
struct bgp_node *bn;
- struct attr attr;
- struct attr attr_new;
+ struct attr attr = { 0 };
+ struct attr attr_new = { 0 };
struct attr *new_attr;
afi_t afi;
int ret;
@@ -4989,7 +5095,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
if (bgp->redist[afi][type])
{
/* Copy attribute for modification. */
- attr_new = attr;
+ bgp_attr_dup (&attr_new, &attr);
if (bgp->redist_metric_flag[afi][type])
attr_new.med = bgp->redist_metric[afi][type];
@@ -5011,17 +5117,22 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
{
/* Free uninterned attribute. */
bgp_attr_flush (&attr_new);
-
+ bgp_attr_extra_free (&attr_new);
+
/* Unintern original. */
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
bgp_redistribute_delete (p, type);
return;
}
}
- bn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST, p, NULL);
+ bn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST],
+ afi, SAFI_UNICAST, p, NULL);
+
new_attr = bgp_attr_intern (&attr_new);
-
+ bgp_attr_extra_free (&attr_new);
+
for (bi = bn->info; bi; bi = bi->next)
if (bi->peer == bgp->peer_self
&& bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
@@ -5034,6 +5145,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
{
bgp_attr_unintern (new_attr);
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
bgp_unlock_node (bn);
return;
}
@@ -5056,6 +5168,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
bgp_process (bgp, bn, afi, SAFI_UNICAST);
bgp_unlock_node (bn);
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
return;
}
}
@@ -5077,6 +5190,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
/* Unintern original. */
aspath_unintern (attr.aspath);
+ bgp_attr_extra_free (&attr);
}
void
@@ -5186,7 +5300,7 @@ route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo)
vty_out (vty, "R");
else if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE))
vty_out (vty, "S");
- else if (binfo->suppress)
+ else if (binfo->extra && binfo->extra->suppress)
vty_out (vty, "s");
else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
vty_out (vty, "*");
@@ -5233,7 +5347,8 @@ route_vty_out (struct vty *vty, struct prefix *p,
if (p->family == AF_INET)
{
if (safi == SAFI_MPLS_VPN)
- vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in));
+ vty_out (vty, "%-16s",
+ inet_ntoa (attr->extra->mp_nexthop_global_in));
else
vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
}
@@ -5244,7 +5359,8 @@ route_vty_out (struct vty *vty, struct prefix *p,
char buf[BUFSIZ];
len = vty_out (vty, "%s",
- inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ));
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
+ buf, BUFSIZ));
len = 16 - len;
if (len < 1)
vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " ");
@@ -5263,7 +5379,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
else
vty_out (vty, " ");
- vty_out (vty, "%7u ",attr->weight);
+ vty_out (vty, "%7u ", (attr->extra ? attr->extra->weight : 0));
/* Print aspath */
if (attr->aspath)
@@ -5294,7 +5410,8 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
if (p->family == AF_INET)
{
if (safi == SAFI_MPLS_VPN)
- vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in));
+ vty_out (vty, "%-16s",
+ inet_ntoa (attr->extra->mp_nexthop_global_in));
else
vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
}
@@ -5303,9 +5420,12 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
{
int len;
char buf[BUFSIZ];
+
+ assert (attr->extra);
len = vty_out (vty, "%s",
- inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ));
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
+ buf, BUFSIZ));
len = 16 - len;
if (len < 1)
vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " ");
@@ -5323,9 +5443,9 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
vty_out (vty, "%7d", attr->local_pref);
else
vty_out (vty, " ");
-
- vty_out (vty, "%7d ",attr->weight);
-
+
+ vty_out (vty, "%7d ", (attr->extra ? attr->extra->weight : 0));
+
/* Print aspath */
if (attr->aspath)
aspath_print_vty (vty, "%s ", attr->aspath);
@@ -5343,7 +5463,10 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
{
struct attr *attr;
u_int32_t label = 0;
-
+
+ if (!binfo->extra)
+ return;
+
/* short status lead text */
route_vty_short_status_out (vty, binfo);
@@ -5360,28 +5483,33 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
if (p->family == AF_INET)
{
if (safi == SAFI_MPLS_VPN)
- vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in));
+ vty_out (vty, "%-16s",
+ inet_ntoa (attr->extra->mp_nexthop_global_in));
else
vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
}
#ifdef HAVE_IPV6
else if (p->family == AF_INET6)
{
+ assert (attr->extra);
char buf[BUFSIZ];
char buf1[BUFSIZ];
- if (attr->mp_nexthop_len == 16)
+ if (attr->extra->mp_nexthop_len == 16)
vty_out (vty, "%s",
- inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ));
- else if (attr->mp_nexthop_len == 32)
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
+ buf, BUFSIZ));
+ else if (attr->extra->mp_nexthop_len == 32)
vty_out (vty, "%s(%s)",
- inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ),
- inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf1, BUFSIZ));
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
+ buf, BUFSIZ),
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local,
+ buf1, BUFSIZ));
}
#endif /* HAVE_IPV6 */
}
- label = decode_label (binfo->tag);
+ label = decode_label (binfo->extra->tag);
vty_out (vty, "notag/%d", label);
@@ -5439,8 +5567,11 @@ flap_route_vty_out (struct vty *vty, struct prefix *p,
struct bgp_damp_info *bdi;
char timebuf[BGP_UPTIME_LEN];
int len;
-
- bdi = binfo->damp_info;
+
+ if (!binfo->extra)
+ return;
+
+ bdi = binfo->extra->damp_info;
/* short status lead text */
route_vty_short_status_out (vty, binfo);
@@ -5516,8 +5647,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
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,
- inet_ntoa (attr->aggregator_addr));
+ vty_out (vty, ", (aggregated by %d %s)",
+ attr->extra->aggregator_as,
+ inet_ntoa (attr->extra->aggregator_addr));
if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
vty_out (vty, ", (Received from a RR-client)");
if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
@@ -5532,14 +5664,15 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (p->family == AF_INET)
{
vty_out (vty, " %s", safi == SAFI_MPLS_VPN ?
- inet_ntoa (attr->mp_nexthop_global_in) :
+ inet_ntoa (attr->extra->mp_nexthop_global_in) :
inet_ntoa (attr->nexthop));
}
#ifdef HAVE_IPV6
else
{
+ assert (attr->extra);
vty_out (vty, " %s",
- inet_ntop (AF_INET6, &attr->mp_nexthop_global,
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
buf, INET6_ADDRSTRLEN));
}
#endif /* HAVE_IPV6 */
@@ -5554,11 +5687,11 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
{
if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
vty_out (vty, " (inaccessible)");
- else if (binfo->igpmetric)
- vty_out (vty, " (metric %d)", binfo->igpmetric);
+ else if (binfo->extra && binfo->extra->igpmetric)
+ vty_out (vty, " (metric %d)", binfo->extra->igpmetric);
vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN));
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- vty_out (vty, " (%s)", inet_ntoa (attr->originator_id));
+ vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id));
else
vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ));
}
@@ -5566,10 +5699,10 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
#ifdef HAVE_IPV6
/* display nexthop local */
- if (attr->mp_nexthop_len == 32)
+ if (attr->extra && attr->extra->mp_nexthop_len == 32)
{
vty_out (vty, " (%s)%s",
- inet_ntop (AF_INET6, &attr->mp_nexthop_local,
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local,
buf, INET6_ADDRSTRLEN),
VTY_NEWLINE);
}
@@ -5586,8 +5719,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
else
vty_out (vty, ", localpref %d", bgp->default_local_pref);
- if (attr->weight != 0)
- vty_out (vty, ", weight %d", attr->weight);
+ if (attr->extra && attr->extra->weight != 0)
+ vty_out (vty, ", weight %d", attr->extra->weight);
if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
vty_out (vty, ", valid");
@@ -5622,27 +5755,30 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
/* Line 5 display Extended-community */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))
- vty_out (vty, " Extended Community: %s%s", attr->ecommunity->str,
- VTY_NEWLINE);
+ vty_out (vty, " Extended Community: %s%s",
+ attr->extra->ecommunity->str, VTY_NEWLINE);
/* Line 6 display Originator, Cluster-id */
if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) ||
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)))
{
+ assert (attr->extra);
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- vty_out (vty, " Originator: %s", inet_ntoa (attr->originator_id));
+ vty_out (vty, " Originator: %s",
+ inet_ntoa (attr->extra->originator_id));
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
{
int i;
vty_out (vty, ", Cluster list: ");
- for (i = 0; i < attr->cluster->length / 4; i++)
- vty_out (vty, "%s ", inet_ntoa (attr->cluster->list[i]));
+ for (i = 0; i < attr->extra->cluster->length / 4; i++)
+ vty_out (vty, "%s ",
+ inet_ntoa (attr->extra->cluster->list[i]));
}
vty_out (vty, "%s", VTY_NEWLINE);
}
- if (binfo->damp_info)
+ if (binfo->extra && binfo->extra->damp_info)
bgp_damp_info_vty (vty, binfo);
/* Line 7 display Uptime */
@@ -5720,7 +5856,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
|| type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
{
- if (! ri->damp_info)
+ if (!(ri->extra && ri->extra->damp_info))
continue;
}
if (type == bgp_show_type_regexp
@@ -5755,12 +5891,14 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
struct attr dummy_attr;
int ret;
- dummy_attr = *ri->attr;
+ bgp_attr_dup (&dummy_attr, ri->attr);
binfo.peer = ri->peer;
binfo.attr = &dummy_attr;
ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo);
-
+
+ bgp_attr_extra_free (&dummy_attr);
+
if (ret == RMAP_DENYMATCH)
continue;
}
@@ -5964,7 +6102,7 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
{
best = count;
- if (ri->suppress)
+ if (ri->extra && ri->extra->suppress)
suppress = 1;
if (ri->attr->community != NULL)
{
@@ -10838,10 +10976,10 @@ bgp_clear_damp_route (struct vty *vty, const char *view_name,
ri = rm->info;
while (ri)
{
- if (ri->damp_info)
+ if (ri->extra && ri->extra->damp_info)
{
ri_temp = ri->next;
- bgp_damp_info_free (ri->damp_info, 1);
+ bgp_damp_info_free (ri->extra->damp_info, 1);
ri = ri_temp;
}
else
@@ -10858,10 +10996,10 @@ bgp_clear_damp_route (struct vty *vty, const char *view_name,
ri = rn->info;
while (ri)
{
- if (ri->damp_info)
+ if (ri->extra && ri->extra->damp_info)
{
ri_temp = ri->next;
- bgp_damp_info_free (ri->damp_info, 1);
+ bgp_damp_info_free (ri->extra->damp_info, 1);
ri = ri_temp;
}
else
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index b0c2fccf..c7eb8c6c 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -23,6 +23,25 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgp_table.h"
+/* Ancillary information to struct bgp_info,
+ * used for uncommonly used data (aggregation, MPLS, etc.)
+ * and lazily allocated to save memory.
+ */
+struct bgp_info_extra
+{
+ /* Pointer to dampening structure. */
+ struct bgp_damp_info *damp_info;
+
+ /* This route is suppressed with aggregation. */
+ int suppress;
+
+ /* Nexthop reachability check. */
+ u_int32_t igpmetric;
+
+ /* MPLS label. */
+ u_char tag[3];
+};
+
struct bgp_info
{
/* For linked list. */
@@ -34,19 +53,13 @@ struct bgp_info
/* Attribute structure. */
struct attr *attr;
-
- /* Pointer to dampening structure. */
- struct bgp_damp_info *damp_info;
-
+
+ /* Extra information */
+ struct bgp_info_extra *extra;
+
/* Uptime. */
time_t uptime;
- /* This route is suppressed with aggregation. */
- int suppress;
-
- /* Nexthop reachability check. */
- u_int32_t igpmetric;
-
/* reference count */
unsigned int lock;
@@ -64,9 +77,6 @@ struct bgp_info
#define BGP_INFO_REMOVED (1 << 9)
#define BGP_INFO_COUNTED (1 << 10)
- /* MPLS label. */
- u_char tag[3];
-
/* BGP route type. This can be static, RIP, OSPF, BGP etc. */
u_char type;
@@ -162,6 +172,7 @@ extern struct bgp_info *bgp_info_lock (struct bgp_info *);
extern struct bgp_info *bgp_info_unlock (struct bgp_info *);
extern void bgp_info_add (struct bgp_node *rn, struct bgp_info *ri);
extern void bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri);
+extern struct bgp_info_extra *bgp_info_extra_get (struct bgp_info *);
extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t);
extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 806a5072..6a44c479 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -692,13 +692,16 @@ route_match_ecommunity (void *rule, struct prefix *prefix,
if (type == RMAP_BGP)
{
bgp_info = object;
-
+
+ if (!bgp_info->attr->extra)
+ return RMAP_NOMATCH;
+
list = community_list_lookup (bgp_clist, (char *) rule,
EXTCOMMUNITY_LIST_MASTER);
if (! list)
return RMAP_NOMATCH;
- if (ecommunity_list_match (bgp_info->attr->ecommunity, list))
+ if (ecommunity_list_match (bgp_info->attr->extra->ecommunity, list))
return RMAP_MATCH;
}
return RMAP_NOMATCH;
@@ -973,7 +976,10 @@ route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type,
bgp_info = object;
/* Set weight value. */
- bgp_info->attr->weight = *weight;
+ if (*weight)
+ (bgp_attr_extra_get (bgp_info->attr))->weight = *weight;
+ else if (bgp_info->attr->extra)
+ bgp_info->attr->extra->weight = 0;
}
return RMAP_OKAY;
@@ -1402,14 +1408,14 @@ route_set_ecommunity_rt (void *rule, struct prefix *prefix,
return RMAP_OKAY;
/* We assume additive for Extended Community. */
- old_ecom = bgp_info->attr->ecommunity;
+ old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity;
if (old_ecom)
new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom);
else
new_ecom = ecommunity_dup (ecom);
- bgp_info->attr->ecommunity = new_ecom;
+ bgp_info->attr->extra->ecommunity = new_ecom;
if (old_ecom)
ecommunity_free (old_ecom);
@@ -1467,7 +1473,7 @@ route_set_ecommunity_soo (void *rule, struct prefix *prefix,
return RMAP_OKAY;
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
- bgp_info->attr->ecommunity = ecommunity_dup (ecom);
+ (bgp_attr_extra_get (bgp_info->attr))->ecommunity = ecommunity_dup (ecom);
}
return RMAP_OKAY;
}
@@ -1610,14 +1616,16 @@ route_set_aggregator_as (void *rule, struct prefix *prefix,
{
struct bgp_info *bgp_info;
struct aggregator *aggregator;
+ struct attr_extra *ae;
if (type == RMAP_BGP)
{
bgp_info = object;
aggregator = rule;
-
- bgp_info->attr->aggregator_as = aggregator->as;
- bgp_info->attr->aggregator_addr = aggregator->address;
+ ae = bgp_attr_extra_get (bgp_info->attr);
+
+ ae->aggregator_as = aggregator->as;
+ ae->aggregator_addr = aggregator->address;
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
}
@@ -1711,12 +1719,15 @@ route_match_ipv6_next_hop (void *rule, struct prefix *prefix,
{
addr = rule;
bgp_info = object;
-
- if (IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_global, rule))
+
+ if (!bgp_info->attr->extra)
+ return RMAP_NOMATCH;
+
+ if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, rule))
return RMAP_MATCH;
- if (bgp_info->attr->mp_nexthop_len == 32 &&
- IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_local, rule))
+ if (bgp_info->attr->extra->mp_nexthop_len == 32 &&
+ IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, rule))
return RMAP_MATCH;
return RMAP_NOMATCH;
@@ -1814,11 +1825,11 @@ route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix,
bgp_info = object;
/* Set next hop value. */
- bgp_info->attr->mp_nexthop_global = *address;
+ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = *address;
/* Set nexthop length. */
- if (bgp_info->attr->mp_nexthop_len == 0)
- bgp_info->attr->mp_nexthop_len = 16;
+ if (bgp_info->attr->extra->mp_nexthop_len == 0)
+ bgp_info->attr->extra->mp_nexthop_len = 16;
}
return RMAP_OKAY;
@@ -1878,11 +1889,11 @@ route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix,
bgp_info = object;
/* Set next hop value. */
- bgp_info->attr->mp_nexthop_local = *address;
+ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = *address;
/* Set nexthop length. */
- if (bgp_info->attr->mp_nexthop_len != 32)
- bgp_info->attr->mp_nexthop_len = 32;
+ if (bgp_info->attr->extra->mp_nexthop_len != 32)
+ bgp_info->attr->extra->mp_nexthop_len = 32;
}
return RMAP_OKAY;
@@ -1942,7 +1953,7 @@ route_set_vpnv4_nexthop (void *rule, struct prefix *prefix,
bgp_info = object;
/* Set next hop value. */
- bgp_info->attr->mp_nexthop_global_in = *address;
+ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global_in = *address;
}
return RMAP_OKAY;
@@ -1997,7 +2008,7 @@ route_set_originator_id (void *rule, struct prefix *prefix, route_map_object_t t
bgp_info = object;
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
- bgp_info->attr->originator_id = *address;
+ (bgp_attr_extra_get (bgp_info->attr))->originator_id = *address;
}
return RMAP_OKAY;
diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c
index 430521f1..3d26890e 100644
--- a/bgpd/bgp_snmp.c
+++ b/bgpd/bgp_snmp.c
@@ -797,10 +797,16 @@ bgp4PathAttrTable (struct variable *v, oid name[], size_t *length,
return SNMP_INTEGER (1);
break;
case BGP4PATHATTRAGGREGATORAS: /* 10 */
- return SNMP_INTEGER (binfo->attr->aggregator_as);
+ if (binfo->attr->extra)
+ return SNMP_INTEGER (binfo->attr->extra->aggregator_as);
+ else
+ return SNMP_INTEGER (0);
break;
case BGP4PATHATTRAGGREGATORADDR: /* 11 */
- return SNMP_IPADDRESS (binfo->attr->aggregator_addr);
+ if (binfo->attr->extra)
+ return SNMP_IPADDRESS (binfo->attr->extra->aggregator_addr);
+ else
+ return SNMP_INTEGER (0);
break;
case BGP4PATHATTRCALCLOCALPREF: /* 12 */
return SNMP_INTEGER (-1);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index b108164f..1e21c74f 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -6496,6 +6496,11 @@ DEFUN (show_bgp_memory,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct bgp_info)),
VTY_NEWLINE);
+ if ((count = mtype_stats_alloc (MTYPE_BGP_ROUTE_EXTRA)))
+ vty_out (vty, "%ld BGP route ancillaries, using %s of memory%s", count,
+ mtype_memstr (memstrbuf, sizeof (memstrbuf),
+ count * sizeof (struct bgp_info_extra)),
+ VTY_NEWLINE);
if ((count = mtype_stats_alloc (MTYPE_BGP_STATIC)))
vty_out (vty, "%ld Static routes, using %s of memory%s", count,
@@ -6533,6 +6538,11 @@ DEFUN (show_bgp_memory,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof(struct attr)),
VTY_NEWLINE);
+ if ((count = mtype_stats_alloc (MTYPE_ATTR_EXTRA)))
+ vty_out (vty, "%ld BGP extra attributes, using %s of memory%s", count,
+ mtype_memstr (memstrbuf, sizeof (memstrbuf),
+ count * sizeof(struct attr_extra)),
+ VTY_NEWLINE);
if ((count = attr_unknown_count()))
vty_out (vty, "%ld unknown attributes%s", count, VTY_NEWLINE);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 301c15b0..0b6ab45a 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -746,20 +746,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
ifindex = 0;
nexthop = NULL;
-
+
+ assert (info->attr->extra);
+
/* Only global address nexthop exists. */
- if (info->attr->mp_nexthop_len == 16)
- nexthop = &info->attr->mp_nexthop_global;
+ if (info->attr->extra->mp_nexthop_len == 16)
+ nexthop = &info->attr->extra->mp_nexthop_global;
/* If both global and link-local address present. */
- if (info->attr->mp_nexthop_len == 32)
+ if (info->attr->extra->mp_nexthop_len == 32)
{
/* Workaround for Cisco's nexthop bug. */
- if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->mp_nexthop_global)
+ if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
&& peer->su_remote->sa.sa_family == AF_INET6)
nexthop = &peer->su_remote->sin6.sin6_addr;
else
- nexthop = &info->attr->mp_nexthop_local;
+ nexthop = &info->attr->extra->mp_nexthop_local;
if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
@@ -867,18 +869,20 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
struct zapi_ipv6 api;
unsigned int ifindex;
struct in6_addr *nexthop;
-
+
+ assert (info->attr->extra);
+
ifindex = 0;
nexthop = NULL;
/* Only global address nexthop exists. */
- if (info->attr->mp_nexthop_len == 16)
- nexthop = &info->attr->mp_nexthop_global;
+ if (info->attr->extra->mp_nexthop_len == 16)
+ nexthop = &info->attr->extra->mp_nexthop_global;
/* If both global and link-local address present. */
- if (info->attr->mp_nexthop_len == 32)
+ if (info->attr->extra->mp_nexthop_len == 32)
{
- nexthop = &info->attr->mp_nexthop_local;
+ nexthop = &info->attr->extra->mp_nexthop_local;
if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
}
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 3787b68c..5666cbad 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,7 @@
+2007-05-03 Paul Jakma <paul.jakma@sun.com>
+
+ * memtypes.c: Add MTYPE_ATTR_EXTRA and MTYPE_BGP_ROUTE_EXTRA
+
2007-05-01 David L Stevens <dlstevens@us.ibm.com>
* (general) These changes collectively add route-map and
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 5a685e0e..f1b10e71 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -6,7 +6,7 @@
* The script is sensitive to the format (though not whitespace), see
* the top of memtypes.awk for more details.
*
- * $Id: memtypes.c,v 1.11 2006/03/30 14:09:38 paul Exp $
+ * $Id$
*/
#include "zebra.h"
@@ -96,6 +96,7 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_PEER_GROUP, "Peer group" },
{ MTYPE_PEER_DESC, "Peer description" },
{ MTYPE_ATTR, "BGP attribute" },
+ { MTYPE_ATTR_EXTRA, "BGP extra attributes" },
{ MTYPE_AS_PATH, "BGP aspath" },
{ MTYPE_AS_SEG, "BGP aspath seg" },
{ MTYPE_AS_SEG_DATA, "BGP aspath segment data" },
@@ -104,6 +105,7 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_BGP_TABLE, "BGP table" },
{ MTYPE_BGP_NODE, "BGP node" },
{ MTYPE_BGP_ROUTE, "BGP route" },
+ { MTYPE_BGP_ROUTE_EXTRA, "BGP ancillary route info" },
{ MTYPE_BGP_STATIC, "BGP static" },
{ MTYPE_BGP_ADVERTISE_ATTR, "BGP adv attr" },
{ MTYPE_BGP_ADVERTISE, "BGP adv" },