From fb982c25aa771b7c7425a3c3cce0a2cda0a715de Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 4 May 2007 20:15:47 +0000 Subject: [bgpd] Trim memory usage of BGP routes 2007-05-03 Paul Jakma * 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 * lib/memtypes.c: Add MTYPE_ATTR_EXTRA and MTYPE_BGP_ROUTE_EXTRA --- bgpd/ChangeLog | 27 ++- bgpd/bgp_attr.c | 385 +++++++++++++++++++++++++++---------------- bgpd/bgp_attr.h | 59 +++++-- bgpd/bgp_damp.c | 32 ++-- bgpd/bgp_debug.c | 39 +++-- bgpd/bgp_nexthop.c | 40 ++--- bgpd/bgp_packet.c | 20 ++- bgpd/bgp_route.c | 466 ++++++++++++++++++++++++++++++++++------------------ bgpd/bgp_route.h | 37 +++-- bgpd/bgp_routemap.c | 53 +++--- bgpd/bgp_snmp.c | 10 +- bgpd/bgp_vty.c | 10 ++ bgpd/bgp_zebra.c | 26 +-- lib/ChangeLog | 4 + lib/memtypes.c | 4 +- 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 +2007-05-03 Paul Jakma + + * 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 * 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 + + * memtypes.c: Add MTYPE_ATTR_EXTRA and MTYPE_BGP_ROUTE_EXTRA + 2007-05-01 David L Stevens * (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" }, -- cgit v1.2.1